Fix for DDLUTILS-233: DataReader doesn't support UTF-8

git-svn-id: https://svn.apache.org/repos/asf/db/ddlutils/trunk@987976 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/main/java/org/apache/ddlutils/io/DataReader.java b/src/main/java/org/apache/ddlutils/io/DataReader.java
index c8cd65c..8bc7b87 100644
--- a/src/main/java/org/apache/ddlutils/io/DataReader.java
+++ b/src/main/java/org/apache/ddlutils/io/DataReader.java
@@ -19,8 +19,10 @@
  * under the License.
  */
 
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
 import java.io.File;
-import java.io.FileReader;
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.Reader;
@@ -155,14 +157,7 @@
      */
     public void read(String filename) throws DdlUtilsXMLException
     {
-        try
-        {
-            read(new FileReader(filename));
-        }
-        catch (IOException ex)
-        {
-            throw new DdlUtilsXMLException(ex);
-        }
+        read(new File(filename));
     }
 
     /**
@@ -172,14 +167,31 @@
      */
     public void read(File file) throws DdlUtilsXMLException
     {
+        FileInputStream input = null;
+
         try
         {
-            read(new FileReader(file));
+            input = new FileInputStream(file);
+            read(input);
         }
         catch (IOException ex)
         {
             throw new DdlUtilsXMLException(ex);
         }
+        finally
+        {
+            if (input != null)
+            {
+                try
+                {
+                    input.close();
+                }
+                catch (IOException ex)
+                {
+                    _log.warn("Error while trying to close the input stream for " + file, ex);
+                }
+            }
+        }
     }
 
     /**
@@ -189,9 +201,19 @@
      */
     public void read(Reader reader) throws DdlUtilsXMLException
     {
+        BufferedReader bufferedReader;
+
+        if (reader instanceof BufferedReader)
+        {
+            bufferedReader = (BufferedReader)reader;
+        }
+        else
+        {
+            bufferedReader = new BufferedReader(reader);
+        }
         try
         {
-            read(getXMLInputFactory().createXMLStreamReader(reader));
+            read(getXMLInputFactory().createXMLStreamReader(bufferedReader));
         }
         catch (XMLStreamException ex)
         {
@@ -206,9 +228,19 @@
      */
     public void read(InputStream input) throws DdlUtilsXMLException
     {
+        BufferedInputStream bufferedInput;
+
+        if (input instanceof BufferedInputStream)
+        {
+            bufferedInput = (BufferedInputStream)input;
+        }
+        else
+        {
+            bufferedInput = new BufferedInputStream(input);
+        }
         try
         {
-            read(getXMLInputFactory().createXMLStreamReader(input));
+            read(getXMLInputFactory().createXMLStreamReader(bufferedInput));
         }
         catch (XMLStreamException ex)
         {
diff --git a/src/main/java/org/apache/ddlutils/io/DataWriter.java b/src/main/java/org/apache/ddlutils/io/DataWriter.java
index b90b06c..1fd7a72 100644
--- a/src/main/java/org/apache/ddlutils/io/DataWriter.java
+++ b/src/main/java/org/apache/ddlutils/io/DataWriter.java
@@ -20,6 +20,7 @@
  */

 

 import java.io.OutputStream;

+import java.io.UnsupportedEncodingException;

 import java.io.Writer;

 import java.util.ArrayList;

 import java.util.Collection;

@@ -202,7 +203,12 @@
                     if (writeBase64Encoded)

                     {

                         writeAttribute(null, DatabaseIO.BASE64_ATTR_NAME, "true");

-                        writeCData(new String(Base64.encodeBase64(content.getBytes())));

+                        try {

+                            writeCData(new String(Base64.encodeBase64(content.getBytes()), getEncoding()));

+                        }

+                        catch (UnsupportedEncodingException ex) {

+                            throw new DataWriterException(ex);

+                        }

                     }

                     else

                     {

diff --git a/src/main/java/org/apache/ddlutils/io/PrettyPrintingXmlWriter.java b/src/main/java/org/apache/ddlutils/io/PrettyPrintingXmlWriter.java
index ed86d66..c01bb26 100644
--- a/src/main/java/org/apache/ddlutils/io/PrettyPrintingXmlWriter.java
+++ b/src/main/java/org/apache/ddlutils/io/PrettyPrintingXmlWriter.java
@@ -19,8 +19,9 @@
  * under the License.
  */
 
+import java.io.BufferedOutputStream;
+import java.io.BufferedWriter;
 import java.io.OutputStream;
-import java.io.PrintWriter;
 import java.io.Writer;
 
 import javax.xml.stream.XMLOutputFactory;
@@ -37,8 +38,6 @@
     /** The indentation string. */
     private static final String INDENT_STRING = "  ";
 
-    /** The output stream. */
-    private PrintWriter _output;
     /** The xml writer. */
     private XMLStreamWriter _writer;
     /** The output encoding. */
@@ -64,7 +63,16 @@
      */
     public PrettyPrintingXmlWriter(OutputStream output, String encoding) throws DdlUtilsXMLException
     {
-        _output = new PrintWriter(output);
+        BufferedOutputStream bufferedOutput;
+
+        if (output instanceof BufferedOutputStream)
+        {
+            bufferedOutput = (BufferedOutputStream)output;
+        }
+        else
+        {
+            bufferedOutput = new BufferedOutputStream(output);
+        }
         if ((encoding == null) || (encoding.length() == 0))
         {
             _encoding = "UTF-8";
@@ -78,7 +86,7 @@
         {
             XMLOutputFactory factory = XMLOutputFactory.newInstance();
 
-            _writer  = factory.createXMLStreamWriter(output, _encoding);
+            _writer  = factory.createXMLStreamWriter(bufferedOutput, _encoding);
         }
         catch (XMLStreamException ex)
         {
@@ -95,13 +103,22 @@
      */
     public PrettyPrintingXmlWriter(Writer output, String encoding) throws DdlUtilsXMLException
     {
-        _output   = new PrintWriter(output);
+        BufferedWriter bufferedWriter;
+
+        if (output instanceof BufferedWriter)
+        {
+            bufferedWriter = (BufferedWriter)output;
+        }
+        else
+        {
+            bufferedWriter = new BufferedWriter(output);
+        }
         _encoding = encoding;
         try
         {
             XMLOutputFactory factory = XMLOutputFactory.newInstance();
 
-            _writer = factory.createXMLStreamWriter(_output);
+            _writer = factory.createXMLStreamWriter(bufferedWriter);
         }
         catch (XMLStreamException ex)
         {
@@ -110,6 +127,16 @@
     }
 
     /**
+     * Returnd the encoding used by this xml writer.
+     * 
+     * @return The encoding
+     */
+    public String getEncoding()
+    {
+        return _encoding;
+    }
+
+    /**
      * Rethrows the given exception, wrapped in a {@link DdlUtilsXMLException}. This
      * method allows subclasses to throw their own subclasses of this exception.
      * 
diff --git a/src/test/java/org/apache/ddlutils/io/TestDataReaderAndWriter.java b/src/test/java/org/apache/ddlutils/io/TestDataReaderAndWriter.java
index f53a3bf..982e9de 100644
--- a/src/test/java/org/apache/ddlutils/io/TestDataReaderAndWriter.java
+++ b/src/test/java/org/apache/ddlutils/io/TestDataReaderAndWriter.java
@@ -20,6 +20,8 @@
  */

 

 import java.io.BufferedWriter;

+import java.io.ByteArrayInputStream;

+import java.io.ByteArrayOutputStream;

 import java.io.File;

 import java.io.FileInputStream;

 import java.io.FileWriter;

@@ -31,6 +33,7 @@
 import junit.framework.TestCase;

 

 import org.apache.commons.beanutils.DynaBean;

+import org.apache.commons.codec.binary.Base64;

 import org.apache.commons.lang.StringUtils;

 import org.apache.ddlutils.dynabean.SqlDynaBean;

 import org.apache.ddlutils.model.Database;

@@ -738,10 +741,10 @@
 

         modelIO.setValidateXml(true);

         

-        Database     model      = modelIO.read(new StringReader(testSchemaXml));

-        StringWriter output     = new StringWriter();

-        DataWriter   dataWriter = new DataWriter(output, "UTF-8");

-        SqlDynaBean  bean       = (SqlDynaBean)model.createDynaBeanFor(model.getTable(0));

+        Database              model      = modelIO.read(new StringReader(testSchemaXml));

+        ByteArrayOutputStream output     = new ByteArrayOutputStream();

+        DataWriter            dataWriter = new DataWriter(output, "ISO-8859-1");

+        SqlDynaBean           bean       = (SqlDynaBean)model.createDynaBeanFor(model.getTable(0));

 

         bean.set("id", new Integer(1));

         bean.set("value", testedValue);

@@ -749,14 +752,81 @@
         dataWriter.write(bean);

         dataWriter.writeDocumentEnd();

 

-        String dataXml = output.toString();

+        final ArrayList readObjects = new ArrayList();

+        DataReader      dataReader  = new DataReader();

+

+        String dataXml = new String(output.toByteArray(), "ISO-8859-1");

+

+        assertEquals("<?xml version='1.0' encoding='ISO-8859-1'?>\n" +

+                     "<data>\n" +

+                     "  <test id=\"1\">\n" +

+                     "    <value " + DatabaseIO.BASE64_ATTR_NAME + "=\"true\"><![CDATA[" + new String(Base64.encodeBase64(testedValue.getBytes()), "ISO-8859-1") + "]]></value>\n" +

+                     "  </test>\n" +

+                     "</data>\n",

+                     dataXml);

+

+        dataReader.setModel(model);

+        dataReader.setSink(new TestDataSink(readObjects));

+        dataReader.read(new ByteArrayInputStream(output.toByteArray()));

+

+        assertEquals(1, readObjects.size());

+

+        DynaBean obj = (DynaBean)readObjects.get(0);

+

+        assertEquals("test",

+                     obj.getDynaClass().getName());

+        assertEquals("1",

+                     obj.get("id").toString());

+        assertEquals(testedValue,

+                     obj.get("value").toString());

+    }

+

+    /**

+     * Tests special characters in the data XML (for DDLUTILS-233).

+     */

+    public void testSpecialCharactersUTF8() throws Exception

+    {

+        final String testSchemaXml = 

+            "<?xml version='1.0' encoding='UTF-8'?>\n"+

+            "<database xmlns='" + DatabaseIO.DDLUTILS_NAMESPACE + "' name='test'>\n" +

+            "  <table name='test'>\n"+

+            "    <column name='id' type='INTEGER' primaryKey='true' required='true'/>\n"+

+            "    <column name='value' type='VARCHAR' size='50' required='true'/>\n"+

+            "  </table>\n"+

+            "</database>";

+        final String testedValue = "Some Special Characters: \u0001\u0009\u0010";

+

+        DatabaseIO modelIO = new DatabaseIO();

+

+        modelIO.setValidateXml(true);

+        

+        Database              model      = modelIO.read(new StringReader(testSchemaXml));

+        ByteArrayOutputStream output     = new ByteArrayOutputStream();

+        DataWriter            dataWriter = new DataWriter(output, "UTF-8");

+        SqlDynaBean           bean       = (SqlDynaBean)model.createDynaBeanFor(model.getTable(0));

+

+        bean.set("id", new Integer(1));

+        bean.set("value", testedValue);

+        dataWriter.writeDocumentStart();

+        dataWriter.write(bean);

+        dataWriter.writeDocumentEnd();

+

+        String dataXml = new String(output.toByteArray(), "UTF-8");

+

+        assertEquals("<?xml version='1.0' encoding='UTF-8'?>\n" +

+                     "<data>\n" +

+                     "  <test id=\"1\">\n" +

+                     "    <value " + DatabaseIO.BASE64_ATTR_NAME + "=\"true\"><![CDATA[" + new String(Base64.encodeBase64(testedValue.getBytes()), "UTF-8") + "]]></value>\n" +

+                     "  </test>\n" +

+                     "</data>\n",

+                     dataXml);

 

         final ArrayList readObjects = new ArrayList();

         DataReader      dataReader  = new DataReader();

 

         dataReader.setModel(model);

         dataReader.setSink(new TestDataSink(readObjects));

-        dataReader.read(new StringReader(dataXml));

+        dataReader.read(new ByteArrayInputStream(output.toByteArray()));

 

         assertEquals(1, readObjects.size());