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    }