Author: tomdz
Date: Tue Oct 10 13:29:40 2006
New Revision: 462544

URL: http://svn.apache.org/viewvc?view=rev&rev=462544
Log:
Fixed DDLUTILS-63: values that contain characters that cannot be put into an 
XML file, are now encoded in Base64 and a sub element will always be used 
(instead of an attribute) which has the attribute base64="true"

Added:
    db/ddlutils/trunk/lib/stax-api-1.0.1.jar   (with props)
    db/ddlutils/trunk/lib/wstx-asl-3.0.2.jar   (with props)
    
db/ddlutils/trunk/src/test/org/apache/ddlutils/io/TestDataReaderAndWriter.java
      - copied, changed from r454479, 
db/ddlutils/trunk/src/test/org/apache/ddlutils/io/TestDataReader.java
Removed:
    db/ddlutils/trunk/lib/stax-1.1.2-dev.jar
    db/ddlutils/trunk/lib/stax-api-1.0.jar
    db/ddlutils/trunk/src/test/org/apache/ddlutils/io/TestDataReader.java
Modified:
    db/ddlutils/trunk/.classpath
    db/ddlutils/trunk/src/java/org/apache/ddlutils/io/DataWriter.java
    db/ddlutils/trunk/src/java/org/apache/ddlutils/io/DatabaseIO.java
    
db/ddlutils/trunk/src/java/org/apache/ddlutils/io/SetColumnPropertyFromSubElementRule.java
    db/ddlutils/trunk/src/test/org/apache/ddlutils/RunAllTests.java

Modified: db/ddlutils/trunk/.classpath
URL: 
http://svn.apache.org/viewvc/db/ddlutils/trunk/.classpath?view=diff&rev=462544&r1=462543&r2=462544
==============================================================================
--- db/ddlutils/trunk/.classpath (original)
+++ db/ddlutils/trunk/.classpath Tue Oct 10 13:29:40 2006
@@ -9,12 +9,12 @@
        <classpathentry path="lib/commons-dbcp-1.2.1.jar" exported="true" 
kind="lib"/>
        <classpathentry path="lib/commons-digester-1.7.jar" exported="true" 
kind="lib"/>
        <classpathentry path="lib/commons-beanutils-1.7.0.jar" exported="true" 
kind="lib"/>
-       <classpathentry path="lib/stax-api-1.0.jar" exported="true" kind="lib"/>
        <classpathentry path="lib/commons-betwixt-0.8-dev.jar" exported="true" 
kind="lib"/>
        <classpathentry path="lib/commons-lang-2.1.jar" exported="true" 
kind="lib"/>
        <classpathentry path="lib/commons-codec-1.3.jar" exported="true" 
kind="lib"/>
        <classpathentry path="lib/jakarta-oro-2.0.8.jar" exported="true" 
kind="lib"/>
        <classpathentry path="lib/build-only/ant-1.6.5.jar" kind="lib"/>
        <classpathentry path="lib/build-only/junit-3.8.2.jar" kind="lib"/>
+       <classpathentry path="lib/stax-api-1.0.1.jar" kind="lib"/>
        <classpathentry path="target/classes" kind="output"/>
 </classpath>

Added: db/ddlutils/trunk/lib/stax-api-1.0.1.jar
URL: 
http://svn.apache.org/viewvc/db/ddlutils/trunk/lib/stax-api-1.0.1.jar?view=auto&rev=462544
==============================================================================
Binary file - no diff available.

Propchange: db/ddlutils/trunk/lib/stax-api-1.0.1.jar
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: db/ddlutils/trunk/lib/wstx-asl-3.0.2.jar
URL: 
http://svn.apache.org/viewvc/db/ddlutils/trunk/lib/wstx-asl-3.0.2.jar?view=auto&rev=462544
==============================================================================
Binary file - no diff available.

Propchange: db/ddlutils/trunk/lib/wstx-asl-3.0.2.jar
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/io/DataWriter.java
URL: 
http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/io/DataWriter.java?view=diff&rev=462544&r1=462543&r2=462544
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/io/DataWriter.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/io/DataWriter.java Tue Oct 
10 13:29:40 2006
@@ -18,6 +18,7 @@
 
 import java.io.OutputStream;
 import java.io.PrintWriter;
+import java.io.Writer;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -28,6 +29,7 @@
 import javax.xml.stream.XMLStreamWriter;
 
 import org.apache.commons.beanutils.DynaBean;
