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");
+            }
+        };
+    }
+}


Reply via email to