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());
}
}