Fix for DDLUTILS-245: writeDataToFile produce broken XML
git-svn-id: https://svn.apache.org/repos/asf/db/ddlutils/trunk@1098483 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/main/java/org/apache/ddlutils/dynabean/SqlDynaBean.java b/src/main/java/org/apache/ddlutils/dynabean/SqlDynaBean.java
index 721a5e8..0cba20b 100644
--- a/src/main/java/org/apache/ddlutils/dynabean/SqlDynaBean.java
+++ b/src/main/java/org/apache/ddlutils/dynabean/SqlDynaBean.java
@@ -67,4 +67,49 @@
}
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;
+ }
}
diff --git a/src/main/java/org/apache/ddlutils/io/ColumnXmlWriter.java b/src/main/java/org/apache/ddlutils/io/ColumnXmlWriter.java
new file mode 100644
index 0000000..d3533b3
--- /dev/null
+++ b/src/main/java/org/apache/ddlutils/io/ColumnXmlWriter.java
@@ -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;
+ }
+ }
+}
diff --git a/src/main/java/org/apache/ddlutils/io/DataReader.java b/src/main/java/org/apache/ddlutils/io/DataReader.java
index 8bc7b87..8ebdd44 100644
--- a/src/main/java/org/apache/ddlutils/io/DataReader.java
+++ b/src/main/java/org/apache/ddlutils/io/DataReader.java
@@ -27,8 +27,11 @@
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 @@
*/
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++)
- {
- QName attrQName = xmlReader.getAttributeName(idx);
- Column column = table.findColumn(attrQName.getLocalPart(), isCaseSensitive());
- if (column == null)
+ for (int idx = 0; idx < table.getColumnCount(); idx++)
+ {
+ Column column = table.getColumn(idx);
+ String value = (String)attributes.get(isCaseSensitive() ? column.getName() : column.getName().toLowerCase());
+
+ 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 @@
eventType = xmlReader.next();
if (eventType == XMLStreamReader.START_ELEMENT)
{
- readColumnSubElement(xmlReader, bean, table);
+ readColumnSubElement(xmlReader, data);
}
}
}
@@ -370,48 +387,128 @@
* 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);
+ String value = xmlReader.getAttributeValue(idx);
+
+ if (DatabaseIO.BASE64_ATTR_NAME.equals(attrQName.getLocalPart()))
+ {
+ if ("true".equalsIgnoreCase(value))
+ {
+ usesBase64 = true;
+ }
+ }
+ else
+ {
+ attributes.put(attrQName.getLocalPart(), value);
+ }
+ }
+
+ int eventType = XMLStreamReader.START_ELEMENT;
+ StringBuffer content = new StringBuffer();
+
+ while (eventType != XMLStreamReader.END_ELEMENT)
+ {
+ 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());
+ }
+ }
+
+ String value = content.toString().trim();
+
+ if (usesBase64)
+ {
+ value = new String(Base64.decodeBase64(value.getBytes()));
+ }
+
+ String name = elemQName.getLocalPart();
+
+ if ("table-name".equals(name))
+ {
+ data.put("table-name", value);
+ }
+ else
+ {
+ if ("column".equals(name))
+ {
+ name = (String)attributes.get("column-name");
+ }
+ if (attributes.containsKey("column-value"))
+ {
+ value = (String)attributes.get("column-value");
+ }
+ data.put(name, value);
+ }
+ consumeRestOfElement(xmlReader);
+ }
+
+
+ /**
+ * 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);
+ 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;
+ if ("true".equalsIgnoreCase(value))
+ {
+ usesBase64 = true;
+ }
break;
}
}
- Column column = table.findColumn(elemQName.getLocalPart(), isCaseSensitive());
+ String value = xmlReader.getElementText();
- if (column == null)
+ if (value != null)
{
- _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.");
- }
- else
- {
- String value = xmlReader.getElementText();
-
- if (value != null)
+ value = value.toString().trim();
+
+ if (usesBase64)
{
- value = value.trim();
-
- if (usesBase64)
- {
- value = new String(Base64.decodeBase64(value.getBytes()));
- }
- setColumnValue(bean, table, column, value);
+ 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 @@
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
diff --git a/src/main/java/org/apache/ddlutils/io/DataWriter.java b/src/main/java/org/apache/ddlutils/io/DataWriter.java
index 902138f..d6b38ab 100644
--- a/src/main/java/org/apache/ddlutils/io/DataWriter.java
+++ b/src/main/java/org/apache/ddlutils/io/DataWriter.java
@@ -20,39 +20,25 @@
*/
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 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 (converter == null)
+ {
+ if (value != 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);
- }
+ valueAsText = value.toString();
}
}
- if (!subElements.isEmpty())
+ else
{
- List cutPoints = new ArrayList();
-
- for (Iterator it = subElements.entrySet().iterator(); it.hasNext();)
- {
- 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();
- }
- printlnIfPrettyPrinting();
- indentIfPrettyPrinting(1);
+ valueAsText = converter.convertToString(value, column.getTypeCode());
}
- 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'))
+ if (valueAsText != null)
{
- return true;
- }
- else if (cutPoints != 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);
}
/**
diff --git a/src/main/java/org/apache/ddlutils/io/ModelXmlWriter.java b/src/main/java/org/apache/ddlutils/io/ModelXmlWriter.java
new file mode 100644
index 0000000..375aa2d
--- /dev/null
+++ b/src/main/java/org/apache/ddlutils/io/ModelXmlWriter.java
@@ -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));
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/org/apache/ddlutils/io/PrettyPrintingXmlWriter.java b/src/main/java/org/apache/ddlutils/io/PrettyPrintingXmlWriter.java
index df245c5..7d73c16 100644
--- a/src/main/java/org/apache/ddlutils/io/PrettyPrintingXmlWriter.java
+++ b/src/main/java/org/apache/ddlutils/io/PrettyPrintingXmlWriter.java
@@ -373,4 +373,24 @@
}
}
}
+
+ /**
+ * 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);
+ }
+ }
+ }
}
diff --git a/src/main/java/org/apache/ddlutils/io/TableXmlWriter.java b/src/main/java/org/apache/ddlutils/io/TableXmlWriter.java
new file mode 100644
index 0000000..42d345f
--- /dev/null
+++ b/src/main/java/org/apache/ddlutils/io/TableXmlWriter.java
@@ -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();
+ }
+}
diff --git a/src/main/java/org/apache/ddlutils/io/XMLUtils.java b/src/main/java/org/apache/ddlutils/io/XMLUtils.java
index a879aaf..b876473 100644
--- a/src/main/java/org/apache/ddlutils/io/XMLUtils.java
+++ b/src/main/java/org/apache/ddlutils/io/XMLUtils.java
@@ -19,9 +19,14 @@
* 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 @@
* @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 @@
{
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;
+ }
}
diff --git a/src/test/java/org/apache/ddlutils/io/TestDataReaderAndWriter.java b/src/test/java/org/apache/ddlutils/io/TestDataReaderAndWriter.java
index 982e9de..8e8b7d2 100644
--- a/src/test/java/org/apache/ddlutils/io/TestDataReaderAndWriter.java
+++ b/src/test/java/org/apache/ddlutils/io/TestDataReaderAndWriter.java
@@ -26,17 +26,18 @@
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.StringReader;
-import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.util.ArrayList;
-
+import java.util.List;
import junit.framework.TestCase;
-
import org.apache.commons.beanutils.DynaBean;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;
import org.apache.ddlutils.dynabean.SqlDynaBean;
+import org.apache.ddlutils.model.Column;
import org.apache.ddlutils.model.Database;
+import org.apache.ddlutils.model.Table;
/**
* Tests the {@link org.apache.ddlutils.io.DataReader} and {@link org.apache.ddlutils.io.DataWriter} classes.
@@ -85,11 +86,102 @@
}
/**
+ * Reads the given schema xml into a {@link Database} object.
+ *
+ * @param schemaXml The schema xml
+ * @return The database model object
+ */
+ private Database readModel(String schemaXml)
+ {
+ DatabaseIO modelIO = new DatabaseIO();
+
+ modelIO.setValidateXml(true);
+
+ return modelIO.read(new StringReader(schemaXml));
+ }
+
+ /**
+ * Writes the given dyna bean via a {@link DataWriter} and returns the raw xml output.
+ *
+ * @param model The database model to use
+ * @param bean The bean to write
+ * @param encoding The encoding in which to write the xml
+ * @return The xml output as raw bytes
+ */
+ private byte[] writeBean(Database model, SqlDynaBean bean, String encoding)
+ {
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ DataWriter dataWriter = new DataWriter(output, encoding);
+
+ dataWriter.writeDocumentStart();
+ dataWriter.write(bean);
+ dataWriter.writeDocumentEnd();
+
+ return output.toByteArray();
+ }
+
+ /**
+ * Uses a {@link DataReader} with default settings to read dyna beans from the given xml data.
+ *
+ * @param model The database model to use
+ * @param dataXml The raw xml data
+ * @return The read dyna beans
+ */
+ private List readBeans(Database model, byte[] dataXml)
+ {
+ ArrayList beans = new ArrayList();
+ DataReader dataReader = new DataReader();
+
+ dataReader.setModel(model);
+ dataReader.setSink(new TestDataSink(beans));
+ dataReader.read(new ByteArrayInputStream(dataXml));
+ return beans;
+ }
+
+ /**
+ * Uses a {@link DataReader} with default settings to read dyna beans from the given xml data.
+ *
+ * @param model The database model to use
+ * @param dataXml The xml data
+ * @return The read dyna beans
+ */
+ private List readBeans(Database model, String dataXml)
+ {
+ ArrayList beans = new ArrayList();
+ DataReader dataReader = new DataReader();
+
+ dataReader.setModel(model);
+ dataReader.setSink(new TestDataSink(beans));
+ dataReader.read(new StringReader(dataXml));
+ return beans;
+ }
+
+ /**
+ * Helper method to perform a test that writes a bean and then reads it back.
+ *
+ * @param model The database model to use
+ * @param bean The bean to write and read back
+ * @param encoding The encoding to use for the data xml
+ * @param expectedDataXml The expected xml generated for the bean
+ */
+ private void roundtripTest(Database model, SqlDynaBean bean, String encoding, String expectedDataXml) throws UnsupportedEncodingException
+ {
+ byte[] xmlData = writeBean(model, bean, encoding);
+
+ assertEquals(expectedDataXml, new String(xmlData, encoding));
+
+ List beans = readBeans(model, xmlData);
+
+ assertEquals(1, beans.size());
+ assertEquals(bean, beans.get(0));
+ }
+
+ /**
* Tests reading the data from XML.
*/
public void testRead() throws Exception
{
- final String testSchemaXml =
+ Database model = readModel(
"<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
"<database xmlns='" + DatabaseIO.DDLUTILS_NAMESPACE + "' name='bookstore'>\n"+
" <table name='author'>\n"+
@@ -110,8 +202,9 @@
" <index-column name='isbn'/>\n"+
" </index>\n"+
" </table>\n"+
- "</database>";
- final String testDataXml =
+ "</database>");
+ List beans = readBeans(
+ model,
"<data>\n"+
" <author author_id='1' name='Ernest Hemingway'/>\n"+
" <author author_id='2' name='William Shakespeare'/>\n"+
@@ -130,27 +223,15 @@
" <title>A Midsummer Night's Dream</title>\n"+
" <issue_date>1595</issue_date>\n"+
" </book>\n"+
- "</data>";
+ "</data>");
- DatabaseIO modelReader = new DatabaseIO();
+ assertEquals(5, beans.size());
- modelReader.setValidateXml(true);
-
- Database model = modelReader.read(new StringReader(testSchemaXml));
- final ArrayList readObjects = new ArrayList();
- DataReader dataReader = new DataReader();
-
- dataReader.setModel(model);
- dataReader.setSink(new TestDataSink(readObjects));
- dataReader.read(new StringReader(testDataXml));
-
- assertEquals(5, readObjects.size());
-
- DynaBean obj1 = (DynaBean)readObjects.get(0);
- DynaBean obj2 = (DynaBean)readObjects.get(1);
- DynaBean obj3 = (DynaBean)readObjects.get(2);
- DynaBean obj4 = (DynaBean)readObjects.get(3);
- DynaBean obj5 = (DynaBean)readObjects.get(4);
+ DynaBean obj1 = (DynaBean)beans.get(0);
+ DynaBean obj2 = (DynaBean)beans.get(1);
+ DynaBean obj3 = (DynaBean)beans.get(2);
+ DynaBean obj4 = (DynaBean)beans.get(3);
+ DynaBean obj5 = (DynaBean)beans.get(4);
assertEquals("author",
obj1.getDynaClass().getName());
@@ -207,15 +288,15 @@
*/
public void testReadFromFile1() throws Exception
{
- final String testSchemaXml =
+ Database model = readModel(
"<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
"<database xmlns='" + DatabaseIO.DDLUTILS_NAMESPACE + "' name='test'>\n" +
" <table name='test'>\n"+
" <column name='id' type='INTEGER' primaryKey='true' required='true'/>\n"+
" <column name='value' type='VARCHAR' size='50' required='true'/>\n"+
" </table>\n"+
- "</database>";
- final String testDataXml =
+ "</database>");
+ String testDataXml =
"<data>\n"+
" <test id='1' value='foo'/>\n"+
"</data>";
@@ -229,21 +310,16 @@
writer.write(testDataXml);
writer.close();
- DatabaseIO modelReader = new DatabaseIO();
-
- modelReader.setValidateXml(true);
-
- Database model = modelReader.read(new StringReader(testSchemaXml));
- final ArrayList readObjects = new ArrayList();
- DataReader dataReader = new DataReader();
+ ArrayList beans = new ArrayList();
+ DataReader dataReader = new DataReader();
dataReader.setModel(model);
- dataReader.setSink(new TestDataSink(readObjects));
+ dataReader.setSink(new TestDataSink(beans));
dataReader.read(tmpFile.getAbsolutePath());
- assertEquals(1, readObjects.size());
+ assertEquals(1, beans.size());
- DynaBean obj = (DynaBean)readObjects.get(0);
+ DynaBean obj = (DynaBean)beans.get(0);
assertEquals("test",
obj.getDynaClass().getName());
@@ -263,15 +339,15 @@
*/
public void testReadFromFile2() throws Exception
{
- final String testSchemaXml =
+ Database model = readModel(
"<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
"<database xmlns='" + DatabaseIO.DDLUTILS_NAMESPACE + "' name='test'>\n" +
" <table name='test'>\n"+
" <column name='id' type='INTEGER' primaryKey='true' required='true'/>\n"+
" <column name='value' type='VARCHAR' size='50' required='true'/>\n"+
" </table>\n"+
- "</database>";
- final String testDataXml =
+ "</database>");
+ String testDataXml =
"<data>\n"+
" <test id='1' value='foo'/>\n"+
"</data>";
@@ -285,21 +361,16 @@
writer.write(testDataXml);
writer.close();
- DatabaseIO modelReader = new DatabaseIO();
-
- modelReader.setValidateXml(true);
-
- Database model = modelReader.read(new StringReader(testSchemaXml));
- final ArrayList readObjects = new ArrayList();
- DataReader dataReader = new DataReader();
+ ArrayList beans = new ArrayList();
+ DataReader dataReader = new DataReader();
dataReader.setModel(model);
- dataReader.setSink(new TestDataSink(readObjects));
+ dataReader.setSink(new TestDataSink(beans));
dataReader.read(tmpFile);
- assertEquals(1, readObjects.size());
+ assertEquals(1, beans.size());
- DynaBean obj = (DynaBean)readObjects.get(0);
+ DynaBean obj = (DynaBean)beans.get(0);
assertEquals("test",
obj.getDynaClass().getName());
@@ -319,15 +390,15 @@
*/
public void testReadFromFile3() throws Exception
{
- final String testSchemaXml =
+ Database model = readModel(
"<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
"<database xmlns='" + DatabaseIO.DDLUTILS_NAMESPACE + "' name='test'>\n" +
" <table name='test'>\n"+
" <column name='id' type='INTEGER' primaryKey='true' required='true'/>\n"+
" <column name='value' type='VARCHAR' size='50' required='true'/>\n"+
" </table>\n"+
- "</database>";
- final String testDataXml =
+ "</database>");
+ String testDataXml =
"<data>\n"+
" <test id='1' value='foo'/>\n"+
"</data>";
@@ -341,21 +412,16 @@
writer.write(testDataXml);
writer.close();
- DatabaseIO modelReader = new DatabaseIO();
-
- modelReader.setValidateXml(true);
-
- Database model = modelReader.read(new StringReader(testSchemaXml));
- final ArrayList readObjects = new ArrayList();
- DataReader dataReader = new DataReader();
+ ArrayList beans = new ArrayList();
+ DataReader dataReader = new DataReader();
dataReader.setModel(model);
- dataReader.setSink(new TestDataSink(readObjects));
+ dataReader.setSink(new TestDataSink(beans));
dataReader.read(new FileInputStream(tmpFile));
- assertEquals(1, readObjects.size());
+ assertEquals(1, beans.size());
- DynaBean obj = (DynaBean)readObjects.get(0);
+ DynaBean obj = (DynaBean)beans.get(0);
assertEquals("test",
obj.getDynaClass().getName());
@@ -375,15 +441,16 @@
*/
public void testSubElements() throws Exception
{
- final String testSchemaXml =
+ Database model = readModel(
"<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
"<database xmlns='" + DatabaseIO.DDLUTILS_NAMESPACE + "' name='test'>\n" +
" <table name='test'>\n"+
" <column name='id' type='INTEGER' primaryKey='true' required='true'/>\n"+
" <column name='value' type='VARCHAR' size='50' required='true'/>\n"+
" </table>\n"+
- "</database>";
- final String testDataXml =
+ "</database>");
+ List beans = readBeans(
+ model,
"<data>\n"+
" <test id='1'>\n"+
" <value>foo</value>\n"+
@@ -393,23 +460,11 @@
" </test>\n"+
" <test id='3' value='baz'>\n"+
" </test>\n"+
- "</data>";
+ "</data>");
- DatabaseIO modelReader = new DatabaseIO();
+ assertEquals(3, beans.size());
- modelReader.setValidateXml(true);
-
- Database model = modelReader.read(new StringReader(testSchemaXml));
- final ArrayList readObjects = new ArrayList();
- DataReader dataReader = new DataReader();
-
- dataReader.setModel(model);
- dataReader.setSink(new TestDataSink(readObjects));
- dataReader.read(new StringReader(testDataXml));
-
- assertEquals(3, readObjects.size());
-
- DynaBean obj = (DynaBean)readObjects.get(0);
+ DynaBean obj = (DynaBean)beans.get(0);
assertEquals("test",
obj.getDynaClass().getName());
@@ -418,7 +473,7 @@
assertEquals("foo",
obj.get("value").toString());
- obj = (DynaBean)readObjects.get(1);
+ obj = (DynaBean)beans.get(1);
assertEquals("test",
obj.getDynaClass().getName());
@@ -427,7 +482,7 @@
assertEquals("bar",
obj.get("value").toString());
- obj = (DynaBean)readObjects.get(2);
+ obj = (DynaBean)beans.get(2);
assertEquals("test",
obj.getDynaClass().getName());
@@ -442,34 +497,23 @@
*/
public void testRootElementNameDoesntMatter() throws Exception
{
- final String testSchemaXml =
+ Database model = readModel(
"<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
"<database xmlns='" + DatabaseIO.DDLUTILS_NAMESPACE + "' name='test'>\n" +
" <table name='test'>\n"+
" <column name='id' type='INTEGER' primaryKey='true' required='true'/>\n"+
" <column name='value' type='VARCHAR' size='50' required='true'/>\n"+
" </table>\n"+
- "</database>";
- final String testDataXml =
+ "</database>");
+ List beans = readBeans(
+ model,
"<someRandomName>\n"+
" <test id='1' value='foo'/>\n"+
- "</someRandomName>";
+ "</someRandomName>");
- DatabaseIO modelReader = new DatabaseIO();
+ assertEquals(1, beans.size());
- modelReader.setValidateXml(true);
-
- Database model = modelReader.read(new StringReader(testSchemaXml));
- final ArrayList readObjects = new ArrayList();
- DataReader dataReader = new DataReader();
-
- dataReader.setModel(model);
- dataReader.setSink(new TestDataSink(readObjects));
- dataReader.read(new StringReader(testDataXml));
-
- assertEquals(1, readObjects.size());
-
- DynaBean obj = (DynaBean)readObjects.get(0);
+ DynaBean obj = (DynaBean)beans.get(0);
assertEquals("test",
obj.getDynaClass().getName());
@@ -484,36 +528,25 @@
*/
public void testElementForUndefinedTable() throws Exception
{
- final String testSchemaXml =
+ Database model = readModel(
"<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
"<database xmlns='" + DatabaseIO.DDLUTILS_NAMESPACE + "' name='test'>\n" +
" <table name='test'>\n"+
" <column name='id' type='INTEGER' primaryKey='true' required='true'/>\n"+
" <column name='value' type='VARCHAR' size='50' required='true'/>\n"+
" </table>\n"+
- "</database>";
- final String testDataXml =
+ "</database>");
+ List beans = readBeans(
+ model,
"<data>\n"+
" <test id='1' value='foo'/>\n"+
" <other id='2' value='bar'/>\n"+
" <test id='3' value='baz'/>\n"+
- "</data>";
+ "</data>");
- DatabaseIO modelReader = new DatabaseIO();
+ assertEquals(2, beans.size());
- modelReader.setValidateXml(true);
-
- Database model = modelReader.read(new StringReader(testSchemaXml));
- final ArrayList readObjects = new ArrayList();
- DataReader dataReader = new DataReader();
-
- dataReader.setModel(model);
- dataReader.setSink(new TestDataSink(readObjects));
- dataReader.read(new StringReader(testDataXml));
-
- assertEquals(2, readObjects.size());
-
- DynaBean obj = (DynaBean)readObjects.get(0);
+ DynaBean obj = (DynaBean)beans.get(0);
assertEquals("test",
obj.getDynaClass().getName());
@@ -522,7 +555,7 @@
assertEquals("foo",
obj.get("value").toString());
- obj = (DynaBean)readObjects.get(1);
+ obj = (DynaBean)beans.get(1);
assertEquals("test",
obj.getDynaClass().getName());
@@ -537,34 +570,23 @@
*/
public void testAttributeForUndefinedColumn() throws Exception
{
- final String testSchemaXml =
+ Database model = readModel(
"<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
"<database xmlns='" + DatabaseIO.DDLUTILS_NAMESPACE + "' name='test'>\n" +
" <table name='test'>\n"+
" <column name='id' type='INTEGER' primaryKey='true' required='true'/>\n"+
" <column name='value' type='VARCHAR' size='50' required='true'/>\n"+
" </table>\n"+
- "</database>";
- final String testDataXml =
+ "</database>");
+ List beans = readBeans(
+ model,
"<data>\n"+
" <test id='1' value1='foo'/>\n"+
- "</data>";
+ "</data>");
- DatabaseIO modelReader = new DatabaseIO();
+ assertEquals(1, beans.size());
- modelReader.setValidateXml(true);
-
- Database model = modelReader.read(new StringReader(testSchemaXml));
- final ArrayList readObjects = new ArrayList();
- DataReader dataReader = new DataReader();
-
- dataReader.setModel(model);
- dataReader.setSink(new TestDataSink(readObjects));
- dataReader.read(new StringReader(testDataXml));
-
- assertEquals(1, readObjects.size());
-
- DynaBean obj = (DynaBean)readObjects.get(0);
+ DynaBean obj = (DynaBean)beans.get(0);
assertEquals("test",
obj.getDynaClass().getName());
@@ -578,36 +600,25 @@
*/
public void testSubElementForUndefinedColumn() throws Exception
{
- final String testSchemaXml =
+ Database model = readModel(
"<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
"<database xmlns='" + DatabaseIO.DDLUTILS_NAMESPACE + "' name='test'>\n" +
" <table name='test'>\n"+
" <column name='id' type='INTEGER' primaryKey='true' required='true'/>\n"+
" <column name='value' type='VARCHAR' size='50' required='true'/>\n"+
" </table>\n"+
- "</database>";
- final String testDataXml =
+ "</database>");
+ List beans = readBeans(
+ model,
"<data>\n"+
" <test id='1'>\n"+
" <value2>foo</value2>\n"+
" </test>\n"+
- "</data>";
+ "</data>");
- DatabaseIO modelReader = new DatabaseIO();
+ assertEquals(1, beans.size());
- modelReader.setValidateXml(true);
-
- Database model = modelReader.read(new StringReader(testSchemaXml));
- final ArrayList readObjects = new ArrayList();
- DataReader dataReader = new DataReader();
-
- dataReader.setModel(model);
- dataReader.setSink(new TestDataSink(readObjects));
- dataReader.read(new StringReader(testDataXml));
-
- assertEquals(1, readObjects.size());
-
- DynaBean obj = (DynaBean)readObjects.get(0);
+ DynaBean obj = (DynaBean)beans.get(0);
assertEquals("test",
obj.getDynaClass().getName());
@@ -621,36 +632,31 @@
*/
public void testCaseSensitivityTurnedOn() throws Exception
{
- final String testSchemaXml =
+ Database model = readModel(
"<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
"<database xmlns='" + DatabaseIO.DDLUTILS_NAMESPACE + "' name='test'>\n" +
" <table name='Test'>\n"+
" <column name='Id' type='INTEGER' primaryKey='true' required='true'/>\n"+
" <column name='Value' type='VARCHAR' size='50' required='true'/>\n"+
" </table>\n"+
- "</database>";
- final String testDataXml =
+ "</database>");
+ String testDataXml =
"<data>\n"+
" <test Id='1' Value='foo'/>\n"+
" <Test Id='2' value='baz'/>\n"+
"</data>";
- DatabaseIO modelReader = new DatabaseIO();
-
- modelReader.setValidateXml(true);
-
- Database model = modelReader.read(new StringReader(testSchemaXml));
- final ArrayList readObjects = new ArrayList();
- DataReader dataReader = new DataReader();
+ ArrayList beans = new ArrayList();
+ DataReader dataReader = new DataReader();
dataReader.setCaseSensitive(true);
dataReader.setModel(model);
- dataReader.setSink(new TestDataSink(readObjects));
+ dataReader.setSink(new TestDataSink(beans));
dataReader.read(new StringReader(testDataXml));
- assertEquals(1, readObjects.size());
+ assertEquals(1, beans.size());
- DynaBean obj = (DynaBean)readObjects.get(0);
+ DynaBean obj = (DynaBean)beans.get(0);
assertEquals("Test",
obj.getDynaClass().getName());
@@ -664,37 +670,32 @@
*/
public void testCaseSensitivityTurnedOff() throws Exception
{
- final String testSchemaXml =
+ Database model = readModel(
"<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
"<database xmlns='" + DatabaseIO.DDLUTILS_NAMESPACE + "' name='test'>\n" +
" <table name='Test'>\n"+
" <column name='Id' type='INTEGER' primaryKey='true' required='true'/>\n"+
" <column name='Value' type='VARCHAR' size='50' required='true'/>\n"+
" </table>\n"+
- "</database>";
- final String testDataXml =
+ "</database>");
+ String testDataXml =
"<data>\n"+
" <test Id='1' Value='foo'/>\n"+
" <Test Id='2' value='bar'/>\n"+
" <Test id='3' Value='baz'/>\n"+
"</data>";
- DatabaseIO modelReader = new DatabaseIO();
-
- modelReader.setValidateXml(true);
-
- Database model = modelReader.read(new StringReader(testSchemaXml));
- final ArrayList readObjects = new ArrayList();
- DataReader dataReader = new DataReader();
+ ArrayList beans = new ArrayList();
+ DataReader dataReader = new DataReader();
dataReader.setCaseSensitive(false);
dataReader.setModel(model);
- dataReader.setSink(new TestDataSink(readObjects));
+ dataReader.setSink(new TestDataSink(beans));
dataReader.read(new StringReader(testDataXml));
- assertEquals(3, readObjects.size());
+ assertEquals(3, beans.size());
- DynaBean obj = (DynaBean)readObjects.get(0);
+ DynaBean obj = (DynaBean)beans.get(0);
assertEquals("Test",
obj.getDynaClass().getName());
@@ -703,7 +704,7 @@
assertEquals("foo",
obj.get("Value").toString());
- obj = (DynaBean)readObjects.get(1);
+ obj = (DynaBean)beans.get(1);
assertEquals("Test",
obj.getDynaClass().getName());
@@ -712,7 +713,7 @@
assertEquals("bar",
obj.get("Value").toString());
- obj = (DynaBean)readObjects.get(2);
+ obj = (DynaBean)beans.get(2);
assertEquals("Test",
obj.getDynaClass().getName());
@@ -727,58 +728,28 @@
*/
public void testSpecialCharacters() throws Exception
{
- final String testSchemaXml =
+ Database model = readModel(
"<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
"<database xmlns='" + DatabaseIO.DDLUTILS_NAMESPACE + "' name='test'>\n" +
" <table name='test'>\n"+
" <column name='id' type='INTEGER' primaryKey='true' required='true'/>\n"+
" <column name='value' type='VARCHAR' size='50' required='true'/>\n"+
" </table>\n"+
- "</database>";
- final String testedValue = "Some Special Characters: \u0001\u0009\u0010";
+ "</database>");
+ String testedValue = "Some Special Characters: \u0001\u0009\u0010";
- DatabaseIO modelIO = new DatabaseIO();
-
- modelIO.setValidateXml(true);
-
- Database model = modelIO.read(new StringReader(testSchemaXml));
- ByteArrayOutputStream output = new ByteArrayOutputStream();
- DataWriter dataWriter = new DataWriter(output, "ISO-8859-1");
- SqlDynaBean bean = (SqlDynaBean)model.createDynaBeanFor(model.getTable(0));
+ 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();
- final ArrayList readObjects = new ArrayList();
- DataReader dataReader = new DataReader();
-
- String dataXml = new String(output.toByteArray(), "ISO-8859-1");
-
- assertEquals("<?xml version='1.0' encoding='ISO-8859-1'?>\n" +
- "<data>\n" +
- " <test id=\"1\">\n" +
- " <value " + DatabaseIO.BASE64_ATTR_NAME + "=\"true\"><![CDATA[" + new String(Base64.encodeBase64(testedValue.getBytes()), "ISO-8859-1") + "]]></value>\n" +
- " </test>\n" +
- "</data>\n",
- dataXml);
-
- dataReader.setModel(model);
- dataReader.setSink(new TestDataSink(readObjects));
- dataReader.read(new ByteArrayInputStream(output.toByteArray()));
-
- assertEquals(1, readObjects.size());
-
- DynaBean obj = (DynaBean)readObjects.get(0);
-
- assertEquals("test",
- obj.getDynaClass().getName());
- assertEquals("1",
- obj.get("id").toString());
- assertEquals(testedValue,
- obj.get("value").toString());
+ roundtripTest(model, bean, "ISO-8859-1",
+ "<?xml version='1.0' encoding='ISO-8859-1'?>\n" +
+ "<data>\n" +
+ " <test id=\"1\">\n" +
+ " <value " + DatabaseIO.BASE64_ATTR_NAME + "=\"true\">" + new String(Base64.encodeBase64(testedValue.getBytes("UTF-8")), "ISO-8859-1") + "</value>\n" +
+ " </test>\n" +
+ "</data>\n");
}
/**
@@ -786,58 +757,28 @@
*/
public void testSpecialCharactersUTF8() throws Exception
{
- final String testSchemaXml =
+ Database model = readModel(
"<?xml version='1.0' encoding='UTF-8'?>\n"+
"<database xmlns='" + DatabaseIO.DDLUTILS_NAMESPACE + "' name='test'>\n" +
" <table name='test'>\n"+
" <column name='id' type='INTEGER' primaryKey='true' required='true'/>\n"+
" <column name='value' type='VARCHAR' size='50' required='true'/>\n"+
" </table>\n"+
- "</database>";
- final String testedValue = "Some Special Characters: \u0001\u0009\u0010";
+ "</database>");
+ String testedValue = "Some Special Characters: \u0001\u0009\u0010";
- DatabaseIO modelIO = new DatabaseIO();
-
- modelIO.setValidateXml(true);
-
- Database model = modelIO.read(new StringReader(testSchemaXml));
- ByteArrayOutputStream output = new ByteArrayOutputStream();
- DataWriter dataWriter = new DataWriter(output, "UTF-8");
- SqlDynaBean bean = (SqlDynaBean)model.createDynaBeanFor(model.getTable(0));
+ SqlDynaBean bean = (SqlDynaBean)model.createDynaBeanFor(model.getTable(0));
bean.set("id", new Integer(1));
bean.set("value", testedValue);
- dataWriter.writeDocumentStart();
- dataWriter.write(bean);
- dataWriter.writeDocumentEnd();
- String dataXml = new String(output.toByteArray(), "UTF-8");
-
- assertEquals("<?xml version='1.0' encoding='UTF-8'?>\n" +
- "<data>\n" +
- " <test id=\"1\">\n" +
- " <value " + DatabaseIO.BASE64_ATTR_NAME + "=\"true\"><![CDATA[" + new String(Base64.encodeBase64(testedValue.getBytes()), "UTF-8") + "]]></value>\n" +
- " </test>\n" +
- "</data>\n",
- dataXml);
-
- final ArrayList readObjects = new ArrayList();
- DataReader dataReader = new DataReader();
-
- dataReader.setModel(model);
- dataReader.setSink(new TestDataSink(readObjects));
- dataReader.read(new ByteArrayInputStream(output.toByteArray()));
-
- assertEquals(1, readObjects.size());
-
- DynaBean obj = (DynaBean)readObjects.get(0);
-
- assertEquals("test",
- obj.getDynaClass().getName());
- assertEquals("1",
- obj.get("id").toString());
- assertEquals(testedValue,
- obj.get("value").toString());
+ roundtripTest(model, bean, "ISO-8859-1",
+ "<?xml version='1.0' encoding='ISO-8859-1'?>\n" +
+ "<data>\n" +
+ " <test id=\"1\">\n" +
+ " <value " + DatabaseIO.BASE64_ATTR_NAME + "=\"true\">" + new String(Base64.encodeBase64(testedValue.getBytes("UTF-8")), "UTF-8") + "</value>\n" +
+ " </test>\n" +
+ "</data>\n");
}
/**
@@ -845,7 +786,7 @@
*/
public void testCData() throws Exception
{
- final String testSchemaXml =
+ Database model = readModel(
"<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
"<database xmlns='" + DatabaseIO.DDLUTILS_NAMESPACE + "' name='test'>\n" +
" <table name='test'>\n"+
@@ -856,21 +797,14 @@
" <column name='value4' type='LONGVARCHAR' size='4000' required='true'/>\n"+
" <column name='value5' type='LONGVARCHAR' size='4000' required='true'/>\n"+
" </table>\n"+
- "</database>";
- final String testedValue1 = "<?xml version='1.0' encoding='ISO-8859-1'?><test><![CDATA[some text]]></test>";
- final String testedValue2 = StringUtils.repeat("a ", 1000) + testedValue1;
- final String testedValue3 = "<div>\n<h1><![CDATA[WfMOpen]]></h1>\n" + StringUtils.repeat("Make it longer\n", 99) + "</div>";
- final String testedValue4 = "<![CDATA[" + StringUtils.repeat("b \n", 1000) + "]]>";
- final String testedValue5 = "<<![CDATA[" + StringUtils.repeat("b \n", 500) + "]]>><![CDATA[" + StringUtils.repeat("c \n", 500) + "]]>";
+ "</database>");
+ String testedValue1 = "<?xml version='1.0' encoding='ISO-8859-1'?><test><![CDATA[some text]]></test>";
+ String testedValue2 = StringUtils.repeat("a ", 1000) + testedValue1;
+ String testedValue3 = "<div>\n<h1><![CDATA[WfMOpen]]></h1>\n" + StringUtils.repeat("Make it longer\n", 99) + "</div>";
+ String testedValue4 = "<![CDATA[" + StringUtils.repeat("b \n", 1000) + "]]>";
+ String testedValue5 = "<<![CDATA[" + StringUtils.repeat("b \n", 500) + "]]>><![CDATA[" + StringUtils.repeat("c \n", 500) + "]]>";
- DatabaseIO modelIO = new DatabaseIO();
-
- modelIO.setValidateXml(true);
-
- Database model = modelIO.read(new StringReader(testSchemaXml));
- StringWriter output = new StringWriter();
- DataWriter dataWriter = new DataWriter(output, "UTF-8");
- SqlDynaBean bean = (SqlDynaBean)model.createDynaBeanFor(model.getTable(0));
+ SqlDynaBean bean = (SqlDynaBean)model.createDynaBeanFor(model.getTable(0));
bean.set("id", new Integer(1));
bean.set("value1", testedValue1);
@@ -878,37 +812,42 @@
bean.set("value3", testedValue3);
bean.set("value4", testedValue4);
bean.set("value5", testedValue5);
- dataWriter.writeDocumentStart();
- dataWriter.write(bean);
- dataWriter.writeDocumentEnd();
- String dataXml = output.toString();
+ byte[] xmlData = writeBean(model, bean, "UTF-8");
+ List beans = readBeans(model, xmlData);
- final ArrayList readObjects = new ArrayList();
- DataReader dataReader = new DataReader();
+ assertEquals(1, beans.size());
+ assertEquals(bean, beans.get(0));
+ }
- dataReader.setModel(model);
- dataReader.setSink(new TestDataSink(readObjects));
- dataReader.read(new StringReader(dataXml));
+ /**
+ * Tests the reader & writer behavior when the table name is not a valid XML identifier.
+ */
+ public void testTableNameLong() throws Exception
+ {
+ String tableName = StringUtils.repeat("test", 100);
+ Database model = readModel(
+ "<?xml version='1.0' encoding='UTF-8'?>\n"+
+ "<database xmlns='" + DatabaseIO.DDLUTILS_NAMESPACE + "' name='test'>\n" +
+ " <table name='" + tableName + "'>\n"+
+ " <column name='id' type='INTEGER' primaryKey='true' required='true'/>\n"+
+ " <column name='value' type='VARCHAR' size='50' required='true'/>\n"+
+ " </table>\n"+
+ "</database>");
+ String testedValue = "Some Text";
- assertEquals(1, readObjects.size());
+ SqlDynaBean bean = (SqlDynaBean)model.createDynaBeanFor(model.getTable(0));
- DynaBean obj = (DynaBean)readObjects.get(0);
+ bean.set("id", new Integer(1));
+ bean.set("value", testedValue);
- assertEquals("test",
- obj.getDynaClass().getName());
- assertEquals("1",
- obj.get("id").toString());
- assertEquals(testedValue1,
- obj.get("value1").toString());
- assertEquals(testedValue2,
- obj.get("value2").toString());
- assertEquals(testedValue3,
- obj.get("value3").toString());
- assertEquals(testedValue4,
- obj.get("value4").toString());
- assertEquals(testedValue5,
- obj.get("value5").toString());
+ roundtripTest(model, bean, "UTF-8",
+ "<?xml version='1.0' encoding='UTF-8'?>\n" +
+ "<data>\n" +
+ " <table id=\"1\" value=\"" + testedValue + "\">\n" +
+ " <table-name>" + tableName + "</table-name>\n" +
+ " </table>\n" +
+ "</data>\n");
}
/**
@@ -916,53 +855,864 @@
*/
public void testTableNameNotAValidXmlIdentifier() throws Exception
{
- final String testSchemaXml =
- "<?xml version='1.0' encoding='ISO-8859-1'?>\n"+
+ Database model = readModel(
+ "<?xml version='1.0' encoding='UTF-8'?>\n"+
+ "<database xmlns='" + DatabaseIO.DDLUTILS_NAMESPACE + "' name='test'>\n" +
+ " <table name='test$'>\n"+
+ " <column name='id' type='INTEGER' primaryKey='true' required='true'/>\n"+
+ " <column name='value' type='VARCHAR' size='50' required='true'/>\n"+
+ " </table>\n"+
+ "</database>");
+ String testedValue = "Some Text";
+
+ SqlDynaBean bean = (SqlDynaBean)model.createDynaBeanFor(model.getTable(0));
+
+ bean.set("id", new Integer(1));
+ bean.set("value", testedValue);
+
+ roundtripTest(model, bean, "UTF-8",
+ "<?xml version='1.0' encoding='UTF-8'?>\n" +
+ "<data>\n" +
+ " <table table-name=\"test$\" id=\"1\" value=\"" + testedValue + "\" />\n" +
+ "</data>\n");
+ }
+
+ /**
+ * Tests the reader & writer behavior when the table name is not a valid XML identifier and too long.
+ */
+ public void testTableNameInvalidAndLong() throws Exception
+ {
+ String tableName = StringUtils.repeat("table name", 50);
+ Database model = readModel(
+ "<?xml version='1.0' encoding='UTF-8'?>\n"+
+ "<database xmlns='" + DatabaseIO.DDLUTILS_NAMESPACE + "' name='test'>\n" +
+ " <table name='" + tableName + "'>\n"+
+ " <column name='id' type='INTEGER' primaryKey='true' required='true'/>\n"+
+ " <column name='value' type='VARCHAR' size='50' required='true'/>\n"+
+ " </table>\n"+
+ "</database>");
+ String testedValue = "Some Text";
+
+ SqlDynaBean bean = (SqlDynaBean)model.createDynaBeanFor(model.getTable(0));
+
+ bean.set("id", new Integer(1));
+ bean.set("value", testedValue);
+
+ roundtripTest(model, bean, "UTF-8",
+ "<?xml version='1.0' encoding='UTF-8'?>\n" +
+ "<data>\n" +
+ " <table id=\"1\" value=\"" + testedValue + "\">\n" +
+ " <table-name>" + tableName + "</table-name>\n" +
+ " </table>\n" +
+ "</data>\n");
+ }
+
+ /**
+ * Tests the reader & writer behavior when the table name contains a '&' character.
+ */
+ public void testTableNameContainsAmpersand() throws Exception
+ {
+ String tableName = "test&table";
+ Database model = new Database("test");
+ Table table = new Table();
+ Column idColumn = new Column();
+ Column valueColumn = new Column();
+
+ idColumn.setName("id");
+ idColumn.setType("INTEGER");
+ idColumn.setPrimaryKey(true);
+ idColumn.setRequired(true);
+ valueColumn.setName("value");
+ valueColumn.setType("VARCHAR");
+ valueColumn.setSize("50");
+ valueColumn.setRequired(true);
+ table.setName(tableName);
+ table.addColumn(idColumn);
+ table.addColumn(valueColumn);
+ model.addTable(table);
+
+ SqlDynaBean bean = (SqlDynaBean)model.createDynaBeanFor(model.getTable(0));
+ String testedValue = "Some Text";
+
+ bean.set("id", new Integer(1));
+ bean.set("value", testedValue);
+
+ roundtripTest(model, bean, "UTF-8",
+ "<?xml version='1.0' encoding='UTF-8'?>\n" +
+ "<data>\n" +
+ " <table table-name=\"test&table\" id=\"1\" value=\"" + testedValue + "\" />\n" +
+ "</data>\n");
+ }
+
+ /**
+ * Tests the reader & writer behavior when the table name contains a '<' character.
+ */
+ public void testTableNameContainsLessCharacter() throws Exception
+ {
+ String tableName = "test<table";
+ Database model = new Database("test");
+ Table table = new Table();
+ Column idColumn = new Column();
+ Column valueColumn = new Column();
+
+ idColumn.setName("id");
+ idColumn.setType("INTEGER");
+ idColumn.setPrimaryKey(true);
+ idColumn.setRequired(true);
+ valueColumn.setName("value");
+ valueColumn.setType("VARCHAR");
+ valueColumn.setSize("50");
+ valueColumn.setRequired(true);
+ table.setName(tableName);
+ table.addColumn(idColumn);
+ table.addColumn(valueColumn);
+ model.addTable(table);
+
+ SqlDynaBean bean = (SqlDynaBean)model.createDynaBeanFor(model.getTable(0));
+ String testedValue = "Some Text";
+
+ bean.set("id", new Integer(1));
+ bean.set("value", testedValue);
+
+ roundtripTest(model, bean, "UTF-8",
+ "<?xml version='1.0' encoding='UTF-8'?>\n" +
+ "<data>\n" +
+ " <table table-name=\"test<table\" id=\"1\" value=\"" + testedValue + "\" />\n" +
+ "</data>\n");
+ }
+
+ /**
+ * Tests the reader & writer behavior when the table name contains a '>' character.
+ */
+ public void testTableNameContainsMoreCharacter() throws Exception
+ {
+ String tableName = "test>table";
+ Database model = new Database("test");
+ Table table = new Table();
+ Column idColumn = new Column();
+ Column valueColumn = new Column();
+
+ idColumn.setName("id");
+ idColumn.setType("INTEGER");
+ idColumn.setPrimaryKey(true);
+ idColumn.setRequired(true);
+ valueColumn.setName("value");
+ valueColumn.setType("VARCHAR");
+ valueColumn.setSize("50");
+ valueColumn.setRequired(true);
+ table.setName(tableName);
+ table.addColumn(idColumn);
+ table.addColumn(valueColumn);
+ model.addTable(table);
+
+ SqlDynaBean bean = (SqlDynaBean)model.createDynaBeanFor(model.getTable(0));
+ String testedValue = "Some Text";
+
+ bean.set("id", new Integer(1));
+ bean.set("value", testedValue);
+
+ roundtripTest(model, bean, "UTF-8",
+ "<?xml version='1.0' encoding='UTF-8'?>\n" +
+ "<data>\n" +
+ " <table table-name=\"test>table\" id=\"1\" value=\"" + testedValue + "\" />\n" +
+ "</data>\n");
+ }
+
+ /**
+ * Tests the reader & writer behavior when the table name contains characters not allowed in XML.
+ */
+ public void testTableNameContainsInvalidCharacters() throws Exception
+ {
+ String tableName = "test\u0000table";
+ Database model = new Database("test");
+ Table table = new Table();
+ Column idColumn = new Column();
+ Column valueColumn = new Column();
+
+ idColumn.setName("id");
+ idColumn.setType("INTEGER");
+ idColumn.setPrimaryKey(true);
+ idColumn.setRequired(true);
+ valueColumn.setName("value");
+ valueColumn.setType("VARCHAR");
+ valueColumn.setSize("50");
+ valueColumn.setRequired(true);
+ table.setName(tableName);
+ table.addColumn(idColumn);
+ table.addColumn(valueColumn);
+ model.addTable(table);
+
+ SqlDynaBean bean = (SqlDynaBean)model.createDynaBeanFor(model.getTable(0));
+ String testedValue = "Some Text";
+
+ bean.set("id", new Integer(1));
+ bean.set("value", testedValue);
+
+ roundtripTest(model, bean, "UTF-8",
+ "<?xml version='1.0' encoding='UTF-8'?>\n" +
+ "<data>\n" +
+ " <table id=\"1\" value=\"" + testedValue + "\">\n" +
+ " <table-name " + DatabaseIO.BASE64_ATTR_NAME + "=\"true\">" + new String(Base64.encodeBase64(tableName.getBytes("UTF-8")), "UTF-8") + "</table-name>\n" +
+ " </table>\n" +
+ "</data>\n");
+ }
+
+ /**
+ * Tests the reader & writer behavior when the table name is 'table'.
+ */
+ public void testTableNameIsTable() throws Exception
+ {
+ Database model = readModel(
+ "<?xml version='1.0' encoding='UTF-8'?>\n"+
+ "<database xmlns='" + DatabaseIO.DDLUTILS_NAMESPACE + "' name='test'>\n" +
+ " <table name='table'>\n"+
+ " <column name='id' type='INTEGER' primaryKey='true' required='true'/>\n"+
+ " <column name='value' type='VARCHAR' size='50' required='true'/>\n"+
+ " </table>\n"+
+ "</database>");
+ String testedValue = "Some Text";
+
+ DatabaseIO modelIO = new DatabaseIO();
+
+ modelIO.setValidateXml(true);
+
+ SqlDynaBean bean = (SqlDynaBean)model.createDynaBeanFor(model.getTable(0));
+
+ bean.set("id", new Integer(1));
+ bean.set("value", testedValue);
+
+ roundtripTest(model, bean, "UTF-8",
+ "<?xml version='1.0' encoding='UTF-8'?>\n" +
+ "<data>\n" +
+ " <table table-name=\"table\" id=\"1\" value=\"" + testedValue + "\" />\n" +
+ "</data>\n");
+ }
+
+ /**
+ * Tests the reader & writer behavior when a column name is a normal valid tag,
+ * and both column name and value are shorter than 255 characters.
+ */
+ public void testColumnNameAndValueShort() throws Exception
+ {
+ Database model = readModel(
+ "<?xml version='1.0' encoding='UTF-8'?>\n"+
"<database xmlns='" + DatabaseIO.DDLUTILS_NAMESPACE + "' name='test'>\n" +
" <table name='test'>\n"+
" <column name='id' type='INTEGER' primaryKey='true' required='true'/>\n"+
" <column name='value' type='VARCHAR' size='50' required='true'/>\n"+
" </table>\n"+
- "</database>";
- final String testedValue = "Some Special Characters: \u0001\u0009\u0010";
+ "</database>");
+ String testedValue = "Some Text";
- DatabaseIO modelIO = new DatabaseIO();
-
- modelIO.setValidateXml(true);
-
- Database model = modelIO.read(new StringReader(testSchemaXml));
- StringWriter output = new StringWriter();
- DataWriter dataWriter = new DataWriter(output, "UTF-8");
- SqlDynaBean bean = (SqlDynaBean)model.createDynaBeanFor(model.getTable(0));
+ 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 TestDataSink(readObjects));
- dataReader.read(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());
+ roundtripTest(model, bean, "UTF-8",
+ "<?xml version='1.0' encoding='UTF-8'?>\n" +
+ "<data>\n" +
+ " <test id=\"1\" value=\"" + testedValue + "\" />\n" +
+ "</data>\n");
}
- // TODO: additional tests
- // - table name with illegal-for-XML characters, e.g space, &, ... (write)
- // - column name with illegal-for-XML characters, e.g space, &, ... (write)
+ /**
+ * Tests the reader & writer behavior when a column name is a normal valid tag,
+ * and the column name is shorter than 255 characters but the value is longer.
+ */
+ public void testColumnNameShortAndValueLong() throws Exception
+ {
+ Database model = readModel(
+ "<?xml version='1.0' encoding='UTF-8'?>\n"+
+ "<database xmlns='" + DatabaseIO.DDLUTILS_NAMESPACE + "' name='test'>\n" +
+ " <table name='test'>\n"+
+ " <column name='id' type='INTEGER' primaryKey='true' required='true'/>\n"+
+ " <column name='value' type='VARCHAR' size='400' required='true'/>\n"+
+ " </table>\n"+
+ "</database>");
+ String testedValue = StringUtils.repeat("Some Text", 40);
+
+ SqlDynaBean bean = (SqlDynaBean)model.createDynaBeanFor(model.getTable(0));
+
+ bean.set("id", new Integer(1));
+ bean.set("value", testedValue);
+
+ roundtripTest(model, bean, "UTF-8",
+ "<?xml version='1.0' encoding='UTF-8'?>\n" +
+ "<data>\n" +
+ " <test id=\"1\">\n" +
+ " <value>" + testedValue + "</value>\n" +
+ " </test>\n" +
+ "</data>\n");
+ }
+
+ /**
+ * Tests the reader & writer behavior when a column name is not a valid XML identifier.
+ */
+ public void testColumnNameShortAndInvalidAndValueShort() throws Exception
+ {
+ Database model = readModel(
+ "<?xml version='1.0' encoding='UTF-8'?>\n"+
+ "<database xmlns='" + DatabaseIO.DDLUTILS_NAMESPACE + "' name='test'>\n" +
+ " <table name='test'>\n"+
+ " <column name='id' type='INTEGER' primaryKey='true' required='true'/>\n"+
+ " <column name='the value' type='VARCHAR' size='50' required='true'/>\n"+
+ " </table>\n"+
+ "</database>");
+ String testedValue = "Some Text";
+
+ SqlDynaBean bean = (SqlDynaBean)model.createDynaBeanFor(model.getTable(0));
+
+ bean.set("id", new Integer(1));
+ bean.set("the value", testedValue);
+
+ roundtripTest(model, bean, "UTF-8",
+ "<?xml version='1.0' encoding='UTF-8'?>\n" +
+ "<data>\n" +
+ " <test id=\"1\">\n" +
+ " <column column-name=\"the value\">" + testedValue + "</column>\n" +
+ " </test>\n" +
+ "</data>\n");
+ }
+
+ /**
+ * Tests the reader & writer behavior when a column name is not a valid tag,
+ * and the column name is shorter than 255 characters and the value is longer.
+ */
+ public void testColumnNameShortAndInvalidAndValueLong() throws Exception
+ {
+ Database model = readModel(
+ "<?xml version='1.0' encoding='UTF-8'?>\n"+
+ "<database xmlns='" + DatabaseIO.DDLUTILS_NAMESPACE + "' name='test'>\n" +
+ " <table name='test'>\n"+
+ " <column name='id' type='INTEGER' primaryKey='true' required='true'/>\n"+
+ " <column name='the value' type='VARCHAR' size='50' required='true'/>\n"+
+ " </table>\n"+
+ "</database>");
+ String testedValue = StringUtils.repeat("Some Text", 40);
+
+ SqlDynaBean bean = (SqlDynaBean)model.createDynaBeanFor(model.getTable(0));
+
+ bean.set("id", new Integer(1));
+ bean.set("the value", testedValue);
+
+ roundtripTest(model, bean, "UTF-8",
+ "<?xml version='1.0' encoding='UTF-8'?>\n" +
+ "<data>\n" +
+ " <test id=\"1\">\n" +
+ " <column column-name=\"the value\">" + testedValue + "</column>\n" +
+ " </test>\n" +
+ "</data>\n");
+ }
+
+ /**
+ * Tests the reader & writer behavior when a column name is a valid tag,
+ * and the column name is longer than 255 characters and the value is shorter.
+ */
+ public void testColumnNameLongAndValueShort() throws Exception
+ {
+ String columnName = StringUtils.repeat("value", 100);
+ Database model = readModel(
+ "<?xml version='1.0' encoding='UTF-8'?>\n"+
+ "<database xmlns='" + DatabaseIO.DDLUTILS_NAMESPACE + "' name='test'>\n" +
+ " <table name='test'>\n"+
+ " <column name='id' type='INTEGER' primaryKey='true' required='true'/>\n"+
+ " <column name='" + columnName + "' type='VARCHAR' size='50' required='true'/>\n"+
+ " </table>\n"+
+ "</database>");
+ String testedValue = "Some Text";
+
+ SqlDynaBean bean = (SqlDynaBean)model.createDynaBeanFor(model.getTable(0));
+
+ bean.set("id", new Integer(1));
+ bean.set(columnName, testedValue);
+
+ roundtripTest(model, bean, "UTF-8",
+ "<?xml version='1.0' encoding='UTF-8'?>\n" +
+ "<data>\n" +
+ " <test id=\"1\">\n" +
+ " <column>\n" +
+ " <column-name>" + columnName + "</column-name>\n" +
+ " <column-value>" + testedValue + "</column-value>\n" +
+ " </column>\n" +
+ " </test>\n" +
+ "</data>\n");
+ }
+
+ /**
+ * Tests the reader & writer behavior when a column name is a valid tag,
+ * and both the column name and value are longer than 255 characters.
+ */
+ public void testColumnNameLongAndValueLong() throws Exception
+ {
+ String columnName = StringUtils.repeat("value", 100);
+ Database model = readModel(
+ "<?xml version='1.0' encoding='UTF-8'?>\n"+
+ "<database xmlns='" + DatabaseIO.DDLUTILS_NAMESPACE + "' name='test'>\n" +
+ " <table name='test'>\n"+
+ " <column name='id' type='INTEGER' primaryKey='true' required='true'/>\n"+
+ " <column name='" + columnName + "' type='VARCHAR' size='500' required='true'/>\n"+
+ " </table>\n"+
+ "</database>");
+ String testedValue = StringUtils.repeat("Some Text", 40);
+
+ SqlDynaBean bean = (SqlDynaBean)model.createDynaBeanFor(model.getTable(0));
+
+ bean.set("id", new Integer(1));
+ bean.set(columnName, testedValue);
+
+ roundtripTest(model, bean, "UTF-8",
+ "<?xml version='1.0' encoding='UTF-8'?>\n" +
+ "<data>\n" +
+ " <test id=\"1\">\n" +
+ " <column>\n" +
+ " <column-name>" + columnName + "</column-name>\n" +
+ " <column-value>" + testedValue + "</column-value>\n" +
+ " </column>\n" +
+ " </test>\n" +
+ "</data>\n");
+ }
+
+ /**
+ * Tests the reader & writer behavior when a column name is a valid tag,
+ * and the column name is longer than 255 characters and the value is shorter.
+ */
+ public void testColumnNameAndValueLong() throws Exception
+ {
+ String columnName = StringUtils.repeat("value", 100);
+ Database model = readModel(
+ "<?xml version='1.0' encoding='UTF-8'?>\n"+
+ "<database xmlns='" + DatabaseIO.DDLUTILS_NAMESPACE + "' name='test'>\n" +
+ " <table name='test'>\n"+
+ " <column name='id' type='INTEGER' primaryKey='true' required='true'/>\n"+
+ " <column name='" + columnName + "' type='VARCHAR' size='50' required='true'/>\n"+
+ " </table>\n"+
+ "</database>");
+ String testedValue = "Some Text";
+
+ SqlDynaBean bean = (SqlDynaBean)model.createDynaBeanFor(model.getTable(0));
+
+ bean.set("id", new Integer(1));
+ bean.set(columnName, testedValue);
+
+ roundtripTest(model, bean, "UTF-8",
+ "<?xml version='1.0' encoding='UTF-8'?>\n" +
+ "<data>\n" +
+ " <test id=\"1\">\n" +
+ " <column>\n" +
+ " <column-name>" + columnName + "</column-name>\n" +
+ " <column-value>" + testedValue + "</column-value>\n" +
+ " </column>\n" +
+ " </test>\n" +
+ "</data>\n");
+ }
+
+ /**
+ * Tests the reader & writer behavior when a column name is not a valid tag,
+ * and the value is invalid, and both are short.
+ */
+ public void testColumnNameAndValueShortAndInvalid() throws Exception
+ {
+ Database model = readModel(
+ "<?xml version='1.0' encoding='UTF-8'?>\n"+
+ "<database xmlns='" + DatabaseIO.DDLUTILS_NAMESPACE + "' name='test'>\n" +
+ " <table name='test'>\n"+
+ " <column name='id' type='INTEGER' primaryKey='true' required='true'/>\n"+
+ " <column name='the value' type='VARCHAR' size='50' required='true'/>\n"+
+ " </table>\n"+
+ "</database>");
+ String testedValue = "the\u0000value";
+
+ SqlDynaBean bean = (SqlDynaBean)model.createDynaBeanFor(model.getTable(0));
+
+ bean.set("id", new Integer(1));
+ bean.set("the value", testedValue);
+
+ roundtripTest(model, bean, "UTF-8",
+ "<?xml version='1.0' encoding='UTF-8'?>\n" +
+ "<data>\n" +
+ " <test id=\"1\">\n" +
+ " <column column-name=\"the value\" " + DatabaseIO.BASE64_ATTR_NAME + "=\"true\">" + new String(Base64.encodeBase64(testedValue.getBytes("UTF-8")), "UTF-8") + "</column>\n" +
+ " </test>\n" +
+ "</data>\n");
+ }
+
+ /**
+ * Tests the reader & writer behavior when a column name is a valid tag and longer,
+ * than 255 characters, and the value is invalid and shorter than 255 characters.
+ */
+ public void testColumnNameLongAndValueInvalidAndShort() throws Exception
+ {
+ String columnName = StringUtils.repeat("value", 100);
+ Database model = readModel(
+ "<?xml version='1.0' encoding='UTF-8'?>\n"+
+ "<database xmlns='" + DatabaseIO.DDLUTILS_NAMESPACE + "' name='test'>\n" +
+ " <table name='test'>\n"+
+ " <column name='id' type='INTEGER' primaryKey='true' required='true'/>\n"+
+ " <column name='" + columnName + "' type='VARCHAR' size='50' required='true'/>\n"+
+ " </table>\n"+
+ "</database>");
+ String testedValue = "the\u0000value";
+
+ SqlDynaBean bean = (SqlDynaBean)model.createDynaBeanFor(model.getTable(0));
+
+ bean.set("id", new Integer(1));
+ bean.set(columnName, testedValue);
+
+ roundtripTest(model, bean, "UTF-8",
+ "<?xml version='1.0' encoding='UTF-8'?>\n" +
+ "<data>\n" +
+ " <test id=\"1\">\n" +
+ " <column>\n" +
+ " <column-name>" + columnName + "</column-name>\n" +
+ " <column-value " + DatabaseIO.BASE64_ATTR_NAME + "=\"true\">" + new String(Base64.encodeBase64(testedValue.getBytes("UTF-8")), "UTF-8") + "</column-value>\n" +
+ " </column>\n" +
+ " </test>\n" +
+ "</data>\n");
+ }
+
+ /**
+ * Tests the reader & writer behavior when a column name is not a valid tag,
+ * and the value is invalid, and both are short.
+ */
+ public void testColumnNameAndValueLongAndInvalid() throws Exception
+ {
+ Database model = new Database("test");
+ Table table = new Table();
+ Column idColumn = new Column();
+ Column valueColumn = new Column();
+ String columnName = StringUtils.repeat("the\u0000name", 100);
+
+ idColumn.setName("id");
+ idColumn.setType("INTEGER");
+ idColumn.setPrimaryKey(true);
+ idColumn.setRequired(true);
+ valueColumn.setName(columnName);
+ valueColumn.setType("VARCHAR");
+ valueColumn.setSize("50");
+ valueColumn.setRequired(true);
+ table.setName("test");
+ table.addColumn(idColumn);
+ table.addColumn(valueColumn);
+ model.addTable(table);
+
+ SqlDynaBean bean = (SqlDynaBean)model.createDynaBeanFor(model.getTable(0));
+ String testedValue = StringUtils.repeat("the\u0000value", 40);
+
+ bean.set("id", new Integer(1));
+ bean.set(columnName, testedValue);
+
+ roundtripTest(model, bean, "UTF-8",
+ "<?xml version='1.0' encoding='UTF-8'?>\n" +
+ "<data>\n" +
+ " <test id=\"1\">\n" +
+ " <column>\n" +
+ " <column-name " + DatabaseIO.BASE64_ATTR_NAME + "=\"true\">" + new String(Base64.encodeBase64(columnName.getBytes("UTF-8")), "UTF-8") + "</column-name>\n" +
+ " <column-value " + DatabaseIO.BASE64_ATTR_NAME + "=\"true\">" + new String(Base64.encodeBase64(testedValue.getBytes("UTF-8")), "UTF-8") + "</column-value>\n" +
+ " </column>\n" +
+ " </test>\n" +
+ "</data>\n");
+ }
+
+ /**
+ * Tests the reader & writer behavior when a column name contains an invalid character.
+ */
+ public void testColumnNameContainsInvalidCharacters() throws Exception
+ {
+ Database model = readModel(
+ "<?xml version='1.0' encoding='UTF-8'?>\n"+
+ "<database xmlns='" + DatabaseIO.DDLUTILS_NAMESPACE + "' name='test'>\n" +
+ " <table name='test'>\n"+
+ " <column name='id' type='INTEGER' primaryKey='true' required='true'/>\n"+
+ " <column name='value' type='VARCHAR' size='50' required='true'/>\n"+
+ " </table>\n"+
+ "</database>");
+ String testedValue = "the\u0000value";
+
+ SqlDynaBean bean = (SqlDynaBean)model.createDynaBeanFor(model.getTable(0));
+
+ bean.set("id", new Integer(1));
+ bean.set("value", testedValue);
+
+ roundtripTest(model, bean, "UTF-8",
+ "<?xml version='1.0' encoding='UTF-8'?>\n" +
+ "<data>\n" +
+ " <test id=\"1\">\n" +
+ " <value " + DatabaseIO.BASE64_ATTR_NAME + "=\"true\">" + new String(Base64.encodeBase64(testedValue.getBytes("UTF-8")), "UTF-8") + "</value>\n" +
+ " </test>\n" +
+ "</data>\n");
+ }
+
+ /**
+ * Tests the reader & writer behavior when a column value contains an invalid character.
+ */
+ public void testColumnValueContainsInvalidCharacters() throws Exception
+ {
+ Database model = new Database("test");
+ Table table = new Table();
+ Column idColumn = new Column();
+ Column valueColumn = new Column();
+ String columnName = "the\u0000value";
+
+ idColumn.setName("id");
+ idColumn.setType("INTEGER");
+ idColumn.setPrimaryKey(true);
+ idColumn.setRequired(true);
+ valueColumn.setName(columnName);
+ valueColumn.setType("VARCHAR");
+ valueColumn.setSize("50");
+ valueColumn.setRequired(true);
+ table.setName("test");
+ table.addColumn(idColumn);
+ table.addColumn(valueColumn);
+ model.addTable(table);
+
+ SqlDynaBean bean = (SqlDynaBean)model.createDynaBeanFor(model.getTable(0));
+ String testedValue = "Some Text";
+
+ bean.set("id", new Integer(1));
+ bean.set(columnName, testedValue);
+
+ roundtripTest(model, bean, "UTF-8",
+ "<?xml version='1.0' encoding='UTF-8'?>\n" +
+ "<data>\n" +
+ " <test id=\"1\">\n" +
+ " <column>\n" +
+ " <column-name " + DatabaseIO.BASE64_ATTR_NAME + "=\"true\">" + new String(Base64.encodeBase64(columnName.getBytes("UTF-8")), "UTF-8") + "</column-name>\n" +
+ " <column-value>" + testedValue + "</column-value>\n" +
+ " </column>\n" +
+ " </test>\n" +
+ "</data>\n");
+ }
+
+ /**
+ * Tests the reader & writer behavior when a column value contains the '&' character.
+ */
+ public void testColumnValueContainsAmpersand() throws Exception
+ {
+ Database model = new Database("test");
+ Table table = new Table();
+ Column idColumn = new Column();
+ Column valueColumn = new Column();
+ String columnName = "foo&bar";
+
+ idColumn.setName("id");
+ idColumn.setType("INTEGER");
+ idColumn.setPrimaryKey(true);
+ idColumn.setRequired(true);
+ valueColumn.setName(columnName);
+ valueColumn.setType("VARCHAR");
+ valueColumn.setSize("50");
+ valueColumn.setRequired(true);
+ table.setName("test");
+ table.addColumn(idColumn);
+ table.addColumn(valueColumn);
+ model.addTable(table);
+
+ SqlDynaBean bean = (SqlDynaBean)model.createDynaBeanFor(model.getTable(0));
+ String testedValue = "Some Text";
+
+ bean.set("id", new Integer(1));
+ bean.set(columnName, testedValue);
+
+ roundtripTest(model, bean, "UTF-8",
+ "<?xml version='1.0' encoding='UTF-8'?>\n" +
+ "<data>\n" +
+ " <test id=\"1\">\n" +
+ " <column column-name=\"foo&bar\">" + testedValue + "</column>\n" +
+ " </test>\n" +
+ "</data>\n");
+ }
+
+ /**
+ * Tests the reader & writer behavior when a column value contains the '<' character.
+ */
+ public void testColumnValueContainsLessCharacter() throws Exception
+ {
+ Database model = new Database("test");
+ Table table = new Table();
+ Column idColumn = new Column();
+ Column valueColumn = new Column();
+ String columnName = "foo<bar";
+
+ idColumn.setName("id");
+ idColumn.setType("INTEGER");
+ idColumn.setPrimaryKey(true);
+ idColumn.setRequired(true);
+ valueColumn.setName(columnName);
+ valueColumn.setType("VARCHAR");
+ valueColumn.setSize("50");
+ valueColumn.setRequired(true);
+ table.setName("test");
+ table.addColumn(idColumn);
+ table.addColumn(valueColumn);
+ model.addTable(table);
+
+ SqlDynaBean bean = (SqlDynaBean)model.createDynaBeanFor(model.getTable(0));
+ String testedValue = "Some Text";
+
+ bean.set("id", new Integer(1));
+ bean.set(columnName, testedValue);
+
+ roundtripTest(model, bean, "UTF-8",
+ "<?xml version='1.0' encoding='UTF-8'?>\n" +
+ "<data>\n" +
+ " <test id=\"1\">\n" +
+ " <column column-name=\"foo<bar\">" + testedValue + "</column>\n" +
+ " </test>\n" +
+ "</data>\n");
+ }
+
+ /**
+ * Tests the reader & writer behavior when a column value contains the '>' character.
+ */
+ public void testColumnValueContainsMoreCharacter() throws Exception
+ {
+ Database model = new Database("test");
+ Table table = new Table();
+ Column idColumn = new Column();
+ Column valueColumn = new Column();
+ String columnName = "foo>bar";
+
+ idColumn.setName("id");
+ idColumn.setType("INTEGER");
+ idColumn.setPrimaryKey(true);
+ idColumn.setRequired(true);
+ valueColumn.setName(columnName);
+ valueColumn.setType("VARCHAR");
+ valueColumn.setSize("50");
+ valueColumn.setRequired(true);
+ table.setName("test");
+ table.addColumn(idColumn);
+ table.addColumn(valueColumn);
+ model.addTable(table);
+
+ SqlDynaBean bean = (SqlDynaBean)model.createDynaBeanFor(model.getTable(0));
+ String testedValue = "Some Text";
+
+ bean.set("id", new Integer(1));
+ bean.set(columnName, testedValue);
+
+ roundtripTest(model, bean, "UTF-8",
+ "<?xml version='1.0' encoding='UTF-8'?>\n" +
+ "<data>\n" +
+ " <test id=\"1\">\n" +
+ " <column column-name=\"foo>bar\">" + testedValue + "</column>\n" +
+ " </test>\n" +
+ "</data>\n");
+ }
+
+ /**
+ * Tests the reader & writer behavior when a column name is 'column'.
+ */
+ public void testColumnNameIsColumn() throws Exception
+ {
+ Database model = readModel(
+ "<?xml version='1.0' encoding='UTF-8'?>\n"+
+ "<database xmlns='" + DatabaseIO.DDLUTILS_NAMESPACE + "' name='test'>\n" +
+ " <table name='test'>\n"+
+ " <column name='id' type='INTEGER' primaryKey='true' required='true'/>\n"+
+ " <column name='column' type='VARCHAR' size='50' required='true'/>\n"+
+ " </table>\n"+
+ "</database>");
+ String testedValue = "Some Text";
+
+ SqlDynaBean bean = (SqlDynaBean)model.createDynaBeanFor(model.getTable(0));
+
+ bean.set("id", new Integer(1));
+ bean.set("column", testedValue);
+
+ roundtripTest(model, bean, "UTF-8",
+ "<?xml version='1.0' encoding='UTF-8'?>\n" +
+ "<data>\n" +
+ " <test id=\"1\">\n" +
+ " <column column-name=\"column\">" + testedValue + "</column>\n" +
+ " </test>\n" +
+ "</data>\n");
+ }
+
+ /**
+ * Tests the reader & writer behavior when a column name is 'column'.
+ */
+ public void testColumnNameIsColumnName() throws Exception
+ {
+ Database model = readModel(
+ "<?xml version='1.0' encoding='UTF-8'?>\n"+
+ "<database xmlns='" + DatabaseIO.DDLUTILS_NAMESPACE + "' name='test'>\n" +
+ " <table name='test'>\n"+
+ " <column name='id' type='INTEGER' primaryKey='true' required='true'/>\n"+
+ " <column name='column-name' type='VARCHAR' size='50' required='true'/>\n"+
+ " </table>\n"+
+ "</database>");
+ String testedValue = "Some Text";
+
+ SqlDynaBean bean = (SqlDynaBean)model.createDynaBeanFor(model.getTable(0));
+
+ bean.set("id", new Integer(1));
+ bean.set("column-name", testedValue);
+
+ roundtripTest(model, bean, "UTF-8",
+ "<?xml version='1.0' encoding='UTF-8'?>\n" +
+ "<data>\n" +
+ " <test id=\"1\" column-name=\"" + testedValue + "\" />\n" +
+ "</data>\n");
+ }
+
+ /**
+ * Tests the reader & writer behavior when a column name is 'column'.
+ */
+ public void testColumnNameIsTableName() throws Exception
+ {
+ Database model = readModel(
+ "<?xml version='1.0' encoding='UTF-8'?>\n"+
+ "<database xmlns='" + DatabaseIO.DDLUTILS_NAMESPACE + "' name='test'>\n" +
+ " <table name='test'>\n"+
+ " <column name='id' type='INTEGER' primaryKey='true' required='true'/>\n"+
+ " <column name='the value' type='VARCHAR' size='50' required='true'/>\n"+
+ " </table>\n"+
+ "</database>");
+ String testedValue = "Some Text";
+
+ SqlDynaBean bean = (SqlDynaBean)model.createDynaBeanFor(model.getTable(0));
+
+ bean.set("id", new Integer(1));
+ bean.set("the value", testedValue);
+
+ roundtripTest(model, bean, "UTF-8",
+ "<?xml version='1.0' encoding='UTF-8'?>\n" +
+ "<data>\n" +
+ " <test id=\"1\">\n" +
+ " <column column-name=\"the value\">" + testedValue + "</column>\n" +
+ " </test>\n" +
+ "</data>\n");
+ }
+
+ /**
+ * Tests the reader & writer behavior when a column name is 'base64'.
+ */
+ public void testColumnNameIsBase64() throws Exception
+ {
+ Database model = readModel(
+ "<?xml version='1.0' encoding='UTF-8'?>\n"+
+ "<database xmlns='" + DatabaseIO.DDLUTILS_NAMESPACE + "' name='test'>\n" +
+ " <table name='test'>\n"+
+ " <column name='id' type='INTEGER' primaryKey='true' required='true'/>\n"+
+ " <column name='" + DatabaseIO.BASE64_ATTR_NAME + "' type='VARCHAR' size='50' required='true'/>\n"+
+ " </table>\n"+
+ "</database>");
+ String testedValue = "Some Text";
+
+ SqlDynaBean bean = (SqlDynaBean)model.createDynaBeanFor(model.getTable(0));
+
+ bean.set("id", new Integer(1));
+ bean.set(DatabaseIO.BASE64_ATTR_NAME, testedValue);
+
+ roundtripTest(model, bean, "UTF-8",
+ "<?xml version='1.0' encoding='UTF-8'?>\n" +
+ "<data>\n" +
+ " <test id=\"1\">\n" +
+ " <column column-name=\"" + DatabaseIO.BASE64_ATTR_NAME + "\">" + testedValue + "</column>\n" +
+ " </test>\n" +
+ "</data>\n");
+ }
}
diff --git a/src/main/java/org/apache/ddlutils/util/DatabaseTestHelper.java b/src/test/java/org/apache/ddlutils/util/DatabaseTestHelper.java
similarity index 100%
rename from src/main/java/org/apache/ddlutils/util/DatabaseTestHelper.java
rename to src/test/java/org/apache/ddlutils/util/DatabaseTestHelper.java