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 }