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.GenericFileOperationFailedException;
024    import org.apache.camel.component.file.GenericFileProducer;
025    import org.apache.camel.util.ExchangeHelper;
026    
027    /**
028     * Remote file producer. Handles connecting and disconnecting if we are not.
029     * Generic type F is the remote system implementation of a file.
030     */
031    public class RemoteFileProducer<T> extends GenericFileProducer<T> implements ServicePoolAware {
032    
033        private boolean loggedIn;
034        
035        protected RemoteFileProducer(RemoteFileEndpoint<T> endpoint, RemoteFileOperations<T> operations) {
036            super(endpoint, operations);
037        }
038        
039        @Override
040        protected String getFileSeparator() {
041            return "/";
042        }
043        
044        @Override
045        protected String normalizePath(String name) {        
046            return name;
047        }
048    
049        @SuppressWarnings("unchecked")
050        public void process(Exchange exchange) throws Exception {
051            Exchange remoteExchange = getEndpoint().createExchange(exchange);
052            processExchange(remoteExchange);
053            ExchangeHelper.copyResults(exchange, remoteExchange);
054        }
055    
056        /**
057         * The file could not be written. We need to disconnect from the remote server.
058         */
059        protected void handleFailedWrite(Exchange exchange, Exception exception) throws Exception {
060            loggedIn = false;
061            if (isStopping() || isStopped()) {
062                // if we are stopping then ignore any exception during a poll
063                log.debug("Exception occured during stopping: " + exception.getMessage());
064            } else {
065                log.debug("Exception occured during processing. ", exception);
066                disconnect();
067                // Rethrow to signify that we didn't poll
068                throw exception;
069            }
070        }
071    
072        public void disconnect() throws IOException {
073            loggedIn = false;
074            if (log.isDebugEnabled()) {
075                log.debug("Disconnecting from: " + getEndpoint());
076            }
077            ((RemoteFileOperations) operations).disconnect();
078        }
079    
080        @Override
081        protected void preWriteCheck() throws Exception {
082            connectIfNecessary();
083            if (!loggedIn) {
084                // must be logged in to be able to upload the file
085                String message = "Cannot connect/login to: " + ((RemoteFileEndpoint) getEndpoint()).remoteServerInformation();
086                throw new GenericFileOperationFailedException(message);
087            }
088        }
089    
090        @Override
091        protected void doStart() throws Exception {
092            log.debug("Starting");
093            // do not connect when component starts, just wait until we process as we will
094            // connect at that time if needed
095            super.doStart();
096        }
097    
098        @Override
099        protected void doStop() throws Exception {
100            try {
101                disconnect();
102            } catch (Exception e) {
103                log.debug("Exception occured during disconnecting from: " + getEndpoint() + " " + e.getMessage());
104            }
105            super.doStop();
106        }
107    
108        protected void connectIfNecessary() throws IOException {
109            if (!((RemoteFileOperations) operations).isConnected() || !loggedIn) {
110                if (log.isDebugEnabled()) {
111                    log.debug("Not already connected/logged in. Connecting to: " + getEndpoint());
112                }
113                RemoteFileOperations rfo = (RemoteFileOperations) operations;
114                RemoteFileEndpoint rfe = (RemoteFileEndpoint) getEndpoint();
115                RemoteFileConfiguration conf = (RemoteFileConfiguration) rfe.getConfiguration();
116                loggedIn = rfo.connect(conf);
117                if (!loggedIn) {
118                    return;
119                }
120                log.info("Connected and logged in to: " + getEndpoint());
121            }
122        }
123    
124        public boolean isSingleton() {
125            // this producer is stateful because the remote file operations is not thread safe
126            return false;
127        }
128    }