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.util.List;
020    
021    import org.apache.camel.Processor;
022    import org.apache.camel.component.file.GenericFile;
023    import org.apache.camel.util.FileUtil;
024    import org.apache.camel.util.ObjectHelper;
025    import org.apache.commons.net.ftp.FTPFile;
026    
027    /**
028     * FTP consumer
029     */
030    public class FtpConsumer extends RemoteFileConsumer<FTPFile> {
031    
032        protected String endpointPath;
033    
034        public FtpConsumer(RemoteFileEndpoint<FTPFile> endpoint, Processor processor, RemoteFileOperations<FTPFile> fileOperations) {
035            super(endpoint, processor, fileOperations);
036            this.endpointPath = endpoint.getConfiguration().getDirectory();
037        }
038    
039        protected boolean pollDirectory(String fileName, List<GenericFile<FTPFile>> fileList) {
040            String currentDir = null;
041            if (isStepwise()) {
042                // must remember current dir so we stay in that directory after the poll
043                currentDir = operations.getCurrentDirectory();
044            }
045    
046            // strip trailing slash
047            fileName = FileUtil.stripTrailingSeparator(fileName);
048    
049            boolean answer = doPollDirectory(fileName, null, fileList);
050            if (isStepwise()) {
051                operations.changeCurrentDirectory(currentDir);
052            }
053    
054            return answer;
055        }
056    
057        protected boolean pollSubDirectory(String absolutePath, String dirName, List<GenericFile<FTPFile>> fileList) {
058            boolean answer = doPollDirectory(absolutePath, dirName, fileList);
059            // change back to parent directory when finished polling sub directory
060            if (isStepwise()) {
061                operations.changeToParentDirectory();
062            }
063            return answer;
064        }
065    
066        protected boolean doPollDirectory(String absolutePath, String dirName, List<GenericFile<FTPFile>> fileList) {
067            if (log.isTraceEnabled()) {
068                log.trace("doPollDirectory from absolutePath: " + absolutePath + ", dirName: " + dirName);
069            }
070            // remove trailing /
071            dirName = FileUtil.stripTrailingSeparator(dirName);
072    
073            // compute dir depending on stepwise is enabled or not
074            String dir;
075            if (isStepwise()) {
076                dir = ObjectHelper.isNotEmpty(dirName) ? dirName : absolutePath;
077                operations.changeCurrentDirectory(dir);
078            } else {
079                dir = absolutePath;
080            }
081    
082            if (log.isTraceEnabled()) {
083                log.trace("Polling directory: " + dir);
084            }
085            List<FTPFile> files;
086            if (isStepwise()) {
087                files = operations.listFiles();
088            } else {
089                files = operations.listFiles(dir);
090            }
091    
092            if (files == null || files.isEmpty()) {
093                // no files in this directory to poll
094                if (log.isTraceEnabled()) {
095                    log.trace("No files found in directory: " + dir);
096                }
097                return true;
098            } else {
099                // we found some files
100                if (log.isTraceEnabled()) {
101                    log.trace("Found " + files.size() + " in directory: " + dir);
102                }
103            }
104    
105            for (FTPFile file : files) {
106    
107                // check if we can continue polling in files
108                if (!canPollMoreFiles(fileList)) {
109                    return false;
110                }
111    
112                if (file.isDirectory()) {
113                    RemoteFile<FTPFile> remote = asRemoteFile(absolutePath, file);
114                    if (endpoint.isRecursive() && isValidFile(remote, true)) {
115                        // recursive scan and add the sub files and folders
116                        String subDirectory = file.getName();
117                        String path = absolutePath + "/" + subDirectory;
118                        boolean canPollMore = pollSubDirectory(path, subDirectory, fileList);
119                        if (!canPollMore) {
120                            return false;
121                        }
122                    }
123                } else if (file.isFile()) {
124                    RemoteFile<FTPFile> remote = asRemoteFile(absolutePath, file);
125                    if (isValidFile(remote, false)) {
126                        if (isInProgress(remote)) {
127                            if (log.isTraceEnabled()) {
128                                log.trace("Skipping as file is already in progress: " + remote.getFileName());
129                            }
130                        } else {
131                            // matched file so add
132                            fileList.add(remote);
133                        }
134                    }
135                } else {
136                    log.debug("Ignoring unsupported remote file type: " + file);
137                }
138            }
139    
140            return true;
141        }
142    
143        private RemoteFile<FTPFile> asRemoteFile(String absolutePath, FTPFile file) {
144            RemoteFile<FTPFile> answer = new RemoteFile<FTPFile>();
145    
146            answer.setEndpointPath(endpointPath);
147            answer.setFile(file);
148            answer.setFileNameOnly(file.getName());
149            answer.setFileLength(file.getSize());
150            if (file.getTimestamp() != null) {
151                answer.setLastModified(file.getTimestamp().getTimeInMillis());
152            }
153            answer.setHostname(((RemoteFileConfiguration) endpoint.getConfiguration()).getHost());
154    
155            // absolute or relative path
156            boolean absolute = FileUtil.hasLeadingSeparator(absolutePath);
157            answer.setAbsolute(absolute);
158    
159            // create a pseudo absolute name
160            String dir = FileUtil.stripTrailingSeparator(absolutePath);
161            String absoluteFileName = FileUtil.stripLeadingSeparator(dir + "/" + file.getName());
162            // if absolute start with a leading separator otherwise let it be relative
163            if (absolute) {
164                absoluteFileName = "/" + absoluteFileName;
165            }
166            answer.setAbsoluteFilePath(absoluteFileName);
167    
168            // the relative filename, skip the leading endpoint configured path
169            String relativePath = ObjectHelper.after(absoluteFileName, endpointPath);
170            // skip leading /
171            relativePath = FileUtil.stripLeadingSeparator(relativePath);
172            answer.setRelativeFilePath(relativePath);
173    
174            // the file name should be the relative path
175            answer.setFileName(answer.getRelativeFilePath());
176    
177            return answer;
178        }
179    
180        private boolean isStepwise() {
181            RemoteFileConfiguration config = (RemoteFileConfiguration) endpoint.getConfiguration();
182            return config.isStepwise();
183        }
184    
185    }