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: 687736 $
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 }