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    import java.io.Serializable;
021    
022    import org.apache.camel.util.FileUtil;
023    import org.apache.camel.util.ObjectHelper;
024    import org.apache.commons.logging.Log;
025    import org.apache.commons.logging.LogFactory;
026    
027    /**
028     * Generic File. Specific implementations of a file based endpoint need to
029     * provide a File for transfer.
030     */
031    public class GenericFile<T> implements Cloneable, Serializable {
032    
033        private static final Log LOG = LogFactory.getLog(GenericFile.class);
034    
035        private String endpointPath;
036        private String fileName;
037        private String fileNameOnly;
038        private String relativeFilePath;
039        private String absoluteFilePath;
040        private long fileLength;
041        private long lastModified;
042        private T file;
043        private GenericFileBinding<T> binding;
044        private boolean absolute;
045    
046        public char getFileSeparator() {
047            return File.separatorChar;
048        }
049    
050        @Override
051        public GenericFile<T> clone() {
052            return copyFrom(this);
053        }
054    
055        /**
056         * Creates a clone based on the source
057         *
058         * @param source the source
059         * @return a clone of the source
060         */
061        @SuppressWarnings("unchecked")
062        public GenericFile<T> copyFrom(GenericFile<T> source) {
063            GenericFile<T> result;
064            try {
065                result = source.getClass().newInstance();
066            } catch (Exception e) {
067                throw ObjectHelper.wrapRuntimeCamelException(e);
068            }
069            result.setEndpointPath(source.getEndpointPath());
070            result.setAbsolute(source.isAbsolute());
071            result.setAbsoluteFilePath(source.getAbsoluteFilePath());
072            result.setRelativeFilePath(source.getRelativeFilePath());
073            result.setFileName(source.getFileName());
074            result.setFileNameOnly(source.getFileNameOnly());
075            result.setFileLength(source.getFileLength());
076            result.setLastModified(source.getLastModified());
077            result.setFile(source.getFile());
078            result.setBody(source.getBody());
079            result.setBinding(source.getBinding());
080            return result;
081        }
082        
083        protected boolean isAbsolute(String name) {
084            File file = new File(name);
085            return file.isAbsolute();        
086        }
087        
088        protected String normalizePath(String name) {
089            return FileUtil.normalizePath(name);
090        }
091       
092        /**
093         * Changes the name of this remote file. This method alters the absolute and
094         * relative names as well.
095         *
096         * @param newName the new name
097         */
098        public void changeFileName(String newName) {
099            if (LOG.isTraceEnabled()) {
100                LOG.trace("Changing name to: " + newName);
101            }
102    
103            // Make sure the newName is normalized.
104            String newFileName = normalizePath(newName);
105    
106            if (LOG.isTraceEnabled()) {            
107                LOG.trace("Normalized endpointPath: " + endpointPath);
108                LOG.trace("Normalized newFileName: " + newFileName);
109            }
110    
111            File file = new File(newFileName);
112            if (!absolute) {
113                // for relative then we should avoid having the endpoint path duplicated so clip it
114                if (ObjectHelper.isNotEmpty(endpointPath) && newFileName.startsWith(endpointPath)) {
115                    // clip starting endpoint in case it was added
116                    newFileName = ObjectHelper.after(newFileName, endpointPath + getFileSeparator());
117    
118                    // reconstruct file with clipped name
119                    file = new File(newFileName);
120                }
121            }
122    
123            // store the file name only
124            setFileNameOnly(file.getName());
125            setFileName(file.getName());
126    
127            // relative path
128            if (file.getParent() != null) {
129                setRelativeFilePath(file.getParent() + getFileSeparator() + file.getName());
130            } else {
131                setRelativeFilePath(file.getName());
132            }
133    
134            // absolute path
135            if (isAbsolute(newFileName)) {
136                setAbsolute(true);
137                setAbsoluteFilePath(newFileName);
138            } else {
139                setAbsolute(false);
140                // construct a pseudo absolute filename that the file operations uses even for relative only
141                String path = ObjectHelper.isEmpty(endpointPath) ? "" : endpointPath + getFileSeparator();
142                setAbsoluteFilePath(path + getRelativeFilePath());
143            }
144    
145            if (LOG.isTraceEnabled()) {
146                LOG.trace("FileNameOnly: " + getFileNameOnly());
147                LOG.trace("FileName: " + getFileName());
148                LOG.trace("Absolute: " + isAbsolute());
149                LOG.trace("Relative path: " + getRelativeFilePath());
150                LOG.trace("Absolute path: " + getAbsoluteFilePath());
151                LOG.trace("Name changed to: " + this);
152            }
153        }
154    
155        public String getRelativeFilePath() {
156            return relativeFilePath;
157        }
158    
159        public void setRelativeFilePath(String relativeFilePath) {
160            this.relativeFilePath = normalizePathToProtocol(relativeFilePath);
161        }
162    
163        public String getFileName() {
164            return fileName;
165        }
166    
167        public void setFileName(String fileName) {
168            this.fileName = normalizePathToProtocol(fileName);
169        }
170    
171        public long getFileLength() {
172            return fileLength;
173        }
174    
175        public void setFileLength(long fileLength) {
176            this.fileLength = fileLength;
177        }
178    
179        public long getLastModified() {
180            return lastModified;
181        }
182    
183        public void setLastModified(long lastModified) {
184            this.lastModified = lastModified;
185        }
186    
187        public T getFile() {
188            return file;
189        }
190    
191        public void setFile(T file) {
192            this.file = file;
193        }
194    
195        public Object getBody() {
196            return getBinding().getBody(this);
197        }
198    
199        public void setBody(Object os) {
200            getBinding().setBody(this, os);
201        }
202    
203        public String getParent() {
204            String parent;
205            if (isAbsolute()) {
206                String name = getAbsoluteFilePath();
207                File path = new File(name);
208                parent = path.getParent();
209            } else {
210                String name = getRelativeFilePath();
211                File path = new File(endpointPath, name);
212                parent = path.getParent();
213            }
214            return normalizePathToProtocol(parent);
215        }
216    
217        public GenericFileBinding<T> getBinding() {
218            if (binding == null) {
219                binding = new GenericFileDefaultBinding<T>();
220            }
221            return binding;
222        }
223    
224        public void setBinding(GenericFileBinding<T> binding) {
225            this.binding = binding;
226        }
227    
228        public void setAbsoluteFilePath(String absoluteFilePath) {
229            this.absoluteFilePath = normalizePathToProtocol(absoluteFilePath);
230        }
231    
232        public String getAbsoluteFilePath() {
233            return absoluteFilePath;
234        }
235    
236        public boolean isAbsolute() {
237            return absolute;
238        }
239    
240        public void setAbsolute(boolean absolute) {
241            this.absolute = absolute;
242        }
243    
244        public String getEndpointPath() {
245            return endpointPath;
246        }
247    
248        public void setEndpointPath(String endpointPath) {
249            this.endpointPath = normalizePathToProtocol(endpointPath);
250        }
251    
252        public String getFileNameOnly() {
253            return fileNameOnly;
254        }
255    
256        public void setFileNameOnly(String fileNameOnly) {
257            this.fileNameOnly = fileNameOnly;
258        }
259    
260        /**
261         * Fixes the path separator to be according to the protocol
262         */
263        protected String normalizePathToProtocol(String path) {
264            if (ObjectHelper.isEmpty(path)) {
265                return path;
266            }
267            path = path.replace('/', getFileSeparator());
268            path = path.replace('\\', getFileSeparator());
269            return path;
270        }
271    
272        @Override
273        public String toString() {
274            return "GenericFile[" + (absolute ? absoluteFilePath : relativeFilePath) + "]";
275        }
276    
277    }