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;
018    
019    import java.io.File;
020    import java.util.List;
021    
022    import org.apache.camel.Processor;
023    import org.apache.camel.util.FileUtil;
024    import org.apache.camel.util.ObjectHelper;
025    
026    /**
027     * File consumer.
028     */
029    public class FileConsumer extends GenericFileConsumer<File> {
030    
031        private String endpointPath;
032    
033        public FileConsumer(GenericFileEndpoint<File> endpoint, Processor processor, GenericFileOperations<File> operations) {
034            super(endpoint, processor, operations);
035            this.endpointPath = endpoint.getConfiguration().getDirectory();
036        }
037    
038        @Override
039        protected boolean pollDirectory(String fileName, List<GenericFile<File>> fileList, int depth) {
040            log.trace("pollDirectory from fileName: {}", fileName);
041    
042            depth++;
043    
044            File directory = new File(fileName);
045            if (!directory.exists() || !directory.isDirectory()) {
046                log.debug("Cannot poll as directory does not exists or its not a directory: {}", directory);
047                if (getEndpoint().isDirectoryMustExist()) {
048                    throw new GenericFileOperationFailedException("Directory does not exist: " + directory);
049                }
050                return true;
051            }
052    
053            log.trace("Polling directory: {}", directory.getPath());
054            File[] files = directory.listFiles();
055            if (files == null || files.length == 0) {
056                // no files in this directory to poll
057                if (log.isTraceEnabled()) {
058                    log.trace("No files found in directory: {}", directory.getPath());
059                }
060                return true;
061            } else {
062                // we found some files
063                if (log.isTraceEnabled()) {
064                    log.trace("Found {} in directory: {}", files.length, directory.getPath());
065                }
066            }
067    
068            for (File file : files) {
069                // check if we can continue polling in files
070                if (!canPollMoreFiles(fileList)) {
071                    return false;
072                }
073    
074                // trace log as Windows/Unix can have different views what the file is?
075                if (log.isTraceEnabled()) {
076                    log.trace("Found file: {} [isAbsolute: {}, isDirectory: {}, isFile: {}, isHidden: {}]",
077                            new Object[]{file, file.isAbsolute(), file.isDirectory(), file.isFile(), file.isHidden()});
078                }
079    
080                // creates a generic file
081                GenericFile<File> gf = asGenericFile(endpointPath, file, getEndpoint().getCharset());
082    
083                if (file.isDirectory()) {
084                    if (endpoint.isRecursive() && isValidFile(gf, true) && depth < endpoint.getMaxDepth()) {
085                        // recursive scan and add the sub files and folders
086                        String subDirectory = fileName + File.separator + file.getName();
087                        boolean canPollMore = pollDirectory(subDirectory, fileList, depth);
088                        if (!canPollMore) {
089                            return false;
090                        }
091                    }
092                } else {
093                    // Windows can report false to a file on a share so regard it always as a file (if its not a directory)
094                    if (isValidFile(gf, false) && depth >= endpoint.minDepth) {
095                        if (isInProgress(gf)) {
096                            if (log.isTraceEnabled()) {
097                                log.trace("Skipping as file is already in progress: {}", gf.getFileName());
098                            }
099                        } else {
100                            log.trace("Adding valid file: {}", file);
101                            // matched file so add
102                            fileList.add(gf);
103                        }
104                    }
105    
106                }
107            }
108    
109            return true;
110        }
111    
112        /**
113         * Creates a new GenericFile<File> based on the given file.
114         *
115         * @param endpointPath the starting directory the endpoint was configured with
116         * @param file the source file
117         * @return wrapped as a GenericFile
118         */
119        public static GenericFile<File> asGenericFile(String endpointPath, File file, String charset) {
120            GenericFile<File> answer = new GenericFile<File>();
121            // use file specific binding
122            answer.setBinding(new FileBinding());
123    
124            answer.setCharset(charset);
125            answer.setEndpointPath(endpointPath);
126            answer.setFile(file);
127            answer.setFileNameOnly(file.getName());
128            answer.setFileLength(file.length());
129            answer.setDirectory(file.isDirectory());
130            // must use FileUtil.isAbsolute to have consistent check for whether the file is
131            // absolute or not. As windows do not consider \ paths as absolute where as all
132            // other OS platforms will consider \ as absolute. The logic in Camel mandates
133            // that we align this for all OS. That is why we must use FileUtil.isAbsolute
134            // to return a consistent answer for all OS platforms.
135            answer.setAbsolute(FileUtil.isAbsolute(file));
136            answer.setAbsoluteFilePath(file.getAbsolutePath());
137            answer.setLastModified(file.lastModified());
138    
139            // compute the file path as relative to the starting directory
140            File path;
141            String endpointNormalized = FileUtil.normalizePath(endpointPath);
142            if (file.getPath().startsWith(endpointNormalized)) {
143                // skip duplicate endpoint path
144                path = new File(ObjectHelper.after(file.getPath(), endpointNormalized + File.separator));
145            } else {
146                path = new File(file.getPath());
147            }
148    
149            if (path.getParent() != null) {
150                answer.setRelativeFilePath(path.getParent() + File.separator + file.getName());
151            } else {
152                answer.setRelativeFilePath(path.getName());
153            }
154    
155            // the file name should be the relative path
156            answer.setFileName(answer.getRelativeFilePath());
157    
158            // use file as body as we have converters if needed as stream
159            answer.setBody(file);
160            return answer;
161        }
162    
163        @Override
164        public FileEndpoint getEndpoint() {
165            return (FileEndpoint) super.getEndpoint();
166        }
167    }