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