Return-Path: Delivered-To: apmail-db-ddlutils-dev-archive@www.apache.org Received: (qmail 13637 invoked from network); 10 Oct 2006 20:30:09 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur.apache.org with SMTP; 10 Oct 2006 20:30:09 -0000 Received: (qmail 66546 invoked by uid 500); 10 Oct 2006 20:30:04 -0000 Delivered-To: apmail-db-ddlutils-dev-archive@db.apache.org Received: (qmail 66520 invoked by uid 500); 10 Oct 2006 20:30:04 -0000 Mailing-List: contact ddlutils-dev-help@db.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: ddlutils-dev@db.apache.org Delivered-To: mailing list ddlutils-dev@db.apache.org Received: (qmail 66509 invoked by uid 500); 10 Oct 2006 20:30:03 -0000 Delivered-To: apmail-db-ddlutils-commits@db.apache.org Received: (qmail 66506 invoked by uid 99); 10 Oct 2006 20:30:03 -0000 Received: from asf.osuosl.org (HELO asf.osuosl.org) (140.211.166.49) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 10 Oct 2006 13:30:03 -0700 X-ASF-Spam-Status: No, hits=-9.4 required=10.0 tests=ALL_TRUSTED,NO_REAL_NAME X-Spam-Check-By: apache.org Received-SPF: pass (asf.osuosl.org: local policy) Received: from [140.211.166.113] (HELO eris.apache.org) (140.211.166.113) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 10 Oct 2006 13:30:02 -0700 Received: by eris.apache.org (Postfix, from userid 65534) id 2700B1A981A; Tue, 10 Oct 2006 13:29:42 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r462544 - in /db/ddlutils/trunk: ./ lib/ src/java/org/apache/ddlutils/io/ src/test/org/apache/ddlutils/ src/test/org/apache/ddlutils/io/ Date: Tue, 10 Oct 2006 20:29:41 -0000 To: ddlutils-commits@db.apache.org From: tomdz@apache.org X-Mailer: svnmailer-1.1.0 Message-Id: <20061010202942.2700B1A981A@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N 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 @@ - + 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 true 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 true 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 @@ /** * {@inheritDoc} */ + 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; + } + } + } + + /** + * {@inheritDoc} + */ + public void end() throws Exception + { + _usesBase64 = false; + } + + /** + * {@inheritDoc} + */ 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 {@link org.apache.ddlutils.io.DataReader} class. + * Tests the {@link org.apache.ddlutils.io.DataReader} and {@link 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 = - "\n"+ - "\n"+ - " \n"+ - " \n"+ - " \n"+ - " \n"+ - "
\n"+ - " \n"+ - " \n"+ - " \n"+ - " \n"+ - " \n"+ - " \n"+ - " \n"+ - " \n"+ - " \n"+ - " \n"+ - " \n"+ - " \n"+ - "
\n"+ - "
"; - - /** The test data. */ - private static final String TEST_DATA = - "\n"+ - " \n"+ - " \n"+ - " \n"+ - " 0684830493\n"+ - " Old Man And The Sea\n"+ - " 1952\n"+ - " \n"+ - " \n"+ - " 0198321465\n"+ - " Macbeth\n"+ - " 1606\n"+ - " \n"+ - " \n"+ - " 0140707026\n"+ - " A Midsummer Night's Dream\n"+ - " 1595\n"+ - " \n"+ - ""; - /** * Tests reading the data from XML. */ public void testRead() throws Exception { + final String testSchemaXml = + "\n"+ + "\n"+ + " \n"+ + " \n"+ + " \n"+ + " \n"+ + "
\n"+ + " \n"+ + " \n"+ + " \n"+ + " \n"+ + " \n"+ + " \n"+ + " \n"+ + " \n"+ + " \n"+ + " \n"+ + " \n"+ + " \n"+ + "
\n"+ + "
"; + final String testDataXml = + "\n"+ + " \n"+ + " \n"+ + " \n"+ + " 0684830493\n"+ + " Old Man And The Sea\n"+ + " 1952\n"+ + " \n"+ + " \n"+ + " 0198321465\n"+ + " Macbeth\n"+ + " 1606\n"+ + " \n"+ + " \n"+ + " 0140707026\n"+ + " A Midsummer Night's Dream\n"+ + " 1595\n"+ + " \n"+ + ""; + 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 = + "\n"+ + "\n"+ + " \n"+ + " \n"+ + " \n"+ + "
\n"+ + "
"; + 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()); } }