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 }