001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.camel.component.file.remote;
018    
019    import java.io.IOException;
020    
021    import org.apache.camel.Exchange;
022    import org.apache.camel.ServicePoolAware;
023    import org.apache.camel.component.file.GenericFileExchange;
024    import org.apache.camel.component.file.GenericFileOperationFailedException;
025    import org.apache.camel.component.file.GenericFileProducer;
026    import org.apache.camel.util.ExchangeHelper;
027    
028    /**
029     * Remote file producer. Handles connecting and disconnecting if we are not.
030     * Generic type F is the remote system implementation of a file.
031     */
032    public class RemoteFileProducer<T> extends GenericFileProducer<T> implements ServicePoolAware {
033    
034        private boolean loggedIn;
035        
036        protected RemoteFileProducer(RemoteFileEndpoint<T> endpoint, RemoteFileOperations<T> operations) {
037            super(endpoint, operations);
038        }
039        
040        @Override
041        protected String getFileSeparator() {
042            return "/";
043        }
044        
045        @Override
046        protected String normalizePath(String name) {        
047            return name;
048        }
049    
050        @SuppressWarnings("unchecked")
051        public void process(Exchange exchange) throws Exception {
052            GenericFileExchange remoteExchange = (GenericFileExchange) getEndpoint().createExchange(exchange);
053            processExchange(remoteExchange);
054            ExchangeHelper.copyResults(exchange, remoteExchange);
055        }
056    
057        /**
058         * The file could not be written. We need to disconnect from the remote server.
059         */
060        protected void handleFailedWrite(GenericFileExchange<T> exchange, Exception exception) throws Exception {
061            loggedIn = false;
062            if (isStopping() || isStopped()) {
063                // if we are stopping then ignore any exception during a poll
064                log.debug("Exception occured during stopping: " + exception.getMessage());
065            } else {
066                log.debug("Exception occured during processing. ", exception);
067                disconnect();
068                // Rethrow to signify that we didn't poll
069                throw exception;
070            }
071        }
072    
073        public void disconnect() throws IOException {
074            loggedIn = false;
075            if (log.isDebugEnabled()) {
076                log.debug("Disconnecting from: " + getEndpoint());
077            }
078            ((RemoteFileOperations) operations).disconnect();
079        }
080    
081        @Override
082        protected void preWriteCheck() throws Exception {
083            connectIfNecessary();
084            if (!loggedIn) {
085                // must be logged in to be able to upload the file
086                String message = "Cannot connect/login to: " + ((RemoteFileEndpoint) getEndpoint()).remoteServerInformation();
087                throw new GenericFileOperationFailedException(message);
088            }
089        }
090    
091        @Override
092        protected void doStart() throws Exception {
093            log.debug("Starting");
094            // do not connect when component starts, just wait until we process as we will
095            // connect at that time if needed
096            super.doStart();
097        }
098    
099        @Override
100        protected void doStop() throws Exception {
101            try {
102                disconnect();
103            } catch (Exception e) {
104                log.debug("Exception occured during disconnecting from: " + getEndpoint() + " " + e.getMessage());
105            }
106            super.doStop();
107        }
108    
109        protected void connectIfNecessary() throws IOException {
110            if (!((RemoteFileOperations) operations).isConnected() || !loggedIn) {
111                if (log.isDebugEnabled()) {
112                    log.debug("Not already connected/logged in. Connecting to: " + getEndpoint());
113                }
114                RemoteFileOperations rfo = (RemoteFileOperations) operations;
115                RemoteFileEndpoint rfe = (RemoteFileEndpoint) getEndpoint();
116                RemoteFileConfiguration conf = (RemoteFileConfiguration) rfe.getConfiguration();
117                loggedIn = rfo.connect(conf);
118                if (!loggedIn) {
119                    return;
120                }
121                log.info("Connected and logged in to: " + getEndpoint());
122            }
123        }
124    
125        public boolean isSingleton() {
126            // this producer is stateful because the remote file operations is not thread safe
127            return false;
128        }
129    }