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