+import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.ddlutils.dynabean.SqlDynaBean;
@@ -108,6 +110,29 @@
     }
 
     /**
+     * Creates a data writer instance using the specified writer. Note that 
the writer
+     * needs to be configured using the specified encoding.
+     * 
+     * @param output   The target to write the data XML to
+     * @param encoding The encoding of the writer
+     */
+    public DataWriter(Writer output, String encoding) throws 
DataWriterException
+    {
+        _output   = new PrintWriter(output);
+        _encoding = encoding;
+        try
+        {
+            XMLOutputFactory factory = XMLOutputFactory.newInstance();
+
+            _writer = factory.createXMLStreamWriter(_output);
+        }
+        catch (XMLStreamException ex)
+        {
+            throw new DataWriterException(ex);
+        }
+    }
+
+    /**
      * Determines whether the output shall be pretty-printed.
      *
      * @return <code>true</code> if the output is pretty-printed
@@ -252,7 +277,9 @@
                 }
                 if (valueAsText != null)
                 {
-                    if (valueAsText.length() > MAX_ATTRIBUTE_LENGTH)
+                    // we create an attribute only if the text is not too long
+                    // and if it does not contain special characters
+                    if ((valueAsText.length() > MAX_ATTRIBUTE_LENGTH) || 
containsSpecialCharacters(valueAsText))
                     {
                         // we defer writing the sub elements
                         subElements.put(column.getName(), valueAsText);
@@ -267,12 +294,25 @@
             {
                 for (Iterator it = subElements.entrySet().iterator(); 
it.hasNext();)
                 {
-                    Map.Entry entry = (Map.Entry)it.next();
-        
+                    Map.Entry entry     = (Map.Entry)it.next();
+                    String    content   = entry.getValue().toString();
+
                     printlnIfPrettyPrinting();
                     indentIfPrettyPrinting(2);
                     _writer.writeStartElement(entry.getKey().toString());
-                    _writer.writeCData(entry.getValue().toString());
+
+                    // if the content contains special characters, we have to 
apply base64 encoding to it
+                    // if the content is too short, then it has to contain 
special characters, otherwise we check
+                    if ((content.length() <= MAX_ATTRIBUTE_LENGTH) || 
containsSpecialCharacters(content))
+                    {
+                        _writer.writeAttribute(DatabaseIO.BASE64_ATTR_NAME, 
"true");
+                        _writer.writeCData(new 
String(Base64.encodeBase64(content.getBytes())));
+                    }
+                    else
+                    {
+                        _writer.writeCData(content);
+                    }
+
                     _writer.writeEndElement();
                 }
                 printlnIfPrettyPrinting();
@@ -289,6 +329,29 @@
         {
             throw new DataWriterException(ex);
         }
+    }
+
+    /**
+     * Determines whether the given string contains special characters that 
cannot
+     * be used in XML.
+     * 
+     * @param text The text
+     * @return <code>true</code> if the text contains special characters
+     */
+    private boolean containsSpecialCharacters(String text)
+    {
+        int numChars = text.length();
+
+        for (int charPos = 0; charPos < numChars; charPos++)
+        {
+            char c = text.charAt(charPos);
+
+            if ((c < 0x0020) && (c != '\n') && (c != '\r') && (c != '\t'))
+            {
+                return true;
+            }
+        }
+        return false;
     }
 
     /**

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/io/DatabaseIO.java
URL: 
http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/io/DatabaseIO.java?view=diff&rev=462544&r1=462543&r2=462544
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/io/DatabaseIO.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/io/DatabaseIO.java Tue Oct 
10 13:29:40 2006
@@ -44,6 +44,10 @@
  */
 public class DatabaseIO
 {
+    /** The name of the XML attribute use to denote that teh content of a data 
XML
+        element uses Base64 encoding. */
+    public static final String BASE64_ATTR_NAME = "base64";
+
     /** Whether to validate the XML. */
     private boolean _validateXml = true;
     /** Whether to use the internal dtd that comes with DdlUtils. */

Modified: 
db/ddlutils/trunk/src/java/org/apache/ddlutils/io/SetColumnPropertyFromSubElementRule.java
URL: 
http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/io/SetColumnPropertyFromSubElementRule.java?view=diff&rev=462544&r1=462543&r2=462544
==============================================================================
--- 
db/ddlutils/trunk/src/java/org/apache/ddlutils/io/SetColumnPropertyFromSubElementRule.java
 (original)
+++ 
db/ddlutils/trunk/src/java/org/apache/ddlutils/io/SetColumnPropertyFromSubElementRule.java
 Tue Oct 10 13:29:40 2006
@@ -17,9 +17,11 @@
  */
 
 import org.apache.commons.beanutils.PropertyUtils;
+import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.digester.Rule;
 import org.apache.ddlutils.io.converters.SqlTypeConverter;
 import org.apache.ddlutils.model.Column;
+import org.xml.sax.Attributes;
 
 /**
  * A digester rule for setting a bean property that corresponds to a column
@@ -34,6 +36,8 @@
     private Column _column;
     /** The converter for generating the property value from a string. */
     private SqlTypeConverter _converter;
+    /** Whether the element's content uses Base64. */
+    private boolean _usesBase64 = false;
 
     /**
      * Creates a new creation rule that sets the property corresponding to the 
given column.
@@ -50,9 +54,45 @@
     /**
      * [EMAIL PROTECTED]
      */
+    public void begin(Attributes attributes) throws Exception
+    {
+        for (int idx = 0; idx < attributes.getLength(); idx++)
+        {
+            String attrName = attributes.getLocalName(idx);
+
+            if ("".equals(attrName))
+            {
+                attrName = attributes.getQName(idx);
+            }
+            if (DatabaseIO.BASE64_ATTR_NAME.equals(attrName) &&
+                "true".equalsIgnoreCase(attributes.getValue(idx)))
+            {
+                _usesBase64 = true;
+                break;
+            }
+        }
+    }
+
+    /**
+     * [EMAIL PROTECTED]
+     */
+    public void end() throws Exception
+    {
+        _usesBase64 = false;
+    }
+
+    /**
+     * [EMAIL PROTECTED]
+     */
     public void body(String text) throws Exception
     {
         String attrValue = text.trim();
+
+        if (_usesBase64 && (attrValue != null))
+        {
+            attrValue = new String(Base64.decodeBase64(attrValue.getBytes()));
+        }
+
         Object propValue = (_converter != null ? 
_converter.convertFromString(attrValue, _column.getTypeCode()) : attrValue);
 
         if (digester.getLogger().isDebugEnabled())

Modified: db/ddlutils/trunk/src/test/org/apache/ddlutils/RunAllTests.java
URL: 
http://svn.apache.org/viewvc/db/ddlutils/trunk/src/test/org/apache/ddlutils/RunAllTests.java?view=diff&rev=462544&r1=462543&r2=462544
==============================================================================
--- db/ddlutils/trunk/src/test/org/apache/ddlutils/RunAllTests.java (original)
+++ db/ddlutils/trunk/src/test/org/apache/ddlutils/RunAllTests.java Tue Oct 10 
13:29:40 2006
@@ -21,7 +21,7 @@
 import org.apache.ddlutils.dynabean.TestDynaSqlQueries;
 import org.apache.ddlutils.io.TestAlteration;
 import org.apache.ddlutils.io.TestConstraints;
-import org.apache.ddlutils.io.TestDataReader;
+import org.apache.ddlutils.io.TestDataReaderAndWriter;
 import org.apache.ddlutils.io.TestDatabaseIO;
 import org.apache.ddlutils.io.TestDatatypes;
 import org.apache.ddlutils.io.converters.TestDateConverter;
@@ -93,7 +93,7 @@
         suite.addTestSuite(TestSqlBuilder.class);
         suite.addTestSuite(TestPlatformUtils.class);
         suite.addTestSuite(TestDatabaseIO.class);
-        suite.addTestSuite(TestDataReader.class);
+        suite.addTestSuite(TestDataReaderAndWriter.class);
         suite.addTestSuite(TestDateConverter.class);
         suite.addTestSuite(TestTimeConverter.class);
         suite.addTestSuite(TestAxionPlatform.class);

Copied: 
db/ddlutils/trunk/src/test/org/apache/ddlutils/io/TestDataReaderAndWriter.java 
(from r454479, 
db/ddlutils/trunk/src/test/org/apache/ddlutils/io/TestDataReader.java)
URL: 
http://svn.apache.org/viewvc/db/ddlutils/trunk/src/test/org/apache/ddlutils/io/TestDataReaderAndWriter.java?view=diff&rev=462544&p1=db/ddlutils/trunk/src/test/org/apache/ddlutils/io/TestDataReader.java&r1=454479&p2=db/ddlutils/trunk/src/test/org/apache/ddlutils/io/TestDataReaderAndWriter.java&r2=462544
==============================================================================
--- db/ddlutils/trunk/src/test/org/apache/ddlutils/io/TestDataReader.java 
(original)
+++ 
db/ddlutils/trunk/src/test/org/apache/ddlutils/io/TestDataReaderAndWriter.java 
Tue Oct 10 13:29:40 2006
@@ -17,78 +17,77 @@
  */
 
 import java.io.StringReader;
+import java.io.StringWriter;
 import java.util.ArrayList;
 
 import junit.framework.TestCase;
 
 import org.apache.commons.beanutils.DynaBean;
+import org.apache.ddlutils.dynabean.SqlDynaBean;
 import org.apache.ddlutils.model.Database;
 
 /**
- * Tests the [EMAIL PROTECTED] org.apache.ddlutils.io.DataReader} class.
+ * Tests the [EMAIL PROTECTED] org.apache.ddlutils.io.DataReader} and [EMAIL 
PROTECTED] org.apache.ddlutils.io.DataWriter} classes.
  * 
  * @author Thomas Dudziak
  * @version $Revision: 289996 $
  */
-public class TestDataReader extends TestCase
+public class TestDataReaderAndWriter extends TestCase
 {
-    /** The tested XML database schema. */
-    private static final String TEST_SCHEMA = 
-        "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"+
-        "<database name=\"bookstore\">\n"+
-        "  <table name=\"author\">\n"+
-        "    <column name=\"author_id\" type=\"INTEGER\" primaryKey=\"true\" 
required=\"true\"/>\n"+
-        "    <column name=\"name\" type=\"VARCHAR\" size=\"50\" 
required=\"true\"/>\n"+
-        "    <column name=\"organisation\" type=\"VARCHAR\" size=\"50\" 
required=\"false\"/>\n"+
-        "  </table>\n"+
-        "  <table name=\"book\">\n"+
-        "    <column name=\"book_id\" type=\"INTEGER\" required=\"true\" 
primaryKey=\"true\" autoIncrement=\"true\"/>\n"+
-        "    <column name=\"isbn\" type=\"VARCHAR\" size=\"15\" 
required=\"true\"/>\n"+
-        "    <column name=\"author_id\" type=\"INTEGER\" 
required=\"true\"/>\n"+
-        "    <column name=\"title\" type=\"VARCHAR\" size=\"255\" 
defaultValue=\"N/A\" required=\"true\"/>\n"+
-        "    <column name=\"issue_date\" type=\"DATE\" required=\"false\"/>\n"+
-        "    <foreign-key foreignTable=\"author\">\n"+
-        "      <reference local=\"author_id\" foreign=\"author_id\"/>\n"+
-        "    </foreign-key>\n"+
-        "    <index name=\"book_isbn\">\n"+
-        "      <index-column name=\"isbn\"/>\n"+
-        "    </index>\n"+
-        "  </table>\n"+
-        "</database>";
-
-    /** The test data. */
-    private static final String TEST_DATA =
-        "<data>\n"+
-        "  <author author_id=\"1\" name=\"Ernest Hemingway\"/>\n"+
-        "  <author author_id=\"2\" name=\"William Shakespeare\"/>\n"+
-        "  <book book_id=\"1\" author_id=\"1\">\n"+
-        "    <isbn>0684830493</isbn>\n"+
-        "    <title>Old Man And The Sea</title>\n"+
-        "    <issue_date>1952</issue_date>\n"+
-        "  </book>\n"+
-        "  <book book_id=\"2\" author_id=\"2\">\n"+
-        "    <isbn>0198321465</isbn>\n"+
-        "    <title>Macbeth</title>\n"+
-        "    <issue_date>1606</issue_date>\n"+
-        "  </book>\n"+
-        "  <book book_id=\"3\" author_id=\"2\">\n"+
-        "    <isbn>0140707026</isbn>\n"+
-        "    <title>A Midsummer Night's Dream</title>\n"+
-        "    <issue_date>1595</issue_date>\n"+
-        "  </book>\n"+
-        "</data>";
-
     /**
      * Tests reading the data from XML.
      */
     public void testRead() throws Exception
     {
+        final String testSchemaXml = 
+            "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"+
+            "<database name=\"bookstore\">\n"+
+            "  <table name=\"author\">\n"+
+            "    <column name=\"author_id\" type=\"INTEGER\" 
primaryKey=\"true\" required=\"true\"/>\n"+
+            "    <column name=\"name\" type=\"VARCHAR\" size=\"50\" 
required=\"true\"/>\n"+
+            "    <column name=\"organisation\" type=\"VARCHAR\" size=\"50\" 
required=\"false\"/>\n"+
+            "  </table>\n"+
+            "  <table name=\"book\">\n"+
+            "    <column name=\"book_id\" type=\"INTEGER\" required=\"true\" 
primaryKey=\"true\" autoIncrement=\"true\"/>\n"+
+            "    <column name=\"isbn\" type=\"VARCHAR\" size=\"15\" 
required=\"true\"/>\n"+
+            "    <column name=\"author_id\" type=\"INTEGER\" 
required=\"true\"/>\n"+
+            "    <column name=\"title\" type=\"VARCHAR\" size=\"255\" 
defaultValue=\"N/A\" required=\"true\"/>\n"+
+            "    <column name=\"issue_date\" type=\"DATE\" 
required=\"false\"/>\n"+
+            "    <foreign-key foreignTable=\"author\">\n"+
+            "      <reference local=\"author_id\" foreign=\"author_id\"/>\n"+
+            "    </foreign-key>\n"+
+            "    <index name=\"book_isbn\">\n"+
+            "      <index-column name=\"isbn\"/>\n"+
+            "    </index>\n"+
+            "  </table>\n"+
+            "</database>";
+        final String testDataXml =
+            "<data>\n"+
+            "  <author author_id=\"1\" name=\"Ernest Hemingway\"/>\n"+
+            "  <author author_id=\"2\" name=\"William Shakespeare\"/>\n"+
+            "  <book book_id=\"1\" author_id=\"1\">\n"+
+            "    <isbn>0684830493</isbn>\n"+
+            "    <title>Old Man And The Sea</title>\n"+
+            "    <issue_date>1952</issue_date>\n"+
+            "  </book>\n"+
+            "  <book book_id=\"2\" author_id=\"2\">\n"+
+            "    <isbn>0198321465</isbn>\n"+
+            "    <title>Macbeth</title>\n"+
+            "    <issue_date>1606</issue_date>\n"+
+            "  </book>\n"+
+            "  <book book_id=\"3\" author_id=\"2\">\n"+
+            "    <isbn>0140707026</isbn>\n"+
+            "    <title>A Midsummer Night's Dream</title>\n"+
+            "    <issue_date>1595</issue_date>\n"+
+            "  </book>\n"+
+            "</data>";
+
         DatabaseIO modelReader = new DatabaseIO();
 
         modelReader.setUseInternalDtd(true);
         modelReader.setValidateXml(false);
         
-        Database        model       = modelReader.read(new 
StringReader(TEST_SCHEMA));
+        Database        model       = modelReader.read(new 
StringReader(testSchemaXml));
         final ArrayList readObjects = new ArrayList();
         DataReader      dataReader  = new DataReader();
 
@@ -105,7 +104,7 @@
             public void end() throws DataSinkException
             {}
         });
-        dataReader.parse(new StringReader(TEST_DATA));
+        dataReader.parse(new StringReader(testDataXml));
 
         assertEquals(5, readObjects.size());
 
@@ -163,5 +162,68 @@
                      obj5.get("title").toString());
         assertEquals("1595-01-01",
                      obj5.get("issue_date").toString());    // parsed as a 
java.sql.Date
+    }
+
+    /**
+     * Tests special characters in the data XML (for DDLUTILS-63).
+     */
+    public void testSpecialCharacters() throws Exception
+    {
+        final String testSchemaXml = 
+            "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"+
+            "<database 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.setUseInternalDtd(true);
+        modelIO.setValidateXml(false);
+        
+        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));
+
+        bean.set("id", new Integer(1));
+        bean.set("value", testedValue);
+        dataWriter.writeDocumentStart();
+        dataWriter.write(bean);
+        dataWriter.writeDocumentEnd();
+
+        String dataXml = output.toString();
+
+        final ArrayList readObjects = new ArrayList();
+        DataReader      dataReader  = new DataReader();
+
+        dataReader.setModel(model);
+        dataReader.setSink(new DataSink() {
+            public void start() throws DataSinkException
+            {}
+
+            public void addBean(DynaBean bean) throws DataSinkException
+            {
+                readObjects.add(bean);
+            }
+
+            public void end() throws DataSinkException
+            {}
+        });
+        dataReader.parse(new StringReader(dataXml));
+
+        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());
     }
 }


Reply via email to