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 }