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