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.Processor;
023    import org.apache.camel.component.file.GenericFile;
024    import org.apache.camel.component.file.GenericFileConsumer;
025    import org.apache.camel.component.file.GenericFileOperationFailedException;
026    import org.apache.camel.util.FileUtil;
027    
028    /**
029     * Base class for remote file consumers.
030     */
031    public abstract class RemoteFileConsumer<T> extends GenericFileConsumer<T> {
032        protected boolean loggedIn;
033    
034        public RemoteFileConsumer(RemoteFileEndpoint<T> endpoint, Processor processor, RemoteFileOperations<T> operations) {
035            super(endpoint, processor, operations);
036            this.setPollStrategy(new RemoteFilePollingConsumerPollStrategy());
037        }
038    
039        @Override
040        @SuppressWarnings("unchecked")
041        public RemoteFileEndpoint<T> getEndpoint() {
042            return (RemoteFileEndpoint<T>) super.getEndpoint();
043        }
044    
045        protected RemoteFileOperations getOperations() {
046            return (RemoteFileOperations) operations;
047        }
048    
049        protected boolean prePollCheck() throws Exception {
050            if (log.isTraceEnabled()) {
051                log.trace("prePollCheck on " + getEndpoint().getConfiguration().remoteServerInformation());
052            }
053            try {
054                if (getEndpoint().getMaximumReconnectAttempts() > 0) {
055                    // only use recoverable if we are allowed any re-connect attempts
056                    recoverableConnectIfNecessary();
057                } else {
058                    connectIfNecessary();
059                }
060            } catch (Exception e) {
061                loggedIn = false;
062    
063                // login failed should we thrown exception
064                if (getEndpoint().getConfiguration().isThrowExceptionOnConnectFailed()) {
065                    throw e;
066                }
067            }
068    
069            if (!loggedIn) {
070                String message = "Cannot connect/login to: " + remoteServer() + ". Will skip this poll.";
071                log.warn(message);
072                return false;
073            }
074    
075            return true;
076        }
077    
078        @Override
079        protected void postPollCheck() {
080            if (log.isTraceEnabled()) {
081                log.trace("postPollCheck on " + getEndpoint().getConfiguration().remoteServerInformation());
082            }
083            if (getEndpoint().isDisconnect()) {
084                log.trace("postPollCheck disconnect from: {}", getEndpoint());
085                disconnect();
086            }
087        }
088    
089        @Override
090        protected void processExchange(Exchange exchange) {
091            // mark the exchange to be processed synchronously as the ftp client is not thread safe
092            // and we must execute the callbacks in the same thread as this consumer
093            exchange.setProperty(Exchange.UNIT_OF_WORK_PROCESS_SYNC, Boolean.TRUE);
094            super.processExchange(exchange);
095        }
096    
097        @Override
098        protected void doStop() throws Exception {
099            super.doStop();
100            disconnect();
101        }
102    
103        protected void disconnect() {
104            // eager indicate we are no longer logged in
105            loggedIn = false;
106    
107            // disconnect
108            try {
109                if (getOperations().isConnected()) {
110                    if (log.isDebugEnabled()) {
111                        log.debug("Disconnecting from: {}", remoteServer());
112                    }
113                    getOperations().disconnect();
114                }
115            } catch (GenericFileOperationFailedException e) {
116                // ignore just log a warning
117                log.warn("Error occurred while disconnecting from " + remoteServer() + " due: " + e.getMessage() + ". This exception will be ignored.");
118            }
119        }
120    
121        protected void recoverableConnectIfNecessary() throws Exception {
122            try {
123                connectIfNecessary();
124            } catch (Exception e) {
125                if (log.isDebugEnabled()) {
126                    log.debug("Could not connect to: " + getEndpoint() + ". Will try to recover.", e);
127                }
128                loggedIn = false;
129            }
130    
131            // recover by re-creating operations which should most likely be able to recover
132            if (!loggedIn) {
133                log.debug("Trying to recover connection to: {} with a fresh client.", getEndpoint());
134                setOperations(getEndpoint().createRemoteFileOperations());
135                connectIfNecessary();
136            }
137        }
138    
139        protected void connectIfNecessary() throws IOException {
140            if (!loggedIn) {
141                if (log.isDebugEnabled()) {
142                    log.debug("Not connected/logged in, connecting to: {}", remoteServer());
143                }
144                loggedIn = getOperations().connect((RemoteFileConfiguration) endpoint.getConfiguration());
145                if (loggedIn) {
146                    log.info("Connected and logged in to: " + remoteServer());
147                }
148            }
149        }
150    
151        /**
152         * Returns human readable server information for logging purpose
153         */
154        protected String remoteServer() {
155            return ((RemoteFileEndpoint) endpoint).remoteServerInformation();
156        }
157    
158        @Override
159        protected boolean isMatched(GenericFile<T> file, String doneFileName) {
160            // ftp specific as we need to cater for stepwise
161            if (getEndpoint().getConfiguration().isStepwise()) {
162                // stepwise enabled, so done file should always be without path
163                doneFileName = FileUtil.stripPath(doneFileName);
164            }
165    
166            return super.isMatched(file, doneFileName);
167        }
168    }