You are viewing a plain text version of this content. The canonical link for it is here.
Posted to ddlutils-dev@db.apache.org by to...@apache.org on 2011/05/02 07:41:14 UTC
svn commit: r1098483 [1/2] - in /db/ddlutils/trunk/src:
main/java/org/apache/ddlutils/dynabean/ main/java/org/apache/ddlutils/io/
main/java/org/apache/ddlutils/util/ test/java/org/apache/ddlutils/io/
test/java/org/apache/ddlutils/util/
Author: tomdz
Date: Mon May 2 05:41:14 2011
New Revision: 1098483
URL: http://svn.apache.org/viewvc?rev=1098483&view=rev
Log:
Fix for DDLUTILS-245: writeDataToFile produce broken XML
Added:
db/ddlutils/trunk/src/main/java/org/apache/ddlutils/io/ColumnXmlWriter.java
db/ddlutils/trunk/src/main/java/org/apache/ddlutils/io/ModelXmlWriter.java
db/ddlutils/trunk/src/main/java/org/apache/ddlutils/io/TableXmlWriter.java
db/ddlutils/trunk/src/test/java/org/apache/ddlutils/util/
db/ddlutils/trunk/src/test/java/org/apache/ddlutils/util/DatabaseTestHelper.java
- copied unchanged from r1002941, db/ddlutils/trunk/src/main/java/org/apache/ddlutils/util/DatabaseTestHelper.java
Removed:
db/ddlutils/trunk/src/main/java/org/apache/ddlutils/util/DatabaseTestHelper.java
Modified:
db/ddlutils/trunk/src/main/java/org/apache/ddlutils/dynabean/SqlDynaBean.java
db/ddlutils/trunk/src/main/java/org/apache/ddlutils/io/DataReader.java
db/ddlutils/trunk/src/main/java/org/apache/ddlutils/io/DataWriter.java
db/ddlutils/trunk/src/main/java/org/apache/ddlutils/io/PrettyPrintingXmlWriter.java
db/ddlutils/trunk/src/main/java/org/apache/ddlutils/io/XMLUtils.java
db/ddlutils/trunk/src/test/java/org/apache/ddlutils/io/TestDataReaderAndWriter.java
Modified: db/ddlutils/trunk/src/main/java/org/apache/ddlutils/dynabean/SqlDynaBean.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/main/java/org/apache/ddlutils/dynabean/SqlDynaBean.java?rev=1098483&r1=1098482&r2=1098483&view=diff
==============================================================================
--- db/ddlutils/trunk/src/main/java/org/apache/ddlutils/dynabean/SqlDynaBean.java (original)
+++ db/ddlutils/trunk/src/main/java/org/apache/ddlutils/dynabean/SqlDynaBean.java Mon May 2 05:41:14 2011
@@ -67,4 +67,49 @@ public class SqlDynaBean extends BasicDy
}
return result.toString();
}
+
+ /**
+ * {@inheritDoc}
+ */
+ public int hashCode()
+ {
+ return toString().hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean equals(Object obj)
+ {
+ if (obj instanceof SqlDynaBean)
+ {
+ SqlDynaBean other = (SqlDynaBean)obj;
+ DynaClass dynaClass = getDynaClass();
+
+ if (dynaClass.equals(other.getDynaClass()))
+ {
+ DynaProperty[] props = dynaClass.getDynaProperties();
+
+ for (int idx = 0; idx < props.length; idx++)
+ {
+ Object value = get(props[idx].getName());
+ Object otherValue = other.get(props[idx].getName());
+
+ if (value == null)
+ {
+ if (otherValue != null)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return value.equals(otherValue);
+ }
+ }
+ return true;
+ }
+ }
+ return false;
+ }
}
Added: db/ddlutils/trunk/src/main/java/org/apache/ddlutils/io/ColumnXmlWriter.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/main/java/org/apache/ddlutils/io/ColumnXmlWriter.java?rev=1098483&view=auto
==============================================================================
--- db/ddlutils/trunk/src/main/java/org/apache/ddlutils/io/ColumnXmlWriter.java (added)
+++ db/ddlutils/trunk/src/main/java/org/apache/ddlutils/io/ColumnXmlWriter.java Mon May 2 05:41:14 2011
@@ -0,0 +1,176 @@
+package org.apache.ddlutils.io;
+
+/*
+ * 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.
+ */
+
+import org.apache.ddlutils.model.Column;
+
+/**
+ * Helper class for writing columns to XML.
+ */
+public class ColumnXmlWriter extends ModelXmlWriter
+{
+ private final int AS_TABLE_ATTRIBUTE = 0;
+ private final int AS_SUBTAG = 1;
+ private final int AS_COLUMN_ATTRIBUTE = 2;
+ private final int AS_VALUE = 3;
+
+ private final String columnName;
+ private final String columnValue;
+ private final boolean nameBase64Encoded;
+ private final boolean valueBase64Encoded;
+ private final int columnFormattingMethod;
+
+ /**
+ * Creates a new column writer.
+ *
+ * @param column The column, cannot be null
+ * @param value The value, cannot be null
+ */
+ public ColumnXmlWriter(Column column, String value)
+ {
+ /*
+ * - attribute "column name"="column value" in the parent's (table) element
+ * iff the column name is a valid attribute name and is not "table-name" and not "column",
+ * and the value is a valid attribute value not longer than 255 characters
+ * - otherwise, writes a sub-element <column> with an attribute column-name that contains the name
+ * of the column, and the body of that sub-element contains the column value,
+ * iff the column name is a valid attribute value not longer than 255 characters. If the column
+ * value contains illegal characters, then the column sub element will have a "base64" attribute
+ * with the value "true" and the value will be base64 encoded
+ * - otherwise writes a sub-element <column> with a sub-element <column-name> whose
+ * body is the name of the column, and another sub-element <column-value> whose body contains
+ * the column value. If either the column name or value contain illegal characters, then the
+ * corresponding sub element will have a "base64" attribute with the value "true" and its body will
+ * be base64 encoded.
+ */
+ if (XMLUtils.hasIllegalXMLCharacters(value))
+ {
+ columnValue = XMLUtils.base64Encode(value);
+ valueBase64Encoded = true;
+ }
+ else
+ {
+ columnValue = value;
+ valueBase64Encoded = false;
+ }
+
+ if (XMLUtils.hasIllegalXMLCharacters(column.getName())) {
+ columnName = XMLUtils.base64Encode(column.getName());
+ nameBase64Encoded = true;
+ columnFormattingMethod = AS_VALUE;
+ }
+ else
+ {
+ columnName = column.getName();
+ nameBase64Encoded = false;
+ if (columnName.length() > XMLUtils.MAX_NAME_LENGTH)
+ {
+ columnFormattingMethod = AS_VALUE;
+ }
+ else if ("table-name".equals(columnName) ||
+ "column".equals(columnName) ||
+ DatabaseIO.BASE64_ATTR_NAME.equals(columnName) ||
+ !XMLUtils.isWellFormedXMLName(columnName))
+ {
+ columnFormattingMethod = AS_COLUMN_ATTRIBUTE;
+ }
+ else if (valueBase64Encoded || (value.length() > XMLUtils.MAX_ATTRIBUTE_LENGTH))
+ {
+ columnFormattingMethod = AS_SUBTAG;
+ }
+ else
+ {
+ columnFormattingMethod = AS_TABLE_ATTRIBUTE;
+ }
+ }
+ }
+
+ /**
+ * Writes the column data as an attribute of the parent element if possible.
+ * Does nothing if the column name or value cannot be used in an attribute.
+ *
+ * @param writer The writer to write to
+ * @return <code>true</code> if something was written
+ */
+ public boolean writeAttribute(DataWriter writer)
+ {
+ if (columnFormattingMethod == AS_TABLE_ATTRIBUTE)
+ {
+ writer.writeAttribute(null, columnName, columnValue);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Writes any sub elements necessary for the column. If no sub elements
+ * are required, then this method does nothing.
+ *
+ * @param writer The writer to write to
+ * @return <code>true</code> if something was written
+ */
+ public boolean writeSubElement(DataWriter writer)
+ {
+ if (columnFormattingMethod != AS_TABLE_ATTRIBUTE)
+ {
+ writer.printlnIfPrettyPrinting();
+ writer.indentIfPrettyPrinting(2);
+ if (columnFormattingMethod == AS_SUBTAG)
+ {
+ writer.writeElementStart(null, columnName);
+ writeText(writer, columnValue, valueBase64Encoded);
+ }
+ else
+ {
+ writer.writeElementStart(null, "column");
+ if (columnFormattingMethod == AS_COLUMN_ATTRIBUTE)
+ {
+ writer.writeAttribute(null, "column-name", columnName);
+ writeText(writer, columnValue, valueBase64Encoded);
+ }
+ else if (columnFormattingMethod == AS_VALUE)
+ {
+ writer.printlnIfPrettyPrinting();
+ writer.indentIfPrettyPrinting(3);
+ writer.writeElementStart(null, "column-name");
+ writeText(writer, columnName, nameBase64Encoded);
+ writer.writeElementEnd();
+
+ writer.printlnIfPrettyPrinting();
+ writer.indentIfPrettyPrinting(3);
+ writer.writeElementStart(null, "column-value");
+ writeText(writer, columnValue, valueBase64Encoded);
+ writer.writeElementEnd();
+ writer.printlnIfPrettyPrinting();
+ writer.indentIfPrettyPrinting(2);
+ }
+ }
+ writer.writeElementEnd();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+}
Modified: db/ddlutils/trunk/src/main/java/org/apache/ddlutils/io/DataReader.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/main/java/org/apache/ddlutils/io/DataReader.java?rev=1098483&r1=1098482&r2=1098483&view=diff
==============================================================================
--- db/ddlutils/trunk/src/main/java/org/apache/ddlutils/io/DataReader.java (original)
+++ db/ddlutils/trunk/src/main/java/org/apache/ddlutils/io/DataReader.java Mon May 2 05:41:14 2011
@@ -27,8 +27,11 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.lang.reflect.InvocationTargetException;
+import java.util.HashMap;
+import java.util.Map;
import javax.xml.namespace.QName;
+import javax.xml.stream.Location;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
@@ -311,48 +314,62 @@ public class DataReader
*/
private void readBean(XMLStreamReader xmlReader) throws XMLStreamException, DdlUtilsXMLException
{
- QName elemQName = xmlReader.getName();
- Table table = _model.findTable(elemQName.getLocalPart(), isCaseSensitive());
+ QName elemQName = xmlReader.getName();
+ Location location = xmlReader.getLocation();
+ Map attributes = new HashMap();
+ String tableName = null;
+
+ for (int idx = 0; idx < xmlReader.getAttributeCount(); idx++)
+ {
+ QName attrQName = xmlReader.getAttributeName(idx);
+
+ attributes.put(isCaseSensitive() ? attrQName.getLocalPart() : attrQName.getLocalPart().toLowerCase(),
+ xmlReader.getAttributeValue(idx));
+ }
+ readColumnSubElements(xmlReader, attributes);
+
+ if ("table".equals(elemQName.getLocalPart()))
+ {
+ tableName = (String)attributes.get("table-name");
+ }
+ else
+ {
+ tableName = elemQName.getLocalPart();
+ }
+
+ Table table = _model.findTable(tableName, isCaseSensitive());
if (table == null)
{
- _log.warn("Data XML contains an element " + elemQName + " at location " + xmlReader.getLocation() +
+ _log.warn("Data XML contains an element " + elemQName + " at location " + location +
" but there is no table defined with this name. This element will be ignored.");
- readOverElement(xmlReader);
}
else
{
DynaBean bean = _model.createDynaBeanFor(table);
-
- for (int idx = 0; idx < xmlReader.getAttributeCount(); idx++)
+
+ for (int idx = 0; idx < table.getColumnCount(); idx++)
{
- QName attrQName = xmlReader.getAttributeName(idx);
- Column column = table.findColumn(attrQName.getLocalPart(), isCaseSensitive());
+ Column column = table.getColumn(idx);
+ String value = (String)attributes.get(isCaseSensitive() ? column.getName() : column.getName().toLowerCase());
- if (column == null)
+ if (value != null)
{
- _log.warn("Data XML contains an attribute " + attrQName + " at location " + xmlReader.getLocation() +
- " but there is no column defined in table " + table.getName() + " with this name. This attribute will be ignored.");
- }
- else
- {
- setColumnValue(bean, table, column, xmlReader.getAttributeValue(idx));
+ setColumnValue(bean, table, column, value);
}
}
- readColumnSubElements(xmlReader, bean, table);
getSink().addBean(bean);
consumeRestOfElement(xmlReader);
}
}
/**
- * Reads all column sub elements that match the columns specified by the given table object from the xml reader into the given bean.
+ * Reads all relevant sub elements that match the columns specified by the given table object from the xml reader into the given bean.
*
* @param xmlReader The reader
- * @param bean The bean to fill
- * @param table The table definition
+ * @param data Where to store the values
*/
- private void readColumnSubElements(XMLStreamReader xmlReader, DynaBean bean, Table table) throws XMLStreamException, DdlUtilsXMLException
+ private void readColumnSubElements(XMLStreamReader xmlReader, Map data) throws XMLStreamException, DdlUtilsXMLException
{
int eventType = XMLStreamReader.START_ELEMENT;
@@ -361,7 +378,7 @@ public class DataReader
eventType = xmlReader.next();
if (eventType == XMLStreamReader.START_ELEMENT)
{
- readColumnSubElement(xmlReader, bean, table);
+ readColumnSubElement(xmlReader, data);
}
}
}
@@ -370,48 +387,128 @@ public class DataReader
* Reads the next column sub element that matches a column specified by the given table object from the xml reader into the given bean.
*
* @param xmlReader The reader
- * @param bean The bean to fill
- * @param table The table definition
+ * @param data Where to store the values
*/
- private void readColumnSubElement(XMLStreamReader xmlReader, DynaBean bean, Table table) throws XMLStreamException, DdlUtilsXMLException
+ private void readColumnSubElement(XMLStreamReader xmlReader, Map data) throws XMLStreamException, DdlUtilsXMLException
{
QName elemQName = xmlReader.getName();
+ Map attributes = new HashMap();
boolean usesBase64 = false;
for (int idx = 0; idx < xmlReader.getAttributeCount(); idx++)
{
- QName attrQName = xmlReader.getAttributeName(idx);
+ QName attrQName = xmlReader.getAttributeName(idx);
+ String value = xmlReader.getAttributeValue(idx);
- if (DatabaseIO.BASE64_ATTR_NAME.equals(attrQName.getLocalPart()) &&
- "true".equalsIgnoreCase(xmlReader.getAttributeValue(idx)))
+ if (DatabaseIO.BASE64_ATTR_NAME.equals(attrQName.getLocalPart()))
{
- usesBase64 = true;
- break;
+ if ("true".equalsIgnoreCase(value))
+ {
+ usesBase64 = true;
+ }
+ }
+ else
+ {
+ attributes.put(attrQName.getLocalPart(), value);
}
}
- Column column = table.findColumn(elemQName.getLocalPart(), isCaseSensitive());
+ int eventType = XMLStreamReader.START_ELEMENT;
+ StringBuffer content = new StringBuffer();
- if (column == null)
+ while (eventType != XMLStreamReader.END_ELEMENT)
{
- _log.warn("Data XML contains an element " + elemQName + " at location " + xmlReader.getLocation() +
- " but there is no column defined in table " + table.getName() + " with this name. This element will be ignored.");
+ eventType = xmlReader.next();
+ if (eventType == XMLStreamReader.START_ELEMENT)
+ {
+ readColumnDataSubElement(xmlReader, attributes);
+ }
+ else if ((eventType == XMLStreamReader.CHARACTERS) ||
+ (eventType == XMLStreamReader.CDATA) ||
+ (eventType == XMLStreamReader.SPACE) ||
+ (eventType == XMLStreamReader.ENTITY_REFERENCE))
+ {
+ content.append(xmlReader.getText());
+ }
}
- else
+
+ String value = content.toString().trim();
+
+ if (usesBase64)
{
- String value = xmlReader.getElementText();
+ value = new String(Base64.decodeBase64(value.getBytes()));
+ }
- if (value != null)
+ String name = elemQName.getLocalPart();
+
+ if ("table-name".equals(name))
+ {
+ data.put("table-name", value);
+ }
+ else
+ {
+ if ("column".equals(name))
{
- value = value.trim();
+ name = (String)attributes.get("column-name");
+ }
+ if (attributes.containsKey("column-value"))
+ {
+ value = (String)attributes.get("column-value");
+ }
+ data.put(name, value);
+ }
+ consumeRestOfElement(xmlReader);
+ }
- if (usesBase64)
+
+ /**
+ * Reads the next column-name or column-value sub element.
+ *
+ * @param xmlReader The reader
+ * @param data Where to store the values
+ */
+ private void readColumnDataSubElement(XMLStreamReader xmlReader, Map data) throws XMLStreamException, DdlUtilsXMLException
+ {
+ QName elemQName = xmlReader.getName();
+ boolean usesBase64 = false;
+
+ for (int idx = 0; idx < xmlReader.getAttributeCount(); idx++)
+ {
+ QName attrQName = xmlReader.getAttributeName(idx);
+ String value = xmlReader.getAttributeValue(idx);
+
+ if (DatabaseIO.BASE64_ATTR_NAME.equals(attrQName.getLocalPart()))
+ {
+ if ("true".equalsIgnoreCase(value))
{
- value = new String(Base64.decodeBase64(value.getBytes()));
+ usesBase64 = true;
}
- setColumnValue(bean, table, column, value);
+ break;
}
}
+
+ String value = xmlReader.getElementText();
+
+ if (value != null)
+ {
+ value = value.toString().trim();
+
+ if (usesBase64)
+ {
+ value = new String(Base64.decodeBase64(value.getBytes()));
+ }
+ }
+
+ String name = elemQName.getLocalPart();
+
+ if ("column-name".equals(name))
+ {
+ data.put("column-name", value);
+ }
+ else if ("column-value".equals(name))
+ {
+ data.put("column-value", value);
+ }
consumeRestOfElement(xmlReader);
}
@@ -445,33 +542,6 @@ public class DataReader
throw new DdlUtilsXMLException("Could not set bean property for column " + column.getName(), ex);
}
}
-
- // TODO: move these two into a helper class:
-
- /**
- * Reads over the current element. This assumes that the current XML stream event type is
- * START_ELEMENT.
- *
- * @param reader The xml reader
- */
- private void readOverElement(XMLStreamReader reader) throws XMLStreamException
- {
- int depth = 1;
-
- while (depth > 0)
- {
- int eventType = reader.next();
-
- if (eventType == XMLStreamReader.START_ELEMENT)
- {
- depth++;
- }
- else if (eventType == XMLStreamReader.END_ELEMENT)
- {
- depth--;
- }
- }
- }
/**
* Consumes the rest of the current element. This assumes that the current XML stream
Modified: db/ddlutils/trunk/src/main/java/org/apache/ddlutils/io/DataWriter.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/main/java/org/apache/ddlutils/io/DataWriter.java?rev=1098483&r1=1098482&r2=1098483&view=diff
==============================================================================
--- db/ddlutils/trunk/src/main/java/org/apache/ddlutils/io/DataWriter.java (original)
+++ db/ddlutils/trunk/src/main/java/org/apache/ddlutils/io/DataWriter.java Mon May 2 05:41:14 2011
@@ -20,39 +20,25 @@ package org.apache.ddlutils.io;
*/
import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
-import java.util.Map;
-
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;
import org.apache.ddlutils.dynabean.SqlDynaClass;
-import org.apache.ddlutils.io.converters.ConversionException;
import org.apache.ddlutils.io.converters.SqlTypeConverter;
import org.apache.ddlutils.model.Column;
import org.apache.ddlutils.model.Table;
/**
* Writes dyna beans matching a specified database model into an XML file.
- *
- * TODO: Make names (tables, columns) XML-compliant
- *
- * @version $Revision: 289996 $
*/
public class DataWriter extends PrettyPrintingXmlWriter
{
- /** String values with a size not bigger than this value will be written to attributes;
- if their size is longer, then a sub element is generated instead. */
- private static final int MAX_ATTRIBUTE_LENGTH = 255;
-
/** Our log. */
private final Log _log = LogFactory.getLog(DataWriter.class);
@@ -139,162 +125,36 @@ public class DataWriter extends PrettyPr
*/
public void write(SqlDynaBean bean) throws DataWriterException
{
- SqlDynaClass dynaClass = (SqlDynaClass)bean.getDynaClass();
- Table table = dynaClass.getTable();
- HashMap subElements = new HashMap();
+ SqlDynaClass dynaClass = (SqlDynaClass)bean.getDynaClass();
+ Table table = dynaClass.getTable();
+ TableXmlWriter tableWriter = new TableXmlWriter(table);
+ List columnWriters = new ArrayList();
- try
+ for (int idx = 0; idx < table.getColumnCount(); idx++)
{
- indentIfPrettyPrinting(1);
- writeElementStart(null, table.getName());
- for (int idx = 0; idx < table.getColumnCount(); idx++)
- {
- Column column = table.getColumn(idx);
- Object value = bean.get(column.getName());
- SqlTypeConverter converter = _converterConf.getRegisteredConverter(table, column);
- String valueAsText = null;
+ Column column = table.getColumn(idx);
+ Object value = bean.get(column.getName());
+ SqlTypeConverter converter = _converterConf.getRegisteredConverter(table, column);
+ String valueAsText = null;
- if (converter == null)
- {
- if (value != null)
- {
- valueAsText = value.toString();
- }
- }
- else
- {
- valueAsText = converter.convertToString(value, column.getTypeCode());
- }
- if (valueAsText != null)
- {
- // 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) || analyzeText(valueAsText, null))
- {
- // we defer writing the sub elements
- subElements.put(column.getName(), valueAsText);
- }
- else
- {
- writeAttribute(null, column.getName(), valueAsText);
- }
- }
- }
- if (!subElements.isEmpty())
+ if (converter == null)
{
- List cutPoints = new ArrayList();
-
- for (Iterator it = subElements.entrySet().iterator(); it.hasNext();)
+ if (value != null)
{
- Map.Entry entry = (Map.Entry)it.next();
- String content = entry.getValue().toString();
-
- printlnIfPrettyPrinting();
- indentIfPrettyPrinting(2);
- writeElementStart(null, entry.getKey().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
- // it would have been written as an attribute already), otherwise we check
- cutPoints.clear();
-
- boolean writeBase64Encoded = analyzeText(content, cutPoints);
-
- if (writeBase64Encoded)
- {
- writeAttribute(null, DatabaseIO.BASE64_ATTR_NAME, "true");
- try {
- writeCData(new String(Base64.encodeBase64(content.getBytes()), getEncoding()));
- }
- catch (UnsupportedEncodingException ex) {
- throw new DataWriterException(ex);
- }
- }
- else
- {
- if (cutPoints.isEmpty())
- {
- writeCData(content);
- }
- else
- {
- int lastPos = 0;
-
- for (Iterator cutPointIt = cutPoints.iterator(); cutPointIt.hasNext();)
- {
- int curPos = ((Integer)cutPointIt.next()).intValue();
-
- writeCData(content.substring(lastPos, curPos));
- lastPos = curPos;
- }
- if (lastPos < content.length())
- {
- writeCData(content.substring(lastPos));
- }
- }
- }
-
- writeElementEnd();
+ valueAsText = value.toString();
}
- printlnIfPrettyPrinting();
- indentIfPrettyPrinting(1);
}
- writeElementEnd();
- printlnIfPrettyPrinting();
- }
- catch (ConversionException ex)
- {
- throw new DataWriterException(ex);
- }
- }
-
- /**
- * Determines whether the given string contains special characters that cannot
- * be used in XML, and if not, finds the cut points where to split the text
- * when writing it in a CDATA section.
- *
- * @param text The text
- * @param cutPoints Will be filled with cut points to split the text when writing it
- * in a CDATA section (only if the method returns <code>false</code>)
- * @return <code>true</code> if the text contains special characters
- */
- private boolean analyzeText(String text, List cutPoints)
- {
- List tmpCutPoints = cutPoints == null ? null : new ArrayList();
- int numChars = text.length();
- int numFoundCDataEndChars = 0;
-
- for (int charPos = 0; charPos < numChars; charPos++)
- {
- char c = text.charAt(charPos);
-
- if ((c < 0x0020) && (c != '\n') && (c != '\r') && (c != '\t'))
+ else
{
- return true;
+ valueAsText = converter.convertToString(value, column.getTypeCode());
}
- else if (cutPoints != null)
+ if (valueAsText != null)
{
- if ((c == ']') && ((numFoundCDataEndChars == 0) || (numFoundCDataEndChars == 1)))
- {
- numFoundCDataEndChars++;
- }
- else if ((c == '>') && (numFoundCDataEndChars == 2))
- {
- // we have to split the CDATA right here before the '>' (see DDLUTILS-174)
- tmpCutPoints.add(new Integer(charPos));
- numFoundCDataEndChars = 0;
- }
- else
- {
- numFoundCDataEndChars = 0;
- }
+ columnWriters.add(new ColumnXmlWriter(column, valueAsText));
}
}
- if (cutPoints != null)
- {
- cutPoints.addAll(tmpCutPoints);
- }
- return false;
+
+ tableWriter.write(columnWriters, this);
}
/**
Added: db/ddlutils/trunk/src/main/java/org/apache/ddlutils/io/ModelXmlWriter.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/main/java/org/apache/ddlutils/io/ModelXmlWriter.java?rev=1098483&view=auto
==============================================================================
--- db/ddlutils/trunk/src/main/java/org/apache/ddlutils/io/ModelXmlWriter.java (added)
+++ db/ddlutils/trunk/src/main/java/org/apache/ddlutils/io/ModelXmlWriter.java Mon May 2 05:41:14 2011
@@ -0,0 +1,64 @@
+package org.apache.ddlutils.io;
+
+/*
+ * 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.
+ */
+
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Base class providing helper functions for writing model elements to XML.
+ */
+public abstract class ModelXmlWriter
+{
+ protected void writeText(DataWriter writer, String value, boolean isBase64Encoded)
+ {
+ if (isBase64Encoded)
+ {
+ writer.writeAttribute(null, "base64", "true");
+ writer.writeCharacters(value);
+ }
+ else
+ {
+ List cutPoints = XMLUtils.findCDataCutPoints(value);
+
+ // if the content contains special characters, we have to apply base64 encoding to it
+ if (cutPoints.isEmpty())
+ {
+ writer.writeCharacters(value);
+ }
+ else
+ {
+ int lastPos = 0;
+
+ for (Iterator cutPointIt = cutPoints.iterator(); cutPointIt.hasNext();)
+ {
+ int curPos = ((Integer)cutPointIt.next()).intValue();
+
+ writer.writeCData(value.substring(lastPos, curPos));
+ lastPos = curPos;
+ }
+ if (lastPos < value.length())
+ {
+ writer.writeCData(value.substring(lastPos));
+ }
+ }
+ }
+ }
+}
Modified: db/ddlutils/trunk/src/main/java/org/apache/ddlutils/io/PrettyPrintingXmlWriter.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/main/java/org/apache/ddlutils/io/PrettyPrintingXmlWriter.java?rev=1098483&r1=1098482&r2=1098483&view=diff
==============================================================================
--- db/ddlutils/trunk/src/main/java/org/apache/ddlutils/io/PrettyPrintingXmlWriter.java (original)
+++ db/ddlutils/trunk/src/main/java/org/apache/ddlutils/io/PrettyPrintingXmlWriter.java Mon May 2 05:41:14 2011
@@ -373,4 +373,24 @@ public class PrettyPrintingXmlWriter
}
}
}
+
+ /**
+ * Writes a text segment.
+ *
+ * @param data The data to write
+ */
+ public void writeCharacters(String data) throws DdlUtilsXMLException
+ {
+ if (data != null)
+ {
+ try
+ {
+ _writer.writeCharacters(data);
+ }
+ catch (XMLStreamException ex)
+ {
+ throwException(ex);
+ }
+ }
+ }
}
Added: db/ddlutils/trunk/src/main/java/org/apache/ddlutils/io/TableXmlWriter.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/main/java/org/apache/ddlutils/io/TableXmlWriter.java?rev=1098483&view=auto
==============================================================================
--- db/ddlutils/trunk/src/main/java/org/apache/ddlutils/io/TableXmlWriter.java (added)
+++ db/ddlutils/trunk/src/main/java/org/apache/ddlutils/io/TableXmlWriter.java Mon May 2 05:41:14 2011
@@ -0,0 +1,115 @@
+package org.apache.ddlutils.io;
+
+/*
+ * 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.
+ */
+
+import java.util.Iterator;
+import java.util.List;
+import org.apache.ddlutils.model.Table;
+
+/**
+ * Base interface for different strategies to write the XML for a data bean for a specific table.
+ */
+public class TableXmlWriter extends ModelXmlWriter
+{
+ private static final int AS_TAG_NAME = 0;
+ private static final int AS_ATTRIBUTE = 1;
+ private static final int AS_SUB_TAG = 2;
+
+ private final String tableName;
+ private final int formattingMethod;
+ private final boolean base64Encoded;
+
+ public TableXmlWriter(Table table)
+ {
+ if (XMLUtils.hasIllegalXMLCharacters(table.getName()))
+ {
+ tableName = XMLUtils.base64Encode(table.getName());
+ formattingMethod = AS_SUB_TAG;
+ base64Encoded = true;
+ }
+ else
+ {
+ tableName = table.getName();
+ base64Encoded = false;
+ if (tableName.length() > XMLUtils.MAX_NAME_LENGTH)
+ {
+ formattingMethod = AS_SUB_TAG;
+ }
+ else if ("table".equals(tableName) || !XMLUtils.isWellFormedXMLName(tableName))
+ {
+ formattingMethod = AS_ATTRIBUTE;
+ }
+ else
+ {
+ formattingMethod = AS_TAG_NAME;
+ }
+ }
+ }
+
+ /**
+ * Write the table data to XML to the given writer.
+ *
+ * @param columnXmlWriters A list of column xml writers for writing out the bean's values to XML
+ * @param writer The writer to write to
+ */
+ public void write(List columnXmlWriters, DataWriter writer)
+ {
+ writer.indentIfPrettyPrinting(1);
+ if (formattingMethod == AS_TAG_NAME)
+ {
+ writer.writeElementStart(null, tableName);
+ }
+ else
+ {
+ writer.writeElementStart(null, "table");
+ }
+ if (formattingMethod == AS_ATTRIBUTE)
+ {
+ writer.writeAttribute(null, "table-name", tableName);
+ }
+ for (Iterator it = columnXmlWriters.iterator(); it.hasNext();)
+ {
+ ((ColumnXmlWriter)it.next()).writeAttribute(writer);
+ }
+
+ boolean hasSubTags = false;
+
+ if (formattingMethod == AS_SUB_TAG)
+ {
+ writer.printlnIfPrettyPrinting();
+ writer.indentIfPrettyPrinting(2);
+ writer.writeElementStart(null, "table-name");
+ writeText(writer, tableName, base64Encoded);
+ writer.writeElementEnd();
+ hasSubTags = true;
+ }
+ for (Iterator it = columnXmlWriters.iterator(); it.hasNext();)
+ {
+ hasSubTags = ((ColumnXmlWriter)it.next()).writeSubElement(writer) || hasSubTags;
+ }
+ if (hasSubTags)
+ {
+ writer.printlnIfPrettyPrinting();
+ writer.indentIfPrettyPrinting(1);
+ }
+ writer.writeElementEnd();
+ writer.printlnIfPrettyPrinting();
+ }
+}
Modified: db/ddlutils/trunk/src/main/java/org/apache/ddlutils/io/XMLUtils.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/main/java/org/apache/ddlutils/io/XMLUtils.java?rev=1098483&r1=1098482&r2=1098483&view=diff
==============================================================================
--- db/ddlutils/trunk/src/main/java/org/apache/ddlutils/io/XMLUtils.java (original)
+++ db/ddlutils/trunk/src/main/java/org/apache/ddlutils/io/XMLUtils.java Mon May 2 05:41:14 2011
@@ -19,9 +19,14 @@ package org.apache.ddlutils.io;
* under the License.
*/
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.codec.binary.Base64;
+
/**
* <p>Contains basic utility methods for XML.</p>
- * This class is borrowed from <a href='http://commons.apache.org/betwixt/'>Apache Commons Betwixt</a>
+ * Parts of this class are borrowed from <a href='http://commons.apache.org/betwixt/'>Apache Commons Betwixt</a>
* whose class in turn is based on code in <a href='http://xerces.apache.org/xerces2-j/index.html'>Apache Xerces</a>.
* <p>The code for {@link #isWellFormedXMLName} is based on code in
* <code>org.apache.xerces.util.XMLChar</code>
@@ -34,10 +39,14 @@ package org.apache.ddlutils.io;
* @author Arnaud Le Hors, IBM
* @author Rahul Srivastava, Sun Microsystems Inc.
* @author Robert Burrell Donkin
- * @version $Revision: $
*/
public class XMLUtils
{
+ /** Maximum length of attribute values that we want to generate. */
+ public static final int MAX_ATTRIBUTE_LENGTH = 255;
+ /** Maximum length of a tag or attribute name that we want to generate. */
+ public static final int MAX_NAME_LENGTH = 255;
+
/** Name start character mask. */
private static final int MASK_NAME_START = 0x01;
/** Name character mask. */
@@ -295,4 +304,88 @@ public class XMLUtils
{
return (c < 0x10000) && ((CHARS[c] & MASK_NAME_START) != 0);
}
+
+ /**
+ * 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
+ */
+ public static boolean hasIllegalXMLCharacters(String text)
+ {
+ int numChars = text.length();
+
+ for (int charPos = 0; charPos < numChars; charPos++)
+ {
+ char c = text.charAt(charPos);
+
+ if ((c != 0x9) && (c != 0xA) && (c != 0xD) && ((c < 0x20) || (c > 0xD7FF)) && ((c < 0xE000) || (c > 0xFFFD)) && ((c < 0x10000) || (c > 0x10FFFF)))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Encodes the given value with Base64.
+ *
+ * @param value The value to encode
+ * @return The encoded value
+ */
+ public static String base64Encode(String value)
+ {
+ try
+ {
+ return value == null ? null : new String(Base64.encodeBase64(value.getBytes("UTF-8")), "UTF-8");
+ }
+ catch (UnsupportedEncodingException ex)
+ {
+ throw new IllegalStateException(ex);
+ }
+ }
+
+ /**
+ * Determines whether the given string contains special characters that cannot
+ * be used in XML, and if not, finds the cut points where to split the text
+ * when writing it in a CDATA section.
+ *
+ * @param text The text
+ * @return <code>null</code> if the text contains special characters, or the list of cut points otherwise
+ */
+ public static List findCDataCutPoints(String text)
+ {
+ List cutPoints = new ArrayList();
+ int numChars = text.length();
+ int numFoundCDataEndChars = 0;
+
+ for (int charPos = 0; charPos < numChars; charPos++)
+ {
+ char c = text.charAt(charPos);
+
+ if ((c != 0x9) && (c != 0xA) && (c != 0xD) && ((c < 0x20) || (c > 0xD7FF)) && ((c < 0xE000) || (c > 0xFFFD)) && ((c < 0x10000) || (c > 0x10FFFF)))
+ {
+ return null;
+ }
+ else
+ {
+ if ((c == ']') && ((numFoundCDataEndChars == 0) || (numFoundCDataEndChars == 1)))
+ {
+ numFoundCDataEndChars++;
+ }
+ else if ((c == '>') && (numFoundCDataEndChars == 2))
+ {
+ // we have to split the CDATA right here before the '>' (see DDLUTILS-174)
+ cutPoints.add(new Integer(charPos));
+ numFoundCDataEndChars = 0;
+ }
+ else
+ {
+ numFoundCDataEndChars = 0;
+ }
+ }
+ }
+ return cutPoints;
+ }
}