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.FileInputStream; 021 import java.io.FileOutputStream; 022 import java.io.IOException; 023 import java.io.InputStream; 024 import java.io.RandomAccessFile; 025 import java.nio.ByteBuffer; 026 import java.nio.channels.FileChannel; 027 028 import org.apache.camel.Exchange; 029 import org.apache.camel.Expression; 030 import org.apache.camel.Message; 031 import org.apache.camel.impl.DefaultProducer; 032 import org.apache.camel.language.simple.FileLanguage; 033 import org.apache.camel.util.ExchangeHelper; 034 import org.apache.camel.util.ObjectHelper; 035 import org.apache.commons.logging.Log; 036 import org.apache.commons.logging.LogFactory; 037 038 /** 039 * For producing files. 040 * 041 * @version $Revision: 1094 $ 042 */ 043 public class FileProducer extends DefaultProducer { 044 private static final transient Log LOG = LogFactory.getLog(FileProducer.class); 045 private FileEndpoint endpoint; 046 047 public FileProducer(FileEndpoint endpoint) { 048 super(endpoint); 049 this.endpoint = endpoint; 050 } 051 052 /** 053 * @deprecated will be removed in Camel 2.0. 054 */ 055 public FileEndpoint getEndpoint() { 056 return endpoint; 057 } 058 059 public void process(Exchange exchange) throws Exception { 060 FileExchange fileExchange = endpoint.createExchange(exchange); 061 process(fileExchange); 062 ExchangeHelper.copyResults(exchange, fileExchange); 063 } 064 065 public void process(FileExchange exchange) throws Exception { 066 boolean fileSource = exchange.getIn().getBody() instanceof File; 067 File target = createFileName(exchange.getIn()); 068 buildDirectory(target); 069 070 if (LOG.isDebugEnabled()) { 071 LOG.debug("About to write to: " + target + " from exchange: " + exchange); 072 } 073 074 if (fileSource) { 075 File source = ExchangeHelper.getMandatoryInBody(exchange, File.class); 076 writeFileByFile(source, target); 077 } else { 078 InputStream in = ExchangeHelper.getMandatoryInBody(exchange, InputStream.class); 079 writeFileByStream(in, target); 080 } 081 } 082 083 private void writeFileByFile(File source, File target) throws IOException { 084 FileChannel in = new FileInputStream(source).getChannel(); 085 FileChannel out = null; 086 try { 087 out = prepareOutputFileChannel(target, out); 088 089 if (LOG.isTraceEnabled()) { 090 LOG.trace("Using FileChannel to transfer from: " + in + " to: " + out); 091 } 092 in.transferTo(0, in.size(), out); 093 } finally { 094 ObjectHelper.close(in, source.getName(), LOG); 095 ObjectHelper.close(out, source.getName(), LOG); 096 } 097 } 098 099 private void writeFileByStream(InputStream in, File target) throws IOException { 100 FileChannel out = null; 101 try { 102 out = prepareOutputFileChannel(target, out); 103 104 if (LOG.isTraceEnabled()) { 105 LOG.trace("Using InputStream to transfer from: " + in + " to: " + out); 106 } 107 int size = endpoint.getBufferSize(); 108 byte[] buffer = new byte[size]; 109 ByteBuffer byteBuffer = ByteBuffer.wrap(buffer); 110 while (true) { 111 int count = in.read(buffer); 112 if (count <= 0) { 113 break; 114 } else if (count < size) { 115 byteBuffer = ByteBuffer.wrap(buffer, 0, count); 116 out.write(byteBuffer); 117 break; 118 } else { 119 out.write(byteBuffer); 120 byteBuffer.clear(); 121 } 122 } 123 } finally { 124 ObjectHelper.close(in, target.getName(), LOG); 125 ObjectHelper.close(out, target.getName(), LOG); 126 } 127 } 128 129 /** 130 * Creates and prepares the output file channel. Will position itself in correct position if eg. it should append 131 * or override any existing content. 132 */ 133 private FileChannel prepareOutputFileChannel(File target, FileChannel out) throws IOException { 134 if (endpoint.isAppend()) { 135 out = new RandomAccessFile(target, "rw").getChannel(); 136 out = out.position(out.size()); 137 } else { 138 out = new FileOutputStream(target).getChannel(); 139 } 140 return out; 141 } 142 143 protected File createFileName(Message message) { 144 File answer; 145 146 String name = null; 147 if (!endpoint.isIgnoreFileNameHeader()) { 148 name = message.getHeader(FileComponent.HEADER_FILE_NAME, String.class); 149 } 150 151 // expression support 152 Expression expression = endpoint.getExpression(); 153 if (name != null) { 154 // the header name can be an expression too, that should override whatever configured on the endpoint 155 if (name.indexOf("${") > -1) { 156 if (LOG.isDebugEnabled()) { 157 LOG.debug(FileComponent.HEADER_FILE_NAME + " contains a FileLanguage expression: " + name); 158 } 159 expression = FileLanguage.file(name); 160 } 161 } 162 if (expression != null) { 163 if (LOG.isDebugEnabled()) { 164 LOG.debug("Filename evaluated as expression: " + expression); 165 } 166 Object result = expression.evaluate(message.getExchange()); 167 name = message.getExchange().getContext().getTypeConverter().convertTo(String.class, result); 168 } 169 170 File endpointFile = endpoint.getFile(); 171 if (endpointFile.isDirectory()) { 172 if (name != null) { 173 answer = new File(endpointFile, name); 174 if (answer.isDirectory()) { 175 answer = new File(answer, endpoint.getGeneratedFileName(message)); 176 } 177 } else { 178 answer = new File(endpointFile, endpoint.getGeneratedFileName(message)); 179 } 180 } else { 181 if (name == null) { 182 answer = endpointFile; 183 } else { 184 answer = new File(endpointFile, name); 185 } 186 } 187 188 // lets store the name we really used in the header, so end-users can retrieve it 189 message.setHeader(FileComponent.HEADER_FILE_NAME_PRODUCED, answer.getAbsolutePath()); 190 191 return answer; 192 } 193 194 private void buildDirectory(File file) { 195 String dirName = file.getAbsolutePath(); 196 int index = dirName.lastIndexOf(File.separatorChar); 197 if (index > 0) { 198 dirName = dirName.substring(0, index); 199 File dir = new File(dirName); 200 dir.mkdirs(); 201 } 202 } 203 204 }