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 021 import org.apache.camel.Consumer; 022 import org.apache.camel.ExchangePattern; 023 import org.apache.camel.Message; 024 import org.apache.camel.Processor; 025 import org.apache.camel.Producer; 026 import org.apache.camel.component.file.strategy.FileProcessStrategyFactory; 027 import org.apache.camel.component.file.strategy.FileProcessStrategySupport; 028 import org.apache.camel.component.file.strategy.NoOpFileProcessStrategy; 029 import org.apache.camel.impl.ScheduledPollEndpoint; 030 import org.apache.commons.logging.Log; 031 import org.apache.commons.logging.LogFactory; 032 033 /** 034 * A <a href="http://activemq.apache.org/camel/file.html">File Endpoint</a> for 035 * working with file systems 036 * 037 * @version $Revision: 37863 $ 038 */ 039 public class FileEndpoint extends ScheduledPollEndpoint<FileExchange> { 040 private static final transient Log LOG = LogFactory.getLog(FileEndpoint.class); 041 private File file; 042 private FileProcessStrategy fileProcessStrategy; 043 private boolean autoCreate = true; 044 private boolean lock = true; 045 private boolean delete; 046 private boolean noop; 047 private boolean append = true; 048 private String moveNamePrefix; 049 private String moveNamePostfix; 050 private String[] excludedNamePrefixes = {"."}; 051 private String[] excludedNamePostfixes = {FileProcessStrategySupport.DEFAULT_LOCK_FILE_POSTFIX}; 052 private int bufferSize = 128 * 1024; 053 private boolean ignoreFileNameHeader; 054 055 protected FileEndpoint(File file, String endpointUri, FileComponent component) { 056 super(endpointUri, component); 057 this.file = file; 058 } 059 060 public Producer<FileExchange> createProducer() throws Exception { 061 Producer<FileExchange> result = new FileProducer(this); 062 return result; 063 } 064 065 public Consumer<FileExchange> createConsumer(Processor processor) throws Exception { 066 Consumer<FileExchange> result = new FileConsumer(this, processor); 067 configureConsumer(result); 068 return result; 069 } 070 071 /** 072 * Create a new exchange for communicating with this endpoint 073 * 074 * @param file the file 075 * @return the created exchange 076 */ 077 public FileExchange createExchange(File file) { 078 return new FileExchange(getContext(), getExchangePattern(), file); 079 } 080 081 public FileExchange createExchange() { 082 return createExchange(getFile()); 083 } 084 085 public FileExchange createExchange(ExchangePattern pattern) { 086 return new FileExchange(getContext(), pattern, file); 087 } 088 089 /** 090 * Configures the given message with the file which sets the body to the file object 091 * and sets the {@link FileComponent#HEADER_FILE_NAME} header. 092 */ 093 public void configureMessage(File file, Message message) { 094 message.setBody(file); 095 String relativePath = file.getPath().substring(getFile().getPath().length()); 096 if (relativePath.startsWith(File.separator) || relativePath.startsWith("/")) { 097 relativePath = relativePath.substring(1); 098 } 099 message.setHeader(FileComponent.HEADER_FILE_NAME, relativePath); 100 } 101 102 public File getFile() { 103 if (autoCreate && !file.exists()) { 104 file.mkdirs(); 105 } 106 return file; 107 } 108 109 public boolean isSingleton() { 110 return true; 111 } 112 113 public boolean isAutoCreate() { 114 return this.autoCreate; 115 } 116 117 public void setAutoCreate(boolean autoCreate) { 118 this.autoCreate = autoCreate; 119 } 120 121 public FileProcessStrategy getFileStrategy() { 122 if (fileProcessStrategy == null) { 123 fileProcessStrategy = createFileStrategy(); 124 LOG.debug("Using file process strategy: " + fileProcessStrategy); 125 } 126 return fileProcessStrategy; 127 } 128 129 /** 130 * Sets the strategy to be used when the file has been processed such as 131 * deleting or renaming it etc. 132 * 133 * @param fileProcessStrategy the new strategy to use 134 */ 135 public void setFileStrategy(FileProcessStrategy fileProcessStrategy) { 136 this.fileProcessStrategy = fileProcessStrategy; 137 } 138 139 public boolean isDelete() { 140 return delete; 141 } 142 143 public void setDelete(boolean delete) { 144 this.delete = delete; 145 } 146 147 public boolean isLock() { 148 return lock; 149 } 150 151 public void setLock(boolean lock) { 152 this.lock = lock; 153 } 154 155 public String getMoveNamePostfix() { 156 return moveNamePostfix; 157 } 158 159 /** 160 * Sets the name postfix appended to moved files. For example to rename all 161 * the files from <tt>*</tt> to <tt>*.done</tt> set this value to <tt>.done</tt> 162 */ 163 public void setMoveNamePostfix(String moveNamePostfix) { 164 this.moveNamePostfix = moveNamePostfix; 165 } 166 167 public String getMoveNamePrefix() { 168 return moveNamePrefix; 169 } 170 171 /** 172 * Sets the name prefix appended to moved files. For example to move 173 * processed files into a hidden directory called <tt>.camel</tt> set this value to 174 * <tt>.camel/</tt> 175 */ 176 public void setMoveNamePrefix(String moveNamePrefix) { 177 this.moveNamePrefix = moveNamePrefix; 178 } 179 180 public String[] getExcludedNamePrefixes() { 181 return excludedNamePrefixes; 182 } 183 184 /** 185 * Sets the excluded file name prefixes, such as <tt>"."</tt> for hidden files which 186 * are excluded by default 187 */ 188 public void setExcludedNamePrefixes(String[] excludedNamePrefixes) { 189 this.excludedNamePrefixes = excludedNamePrefixes; 190 } 191 192 public String[] getExcludedNamePostfixes() { 193 return excludedNamePostfixes; 194 } 195 196 /** 197 * Sets the excluded file name postfixes, such as {@link FileProcessStrategySupport#DEFAULT_LOCK_FILE_POSTFIX} 198 * to ignore lock files by default. 199 */ 200 public void setExcludedNamePostfixes(String[] excludedNamePostfixes) { 201 this.excludedNamePostfixes = excludedNamePostfixes; 202 } 203 204 public boolean isNoop() { 205 return noop; 206 } 207 208 /** 209 * If set to true then the default {@link FileProcessStrategy} will be to use the 210 * {@link NoOpFileProcessStrategy} to not move or copy processed files 211 */ 212 public void setNoop(boolean noop) { 213 this.noop = noop; 214 } 215 216 public boolean isAppend() { 217 return append; 218 } 219 220 /** 221 * When writing do we append to the end of the file, or replace it? 222 * The default is to append 223 */ 224 public void setAppend(boolean append) { 225 this.append = append; 226 } 227 228 public int getBufferSize() { 229 return bufferSize; 230 } 231 232 /** 233 * Sets the buffer size used to read/write files 234 */ 235 public void setBufferSize(int bufferSize) { 236 this.bufferSize = bufferSize; 237 } 238 239 public boolean isIgnoreFileNameHeader() { 240 return ignoreFileNameHeader; 241 } 242 243 /** 244 * If this flag is enabled then producers will ignore the {@link FileComponent#HEADER_FILE_NAME} 245 * header and generate a new dynamic file 246 */ 247 public void setIgnoreFileNameHeader(boolean ignoreFileNameHeader) { 248 this.ignoreFileNameHeader = ignoreFileNameHeader; 249 } 250 251 /** 252 * A strategy method to lazily create the file strategy 253 */ 254 protected FileProcessStrategy createFileStrategy() { 255 return FileProcessStrategyFactory.createFileProcessStrategy(isNoop(), isDelete(), isLock(), moveNamePrefix, moveNamePostfix); 256 } 257 258 }