Author: davsclaus
Date: Wed Apr 25 11:26:00 2012
New Revision: 1330208
URL: http://svn.apache.org/viewvc?rev=1330208&view=rev
Log:
CAMEL-5215: Fixed file producer to use charset when writing files if given.
Added:
camel/trunk/camel-core/src/test/java/org/apache/camel/component/file/FileProducerCharsetUTFOptimizedTest.java
camel/trunk/camel-core/src/test/java/org/apache/camel/component/file/FileProducerCharsetUTFtoISOTest.java
camel/trunk/camel-core/src/test/java/org/apache/camel/component/file/FileProducerCharsetUTFtoUTFTest.java
Modified:
camel/trunk/camel-core/src/main/java/org/apache/camel/component/file/FileBinding.java
camel/trunk/camel-core/src/main/java/org/apache/camel/component/file/FileOperations.java
camel/trunk/camel-core/src/main/java/org/apache/camel/component/file/GenericFileConverter.java
camel/trunk/camel-core/src/main/java/org/apache/camel/component/file/GenericFileProducer.java
camel/trunk/camel-core/src/main/java/org/apache/camel/converter/IOConverter.java
camel/trunk/camel-core/src/main/java/org/apache/camel/util/IOHelper.java
Modified:
camel/trunk/camel-core/src/main/java/org/apache/camel/component/file/FileBinding.java
URL:
http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/component/file/FileBinding.java?rev=1330208&r1=1330207&r2=1330208&view=diff
==============================================================================
---
camel/trunk/camel-core/src/main/java/org/apache/camel/component/file/FileBinding.java
(original)
+++
camel/trunk/camel-core/src/main/java/org/apache/camel/component/file/FileBinding.java
Wed Apr 25 11:26:00 2012
@@ -54,7 +54,7 @@ public class FileBinding implements Gene
public void loadContent(Exchange exchange, GenericFile<?> file) throws
IOException {
if (content == null) {
try {
- content =
exchange.getContext().getTypeConverter().mandatoryConvertTo(byte[].class,
file.getFile());
+ content =
exchange.getContext().getTypeConverter().mandatoryConvertTo(byte[].class,
exchange, file.getFile());
} catch (NoTypeConversionAvailableException e) {
throw new IOException("Cannot load file content: " +
file.getAbsoluteFilePath(), e);
}
Modified:
camel/trunk/camel-core/src/main/java/org/apache/camel/component/file/FileOperations.java
URL:
http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/component/file/FileOperations.java?rev=1330208&r1=1330207&r2=1330208&view=diff
==============================================================================
---
camel/trunk/camel-core/src/main/java/org/apache/camel/component/file/FileOperations.java
(original)
+++
camel/trunk/camel-core/src/main/java/org/apache/camel/component/file/FileOperations.java
Wed Apr 25 11:26:00 2012
@@ -21,7 +21,10 @@ import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.InputStreamReader;
import java.io.RandomAccessFile;
+import java.io.Reader;
+import java.io.Writer;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Date;
@@ -29,6 +32,8 @@ import java.util.List;
import org.apache.camel.Exchange;
import org.apache.camel.InvalidPayloadException;
+import org.apache.camel.WrappedFile;
+import org.apache.camel.converter.IOConverter;
import org.apache.camel.util.FileUtil;
import org.apache.camel.util.IOHelper;
import org.apache.camel.util.ObjectHelper;
@@ -173,10 +178,24 @@ public class FileOperations implements G
// 3. write stream to file
try {
- // is the body file based
+ // determine charset, exchange property overrides endpoint
configuration
+ String charset = IOHelper.getCharsetName(exchange, false);
+ if (charset == null) {
+ charset = endpoint.getCharset();
+ }
+
+ // we can optimize and use file based if no charset must be used,
and the input body is a file
File source = null;
- // get the File Object from in message
- source = exchange.getIn().getBody(File.class);
+ if (charset == null) {
+ // if no charset, then we can try using file directly
(optimized)
+ Object body = exchange.getIn().getBody();
+ if (body instanceof WrappedFile) {
+ body = ((WrappedFile) body).getFile();
+ }
+ if (body instanceof File) {
+ source = (File) body;
+ }
+ }
if (source != null) {
// okay we know the body is a file type
@@ -205,9 +224,22 @@ public class FileOperations implements G
}
}
- // fallback and use stream based
- InputStream in =
exchange.getIn().getMandatoryBody(InputStream.class);
- writeFileByStream(in, file);
+ if (charset != null) {
+ // charset configured so we must use a reader so we can write
with encoding
+ Reader in = exchange.getIn().getBody(Reader.class);
+ if (in == null) {
+ // okay no direct reader conversion, so use an input
stream (which a lot can be converted as)
+ InputStream is =
exchange.getIn().getMandatoryBody(InputStream.class);
+ in = new InputStreamReader(is);
+ }
+ // buffer the reader
+ in = IOHelper.buffered(in);
+ writeFileByReaderWithCharset(in, file, charset);
+ } else {
+ // fallback and use stream based
+ InputStream in =
exchange.getIn().getMandatoryBody(InputStream.class);
+ writeFileByStream(in, file);
+ }
// try to keep last modified timestamp if configured to do so
keepLastModified(exchange, file);
return true;
@@ -239,7 +271,6 @@ public class FileOperations implements G
private boolean writeFileByLocalWorkPath(File source, File file) throws
IOException {
LOG.trace("Using local work file being renamed from: {} to: {}",
source, file);
-
return FileUtil.renameFile(source, file,
endpoint.isCopyAndDeleteOnRenameFail());
}
@@ -286,6 +317,19 @@ public class FileOperations implements G
}
}
+ private void writeFileByReaderWithCharset(Reader in, File target, String
charset) throws IOException {
+ boolean append = endpoint.getFileExist() == GenericFileExist.Append;
+ Writer out = IOConverter.toWriter(target, append, charset);
+ try {
+ LOG.trace("Using Reader to transfer from: {} to: {} with charset:
{}", new Object[]{in, out, charset});
+ int size = endpoint.getBufferSize();
+ IOHelper.copy(in, out, size);
+ } finally {
+ IOHelper.close(in, target.getName(), LOG);
+ IOHelper.close(out, target.getName(), LOG);
+ }
+ }
+
/**
* Creates and prepares the output file channel. Will position itself in
correct position if the file is writable
* eg. it should append or override any existing content.
Modified:
camel/trunk/camel-core/src/main/java/org/apache/camel/component/file/GenericFileConverter.java
URL:
http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/component/file/GenericFileConverter.java?rev=1330208&r1=1330207&r2=1330208&view=diff
==============================================================================
---
camel/trunk/camel-core/src/main/java/org/apache/camel/component/file/GenericFileConverter.java
(original)
+++
camel/trunk/camel-core/src/main/java/org/apache/camel/component/file/GenericFileConverter.java
Wed Apr 25 11:26:00 2012
@@ -17,7 +17,6 @@
package org.apache.camel.component.file;
import java.io.File;
-import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
@@ -25,9 +24,9 @@ import java.io.Serializable;
import org.apache.camel.Converter;
import org.apache.camel.Exchange;
import org.apache.camel.FallbackConverter;
+import org.apache.camel.NoTypeConversionAvailableException;
import org.apache.camel.TypeConverter;
import org.apache.camel.spi.TypeConverterRegistry;
-import org.apache.camel.util.IOHelper;
/**
* A set of converter methods for working with generic file types
@@ -64,11 +63,15 @@ public final class GenericFileConverter
}
@Converter
- public static InputStream genericFileToInputStream(GenericFile<?> file,
Exchange exchange) throws IOException {
+ public static InputStream genericFileToInputStream(GenericFile<?> file,
Exchange exchange) throws IOException, NoTypeConversionAvailableException {
if (exchange != null) {
- // use a file input stream if its a java.io.File
if (file.getFile() instanceof java.io.File) {
- return IOHelper.buffered(new FileInputStream((File)
file.getFile()));
+ // prefer to use a file input stream if its a java.io.File
(must use type converter to take care of encoding)
+ File f = (File) file.getFile();
+ InputStream is =
exchange.getContext().getTypeConverter().convertTo(InputStream.class, exchange,
f);
+ if (is != null) {
+ return is;
+ }
}
// otherwise ensure the body is loaded as we want the input stream
of the body
file.getBinding().loadContent(exchange, file);
Modified:
camel/trunk/camel-core/src/main/java/org/apache/camel/component/file/GenericFileProducer.java
URL:
http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/component/file/GenericFileProducer.java?rev=1330208&r1=1330207&r2=1330208&view=diff
==============================================================================
---
camel/trunk/camel-core/src/main/java/org/apache/camel/component/file/GenericFileProducer.java
(original)
+++
camel/trunk/camel-core/src/main/java/org/apache/camel/component/file/GenericFileProducer.java
Wed Apr 25 11:26:00 2012
@@ -59,8 +59,6 @@ public class GenericFileProducer<T> exte
}
public void process(Exchange exchange) throws Exception {
- endpoint.configureExchange(exchange);
-
String target = createFileName(exchange);
// use lock for same file name to avoid concurrent writes to the same
file
Modified:
camel/trunk/camel-core/src/main/java/org/apache/camel/converter/IOConverter.java
URL:
http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/converter/IOConverter.java?rev=1330208&r1=1330207&r2=1330208&view=diff
==============================================================================
---
camel/trunk/camel-core/src/main/java/org/apache/camel/converter/IOConverter.java
(original)
+++
camel/trunk/camel-core/src/main/java/org/apache/camel/converter/IOConverter.java
Wed Apr 25 11:26:00 2012
@@ -101,12 +101,16 @@ public final class IOConverter {
*/
@Deprecated
public static BufferedWriter toWriter(File file) throws IOException {
- return toWriter(file, null);
+ return toWriter(file, false, IOHelper.getCharsetName(null, true));
}
@Converter
public static BufferedWriter toWriter(File file, Exchange exchange) throws
IOException {
- return IOHelper.buffered(new EncodingFileWriter(file,
IOHelper.getCharsetName(exchange)));
+ return toWriter(file, false, IOHelper.getCharsetName(exchange));
+ }
+
+ public static BufferedWriter toWriter(File file, boolean append, String
charset) throws IOException {
+ return IOHelper.buffered(new EncodingFileWriter(file, append,
charset));
}
/**
@@ -434,6 +438,16 @@ public final class IOConverter {
super(new FileOutputStream(file), charset);
}
+ /**
+ * @param file file to write
+ * @param append whether to append to the file
+ * @param charset character set to use
+ */
+ public EncodingFileWriter(File file, boolean append, String charset)
+ throws FileNotFoundException, UnsupportedEncodingException {
+ super(new FileOutputStream(file, append), charset);
+ }
+
}
/**
Modified:
camel/trunk/camel-core/src/main/java/org/apache/camel/util/IOHelper.java
URL:
http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/util/IOHelper.java?rev=1330208&r1=1330207&r2=1330208&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/util/IOHelper.java
(original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/util/IOHelper.java
Wed Apr 25 11:26:00 2012
@@ -191,6 +191,20 @@ public final class IOHelper {
close(input, null, LOG);
}
+ public static int copy(final Reader input, final Writer output, int
bufferSize) throws IOException {
+ final char[] buffer = new char[bufferSize];
+ int n = input.read(buffer);
+ int total = 0;
+ while (-1 != n) {
+ output.write(buffer, 0, n);
+ total += n;
+ n = input.read(buffer);
+ }
+ output.flush();
+ return total;
+ }
+
+
/**
* Forces any updates to this channel's file to be written to the storage
device that contains it.
*
Added:
camel/trunk/camel-core/src/test/java/org/apache/camel/component/file/FileProducerCharsetUTFOptimizedTest.java
URL:
http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/component/file/FileProducerCharsetUTFOptimizedTest.java?rev=1330208&view=auto
==============================================================================
---
camel/trunk/camel-core/src/test/java/org/apache/camel/component/file/FileProducerCharsetUTFOptimizedTest.java
(added)
+++
camel/trunk/camel-core/src/test/java/org/apache/camel/component/file/FileProducerCharsetUTFOptimizedTest.java
Wed Apr 25 11:26:00 2012
@@ -0,0 +1,93 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.file;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.nio.charset.Charset;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.util.IOHelper;
+
+/**
+ *
+ */
+public class FileProducerCharsetUTFOptimizedTest extends ContextTestSupport {
+
+ private byte[] utf;
+
+ @Override
+ protected void setUp() throws Exception {
+ // use utf-8 as original payload with 00e6 which is a danish ae letter
+ utf = "ABC\u00e6".getBytes("utf-8");
+
+ deleteDirectory("target/charset");
+ createDirectory("target/charset/input");
+
+ log.debug("utf: {}", new String(utf, Charset.forName("utf-8")));
+
+ for (byte b : utf) {
+ log.debug("utf byte: {}", b);
+ }
+
+ // write the byte array to a file using plain API
+ FileOutputStream fos = new
FileOutputStream("target/charset/input/input.txt");
+ fos.write(utf);
+ fos.close();
+
+ super.setUp();
+ }
+
+ public void testFileProducerCharsetUTFOptimized() throws Exception {
+ oneExchangeDone.matchesMockWaitTime();
+
+ File file = new File("target/charset/output.txt").getAbsoluteFile();
+ assertTrue("File should exist", file.exists());
+
+ InputStream fis = IOHelper.buffered(new FileInputStream(file));
+ byte[] buffer = new byte[100];
+
+ int len = fis.read(buffer);
+ assertTrue("Should read data: " + len, len != -1);
+ byte[] data = new byte[len];
+ System.arraycopy(buffer, 0, data, 0, len);
+ fis.close();
+
+ // data should be in utf, where the danish ae is -61 -90
+ assertEquals(5, data.length);
+ assertEquals(65, data[0]);
+ assertEquals(66, data[1]);
+ assertEquals(67, data[2]);
+ assertEquals(-61, data[3]);
+ assertEquals(-90, data[4]);
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from("file:target/charset/input?noop=true")
+ // no charset so its optimized to write directly
+ .to("file:target/charset/?fileName=output.txt");
+ }
+ };
+ }
+}
Added:
camel/trunk/camel-core/src/test/java/org/apache/camel/component/file/FileProducerCharsetUTFtoISOTest.java
URL:
http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/component/file/FileProducerCharsetUTFtoISOTest.java?rev=1330208&view=auto
==============================================================================
---
camel/trunk/camel-core/src/test/java/org/apache/camel/component/file/FileProducerCharsetUTFtoISOTest.java
(added)
+++
camel/trunk/camel-core/src/test/java/org/apache/camel/component/file/FileProducerCharsetUTFtoISOTest.java
Wed Apr 25 11:26:00 2012
@@ -0,0 +1,97 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.file;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.nio.charset.Charset;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.util.IOHelper;
+
+/**
+ *
+ */
+public class FileProducerCharsetUTFtoISOTest extends ContextTestSupport {
+
+ private byte[] utf;
+ private byte[] iso;
+
+ @Override
+ protected void setUp() throws Exception {
+ // use utf-8 as original payload with 00e6 which is a danish ae letter
+ utf = "ABC\u00e6".getBytes("utf-8");
+ iso = "ABC\u00e6".getBytes("iso-8859-1");
+
+ deleteDirectory("target/charset");
+ createDirectory("target/charset/input");
+
+ log.debug("utf: {}", new String(utf, Charset.forName("utf-8")));
+ log.debug("iso: {}", new String(iso, Charset.forName("iso-8859-1")));
+
+ for (byte b : utf) {
+ log.debug("utf byte: {}", b);
+ }
+ for (byte b : iso) {
+ log.debug("iso byte: {}", b);
+ }
+
+ // write the byte array to a file using plain API
+ FileOutputStream fos = new
FileOutputStream("target/charset/input/input.txt");
+ fos.write(utf);
+ fos.close();
+
+ super.setUp();
+ }
+
+ public void testFileProducerCharsetUTFtoISO() throws Exception {
+ oneExchangeDone.matchesMockWaitTime();
+
+ File file = new File("target/charset/output.txt").getAbsoluteFile();
+ assertTrue("File should exist", file.exists());
+
+ InputStream fis = IOHelper.buffered(new FileInputStream(file));
+ byte[] buffer = new byte[100];
+
+ int len = fis.read(buffer);
+ assertTrue("Should read data: " + len, len != -1);
+ byte[] data = new byte[len];
+ System.arraycopy(buffer, 0, data, 0, len);
+ fis.close();
+
+ // data should be in iso, where the danish ae is -26
+ assertEquals(4, data.length);
+ assertEquals(65, data[0]);
+ assertEquals(66, data[1]);
+ assertEquals(67, data[2]);
+ assertEquals(-26, data[3]);
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from("file:target/charset/input?noop=true")
+
.to("file:target/charset/?fileName=output.txt&charset=iso-8859-1");
+ }
+ };
+ }
+}
Added:
camel/trunk/camel-core/src/test/java/org/apache/camel/component/file/FileProducerCharsetUTFtoUTFTest.java
URL:
http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/component/file/FileProducerCharsetUTFtoUTFTest.java?rev=1330208&view=auto
==============================================================================
---
camel/trunk/camel-core/src/test/java/org/apache/camel/component/file/FileProducerCharsetUTFtoUTFTest.java
(added)
+++
camel/trunk/camel-core/src/test/java/org/apache/camel/component/file/FileProducerCharsetUTFtoUTFTest.java
Wed Apr 25 11:26:00 2012
@@ -0,0 +1,92 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.file;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.nio.charset.Charset;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.util.IOHelper;
+
+/**
+ *
+ */
+public class FileProducerCharsetUTFtoUTFTest extends ContextTestSupport {
+
+ private byte[] utf;
+
+ @Override
+ protected void setUp() throws Exception {
+ // use utf-8 as original payload with 00e6 which is a danish ae letter
+ utf = "ABC\u00e6".getBytes("utf-8");
+
+ deleteDirectory("target/charset");
+ createDirectory("target/charset/input");
+
+ log.debug("utf: {}", new String(utf, Charset.forName("utf-8")));
+
+ for (byte b : utf) {
+ log.debug("utf byte: {}", b);
+ }
+
+ // write the byte array to a file using plain API
+ FileOutputStream fos = new
FileOutputStream("target/charset/input/input.txt");
+ fos.write(utf);
+ fos.close();
+
+ super.setUp();
+ }
+
+ public void testFileProducerCharsetUTFtoUTF() throws Exception {
+ oneExchangeDone.matchesMockWaitTime();
+
+ File file = new File("target/charset/output.txt").getAbsoluteFile();
+ assertTrue("File should exist", file.exists());
+
+ InputStream fis = IOHelper.buffered(new FileInputStream(file));
+ byte[] buffer = new byte[100];
+
+ int len = fis.read(buffer);
+ assertTrue("Should read data: " + len, len != -1);
+ byte[] data = new byte[len];
+ System.arraycopy(buffer, 0, data, 0, len);
+ fis.close();
+
+ // data should be in utf, where the danish ae is -61 -90
+ assertEquals(5, data.length);
+ assertEquals(65, data[0]);
+ assertEquals(66, data[1]);
+ assertEquals(67, data[2]);
+ assertEquals(-61, data[3]);
+ assertEquals(-90, data[4]);
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from("file:target/charset/input?noop=true")
+
.to("file:target/charset/?fileName=output.txt&charset=utf-8");
+ }
+ };
+ }
+}