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