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    }