db-ddlutils-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From to...@apache.org
Subject svn commit: r572524 [1/2] - in /db/ddlutils/trunk: ./ lib/ src/java/org/apache/ddlutils/io/ src/java/org/apache/ddlutils/model/ src/test/org/apache/ddlutils/io/
Date Tue, 04 Sep 2007 04:58:11 GMT
Author: tomdz
Date: Mon Sep  3 21:58:10 2007
New Revision: 572524

URL: http://svn.apache.org/viewvc?rev=572524&view=rev
Log:
Implemented DDLUTILS-184
Created enum for the cascade settings for DDUTILS-75, and added properties to the foreign key object

Added:
    db/ddlutils/trunk/src/java/org/apache/ddlutils/io/DdlUtilsXMLException.java
    db/ddlutils/trunk/src/java/org/apache/ddlutils/io/PrettyPrintingXmlWriter.java
    db/ddlutils/trunk/src/java/org/apache/ddlutils/model/CascadeActionEnum.java
Removed:
    db/ddlutils/trunk/lib/commons-betwixt-0.8.jar
Modified:
    db/ddlutils/trunk/.classpath
    db/ddlutils/trunk/src/java/org/apache/ddlutils/io/DataWriter.java
    db/ddlutils/trunk/src/java/org/apache/ddlutils/io/DataWriterException.java
    db/ddlutils/trunk/src/java/org/apache/ddlutils/io/DatabaseIO.java
    db/ddlutils/trunk/src/java/org/apache/ddlutils/model/ForeignKey.java
    db/ddlutils/trunk/src/test/org/apache/ddlutils/io/TestDatabaseIO.java

Modified: db/ddlutils/trunk/.classpath
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/.classpath?rev=572524&r1=572523&r2=572524&view=diff
==============================================================================
--- db/ddlutils/trunk/.classpath (original)
+++ db/ddlutils/trunk/.classpath Mon Sep  3 21:58:10 2007
@@ -34,6 +34,5 @@
 	<classpathentry kind="lib" path="lib/build-only/junit-3.8.2.jar"/>
 	<classpathentry kind="lib" path="lib/stax-api-1.0.1.jar"/>
 	<classpathentry kind="lib" path="lib/log4j-1.2.8.jar"/>
-	<classpathentry kind="lib" path="lib/commons-betwixt-0.8.jar"/>
 	<classpathentry kind="output" path="target/classes"/>
 </classpath>

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/io/DataWriter.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/io/DataWriter.java?rev=572524&r1=572523&r2=572524&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/io/DataWriter.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/io/DataWriter.java Mon Sep  3 21:58:10 2007
@@ -20,7 +20,6 @@
  */
 
 import java.io.OutputStream;
-import java.io.PrintWriter;
 import java.io.Writer;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -29,10 +28,6 @@
 import java.util.List;
 import java.util.Map;
 
-import javax.xml.stream.XMLOutputFactory;
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.XMLStreamWriter;
-
 import org.apache.commons.beanutils.DynaBean;
 import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.logging.Log;
@@ -51,27 +46,17 @@
  * 
  * @version $Revision: 289996 $
  */
-public class DataWriter
+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;
-    /** The indentation string. */
-    private static final String INDENT_STRING = "  ";
 
     /** Our log. */
     private final Log _log = LogFactory.getLog(DataWriter.class);
 
     /** The converters. */
     private ConverterConfiguration _converterConf = new ConverterConfiguration();
-    /** The output stream. */
-    private PrintWriter _output;
-    /** The xml writer. */
-    private XMLStreamWriter _writer;
-    /** The output encoding. */
-    private String _encoding;
-    /** Whether we're pretty-printing. */
-    private boolean _prettyPrinting = true;
 
     /**
      * Creates a data writer instance using UTF-8 encoding.
@@ -91,26 +76,7 @@
      */
     public DataWriter(OutputStream output, String encoding) throws DataWriterException
     {
-        _output = new PrintWriter(output);
-        if ((encoding == null) || (encoding.length() == 0))
-        {
-            _encoding = "UTF-8";
-        }
-        else
-        {
-            _encoding = encoding;
-        }
-
-        try
-        {
-            XMLOutputFactory factory = XMLOutputFactory.newInstance();
-
-            _writer  = factory.createXMLStreamWriter(output, _encoding);
-        }
-        catch (XMLStreamException ex)
-        {
-            throw new DataWriterException(ex);
-        }
+        super(output, encoding);
     }
 
     /**
@@ -122,38 +88,15 @@
      */
     public DataWriter(Writer output, String encoding) throws DataWriterException
     {
-        _output   = new PrintWriter(output);
-        _encoding = encoding;
-        try
-        {
-            XMLOutputFactory factory = XMLOutputFactory.newInstance();
-
-            _writer = factory.createXMLStreamWriter(_output);
-        }
-        catch (XMLStreamException ex)
-        {
-            throw new DataWriterException(ex);
-        }
+        super(output, encoding);
     }
 
     /**
-     * Determines whether the output shall be pretty-printed.
-     *
-     * @return <code>true</code> if the output is pretty-printed
+     * {@inheritDoc}
      */
-    public boolean isPrettyPrinting()
+    protected void throwException(Exception baseEx) throws DdlUtilsXMLException
     {
-        return _prettyPrinting;
-    }
-
-    /**
-     * Specifies whether the output shall be pretty-printed.
-     *
-     * @param prettyPrinting <code>true</code> if the output is pretty-printed
-     */
-    public void setPrettyPrinting(boolean prettyPrinting)
-    {
-        _prettyPrinting = prettyPrinting;
+        throw new DataWriterException(baseEx);
     }
 
     /**
@@ -167,83 +110,25 @@
     }
 
     /**
-     * Prints a newline if we're pretty-printing.
-     */
-    private void printlnIfPrettyPrinting() throws DataWriterException
-    {
-        if (_prettyPrinting)
-        {
-            try
-            {
-                _writer.writeCharacters("\n");
-            }
-            catch (XMLStreamException ex)
-            {
-                throw new DataWriterException(ex);
-            }
-        }
-    }
-
-    /**
-     * Prints the indentation if we're pretty-printing.
-     * 
-     * @param level The indentation level
+     * Writes the start of the XML document, including the start of the outermost
+     * XML element (<code>data</code>).
      */
-    private void indentIfPrettyPrinting(int level) throws DataWriterException
+    public void writeDocumentStart() throws DdlUtilsXMLException
     {
-        if (_prettyPrinting)
-        {
-            try
-            {
-                for (int idx = 0; idx < level; idx++)
-                {
-                    _writer.writeCharacters(INDENT_STRING);
-                }
-            }
-            catch (XMLStreamException ex)
-            {
-                throw new DataWriterException(ex);
-            }
-        }
+        super.writeDocumentStart();
+        writeElementStart(null, "data");
+        printlnIfPrettyPrinting();
     }
 
     /**
-     * Writes the start of the XML document, i.e. the "<?xml?>" section and the start of the
-     * root node.
+     * Writes the end of the XML document, including the end of the outermost
+     * XML element (<code>data</code>).
      */
-    public void writeDocumentStart() throws DataWriterException
+    public void writeDocumentEnd() throws DdlUtilsXMLException
     {
-        try
-        {
-            _writer.writeStartDocument(_encoding, "1.0");
-            printlnIfPrettyPrinting();
-            _writer.writeStartElement("data");
-            printlnIfPrettyPrinting();
-        }
-        catch (XMLStreamException ex)
-        {
-            throw new DataWriterException(ex);
-        }
-    }
-
-    /**
-     * Writes the end of the XML document, i.e. end of the root node.
-     */
-    public void writeDocumentEnd() throws DataWriterException
-    {
-        try
-        {
-            _writer.writeEndElement();
-            printlnIfPrettyPrinting();
-            _writer.writeEndDocument();
-            _writer.flush();
-            _writer.close();
-            _output.close();
-        }
-        catch (XMLStreamException ex)
-        {
-            throw new DataWriterException(ex);
-        }
+        writeElementEnd();
+        printlnIfPrettyPrinting();
+        super.writeDocumentEnd();
     }
 
     /**
@@ -260,7 +145,7 @@
         try
         {
             indentIfPrettyPrinting(1);
-            _writer.writeStartElement(table.getName());
+            writeElementStart(null, table.getName());
             for (int idx = 0; idx < table.getColumnCount(); idx++)
             {
                 Column           column      = table.getColumn(idx);
@@ -290,7 +175,7 @@
                     }
                     else
                     {
-                        _writer.writeAttribute(column.getName(), valueAsText);
+                        writeAttribute(null, column.getName(), valueAsText);
                     }
                 }
             }
@@ -305,7 +190,7 @@
 
                     printlnIfPrettyPrinting();
                     indentIfPrettyPrinting(2);
-                    _writer.writeStartElement(entry.getKey().toString());
+                    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
@@ -316,14 +201,14 @@
 
                     if (writeBase64Encoded)
                     {
-                        _writer.writeAttribute(DatabaseIO.BASE64_ATTR_NAME, "true");
-                        _writer.writeCData(new String(Base64.encodeBase64(content.getBytes())));
+                        writeAttribute(null, DatabaseIO.BASE64_ATTR_NAME, "true");
+                        writeCData(new String(Base64.encodeBase64(content.getBytes())));
                     }
                     else
                     {
                         if (cutPoints.isEmpty())
                         {
-                            _writer.writeCData(content);
+                            writeCData(content);
                         }
                         else
                         {
@@ -333,27 +218,23 @@
                             {
                                 int curPos = ((Integer)cutPointIt.next()).intValue();
 
-                                _writer.writeCData(content.substring(lastPos, curPos));
+                                writeCData(content.substring(lastPos, curPos));
                                 lastPos = curPos;
                             }
                             if (lastPos < content.length())
                             {
-                                _writer.writeCData(content.substring(lastPos));
+                                writeCData(content.substring(lastPos));
                             }
                         }
                     }
 
-                    _writer.writeEndElement();
+                    writeElementEnd();
                 }
                 printlnIfPrettyPrinting();
                 indentIfPrettyPrinting(1);
             }
-            _writer.writeEndElement();
+            writeElementEnd();
             printlnIfPrettyPrinting();
-        }
-        catch (XMLStreamException ex)
-        {
-            throw new DataWriterException(ex);
         }
         catch (ConversionException ex)
         {

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/io/DataWriterException.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/io/DataWriterException.java?rev=572524&r1=572523&r2=572524&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/io/DataWriterException.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/io/DataWriterException.java Mon Sep  3 21:58:10 2007
@@ -19,14 +19,13 @@
  * under the License.
  */
 
-import org.apache.commons.lang.exception.NestableRuntimeException;
 
 /**
  * Exception generated by the {@link org.apache.ddlutils.io.DataWriter}.
  * 
  * @version $Revision: 289996 $
  */
-public class DataWriterException extends NestableRuntimeException
+public class DataWriterException extends DdlUtilsXMLException
 {
     /** Unique id for serialization purposes. */
     private static final long serialVersionUID = 6254759931565130848L;

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/io/DatabaseIO.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/io/DatabaseIO.java?rev=572524&r1=572523&r2=572524&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/io/DatabaseIO.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/io/DatabaseIO.java Mon Sep  3 21:58:10 2007
@@ -19,9 +19,9 @@
  * under the License.
  */
 
-import java.beans.IntrospectionException;
 import java.io.BufferedWriter;
 import java.io.File;
+import java.io.FileReader;
 import java.io.FileWriter;
 import java.io.IOException;
 import java.io.OutputStream;
@@ -29,13 +29,23 @@
 import java.io.Reader;
 import java.io.Writer;
 
-import org.apache.commons.betwixt.io.BeanReader;
-import org.apache.commons.betwixt.io.BeanWriter;
-import org.apache.commons.betwixt.strategy.HyphenatedNameMapper;
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import org.apache.commons.lang.StringUtils;
 import org.apache.ddlutils.DdlUtilsException;
+import org.apache.ddlutils.model.Column;
 import org.apache.ddlutils.model.Database;
+import org.apache.ddlutils.model.ForeignKey;
+import org.apache.ddlutils.model.Index;
+import org.apache.ddlutils.model.IndexColumn;
+import org.apache.ddlutils.model.NonUniqueIndex;
+import org.apache.ddlutils.model.Reference;
+import org.apache.ddlutils.model.Table;
+import org.apache.ddlutils.model.UniqueIndex;
 import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
 
 /**
  * This class provides functions to read and write database models from/to XML.
@@ -48,11 +58,62 @@
         element uses Base64 encoding. */
     public static final String BASE64_ATTR_NAME = "base64";
 
+    /** The namespace used by DdlUtils. */
+    public static final String DDLUTILS_NAMESPACE = "http://db.apache.org/torque/";
+
+    /** Qualified name of the column element. */
+    public static final QName QNAME_ELEMENT_COLUMN        = new QName(DDLUTILS_NAMESPACE, "column");
+    /** Qualified name of the database element. */
+    public static final QName QNAME_ELEMENT_DATABASE      = new QName(DDLUTILS_NAMESPACE, "database");
+    /** Qualified name of the foreign-key element. */
+    public static final QName QNAME_ELEMENT_FOREIGN_KEY   = new QName(DDLUTILS_NAMESPACE, "foreign-key");
+    /** Qualified name of the index element. */
+    public static final QName QNAME_ELEMENT_INDEX         = new QName(DDLUTILS_NAMESPACE, "index");
+    /** Qualified name of the index-column element. */
+    public static final QName QNAME_ELEMENT_INDEX_COLUMN  = new QName(DDLUTILS_NAMESPACE, "index-column");
+    /** Qualified name of the reference element. */
+    public static final QName QNAME_ELEMENT_REFERENCE     = new QName(DDLUTILS_NAMESPACE, "reference");
+    /** Qualified name of the table element. */
+    public static final QName QNAME_ELEMENT_TABLE         = new QName(DDLUTILS_NAMESPACE, "table");
+    /** Qualified name of the unique element. */
+    public static final QName QNAME_ELEMENT_UNIQUE        = new QName(DDLUTILS_NAMESPACE, "unique");
+    /** Qualified name of the unique-column element. */
+    public static final QName QNAME_ELEMENT_UNIQUE_COLUMN = new QName(DDLUTILS_NAMESPACE, "unique-column");
+
+    /** Qualified name of the autoIncrement attribute. */
+    public static final QName QNAME_ATTRIBUTE_AUTO_INCREMENT    = new QName(DDLUTILS_NAMESPACE, "autoIncrement");
+    /** Qualified name of the default attribute. */
+    public static final QName QNAME_ATTRIBUTE_DEFAULT           = new QName(DDLUTILS_NAMESPACE, "default");
+    /** Qualified name of the defaultIdMethod attribute. */
+    public static final QName QNAME_ATTRIBUTE_DEFAULT_ID_METHOD = new QName(DDLUTILS_NAMESPACE, "defaultIdMethod");
+    /** Qualified name of the description attribute. */
+    public static final QName QNAME_ATTRIBUTE_DESCRIPTION       = new QName(DDLUTILS_NAMESPACE, "description");
+    /** Qualified name of the foreign attribute. */
+    public static final QName QNAME_ATTRIBUTE_FOREIGN           = new QName(DDLUTILS_NAMESPACE, "foreign");
+    /** Qualified name of the foreignTable attribute. */
+    public static final QName QNAME_ATTRIBUTE_FOREIGN_TABLE     = new QName(DDLUTILS_NAMESPACE, "foreignTable");
+    /** Qualified name of the javaName attribute. */
+    public static final QName QNAME_ATTRIBUTE_JAVA_NAME         = new QName(DDLUTILS_NAMESPACE, "javaName");
+    /** Qualified name of the local attribute. */
+    public static final QName QNAME_ATTRIBUTE_LOCAL             = new QName(DDLUTILS_NAMESPACE, "local");
+    /** Qualified name of the name attribute. */
+    public static final QName QNAME_ATTRIBUTE_NAME              = new QName(DDLUTILS_NAMESPACE, "name");
+    /** Qualified name of the primaryKey attribute. */
+    public static final QName QNAME_ATTRIBUTE_PRIMARY_KEY       = new QName(DDLUTILS_NAMESPACE, "primaryKey");
+    /** Qualified name of the required attribute. */
+    public static final QName QNAME_ATTRIBUTE_REQUIRED          = new QName(DDLUTILS_NAMESPACE, "required");
+    /** Qualified name of the size attribute. */
+    public static final QName QNAME_ATTRIBUTE_SIZE              = new QName(DDLUTILS_NAMESPACE, "size");
+    /** Qualified name of the type attribute. */
+    public static final QName QNAME_ATTRIBUTE_TYPE              = new QName(DDLUTILS_NAMESPACE, "type");
+    /** Qualified name of the version attribute. */
+    public static final QName QNAME_ATTRIBUTE_VERSION           = new QName(DDLUTILS_NAMESPACE, "version");
+
     /** Whether to validate the XML. */
     private boolean _validateXml = true;
     /** Whether to use the internal dtd that comes with DdlUtils. */
     private boolean _useInternalDtd = true;
-
+    
     /**
      * Returns whether XML is validated upon reading it.
      * 
@@ -94,151 +155,615 @@
     }
 
     /**
-     * Returns the commons-betwixt mapping file as an {@link org.xml.sax.InputSource} object.
-     * Per default, this will be classpath resource under the path <code>/mapping.xml</code>.
-     *  
-     * @return The input source for the mapping
+     * Reads the database model contained in the specified file.
+     * 
+     * @param filename The model file name
+     * @return The database model
      */
-    protected InputSource getBetwixtMapping()
+    public Database read(String filename) throws DdlUtilsException
     {
-        return new InputSource(getClass().getResourceAsStream("/mapping.xml"));
+        try
+        {
+            return read(new FileReader(filename));
+        }
+        catch (IOException ex)
+        {
+            throw new DdlUtilsException(ex);
+        }
     }
-    
+
     /**
-     * Returns a new bean reader configured to read database models.
+     * Reads the database model contained in the specified file.
      * 
-     * @return The reader
+     * @param file The model file
+     * @return The database model
      */
-    protected BeanReader getReader() throws IntrospectionException, SAXException, IOException
+    public Database read(File file) throws DdlUtilsException
     {
-        BeanReader reader = new BeanReader();
-
-        reader.getXMLIntrospector().getConfiguration().setAttributesForPrimitives(true);
-        reader.getXMLIntrospector().getConfiguration().setWrapCollectionsInElement(false);
-        reader.getXMLIntrospector().getConfiguration().setElementNameMapper(new HyphenatedNameMapper());
-        reader.setValidating(isValidateXml());
-        if (isUseInternalDtd())
+        try
         {
-            reader.setEntityResolver(new LocalEntityResolver());
+            return read(new FileReader(file));
+        }
+        catch (IOException ex)
+        {
+            throw new DdlUtilsException(ex);
         }
-        reader.registerMultiMapping(getBetwixtMapping());
-
-        return reader;
     }
 
     /**
-     * Returns a new bean writer configured to writer database models.
+     * Reads the database model given by the reader.
      * 
-     * @param output The target output writer
-     * @return The writer
+     * @param reader The reader that returns the model XML
+     * @return The database model
      */
-    protected BeanWriter getWriter(Writer output) throws DdlUtilsException
+    public Database read(Reader reader) throws DdlUtilsException
     {
         try
         {
-            BeanWriter writer = new BeanWriter(output);
-    
-            writer.getXMLIntrospector().register(getBetwixtMapping());
-            writer.getXMLIntrospector().getConfiguration().setAttributesForPrimitives(true);
-            writer.getXMLIntrospector().getConfiguration().setWrapCollectionsInElement(false);
-            writer.getXMLIntrospector().getConfiguration().setElementNameMapper(new HyphenatedNameMapper());
-            writer.getBindingConfiguration().setMapIDs(false);
-            writer.enablePrettyPrint();
-    
-            return writer;
+            return read(getXMLInputFactory().createXMLStreamReader(reader));
         }
-        catch (Exception ex)
+        catch (XMLStreamException ex)
         {
             throw new DdlUtilsException(ex);
         }
     }
 
     /**
-     * Reads the database model contained in the specified file.
-     * 
-     * @param filename The model file name
+     * Reads the database model from the given input source.
+     *
+     * @param source The input source
      * @return The database model
      */
-    public Database read(String filename) throws DdlUtilsException
+    public Database read(InputSource source) throws DdlUtilsException
     {
-        Database model = null;
-
         try
         {
-            model = (Database)getReader().parse(filename);
+            return read(getXMLInputFactory().createXMLStreamReader(source.getCharacterStream()));
         }
-        catch (Exception ex)
+        catch (XMLStreamException ex)
         {
             throw new DdlUtilsException(ex);
         }
-        model.initialize();
-        return model;
     }
 
     /**
-     * Reads the database model contained in the specified file.
+     * Creates a new, initialized XML input factory object.
      * 
-     * @param file The model file
+     * @return The factory object
+     */
+    private XMLInputFactory getXMLInputFactory()
+    {
+        XMLInputFactory factory = XMLInputFactory.newInstance();
+
+        factory.setProperty("javax.xml.stream.isCoalescing",     Boolean.TRUE);
+        factory.setProperty("javax.xml.stream.isNamespaceAware", Boolean.TRUE);
+        return factory;
+    }
+
+    /**
+     * Reads the database model from the given XML stream reader.
+     * 
+     * @param xmlReader The reader
      * @return The database model
      */
-    public Database read(File file) throws DdlUtilsException
+    private Database read(XMLStreamReader xmlReader) throws DdlUtilsException
     {
         Database model = null;
 
         try
         {
-            model = (Database)getReader().parse(file);
+            while (xmlReader.getEventType() != XMLStreamReader.START_ELEMENT)
+            {
+                if (xmlReader.next() == XMLStreamReader.END_DOCUMENT)
+                {
+                    return null;
+                }
+            }
+            if (isSameAs(xmlReader.getName(), QNAME_ELEMENT_DATABASE))
+            {
+                model = readDatabaseElement(xmlReader);
+            }
         }
-        catch (Exception ex)
+        catch (IOException ex)
+        {
+            throw new DdlUtilsException(ex);
+        }
+        catch (XMLStreamException ex)
         {
             throw new DdlUtilsException(ex);
         }
-        model.initialize();
+        if (model != null)
+        {
+            model.initialize();
+        }
         return model;
     }
 
     /**
-     * Reads the database model given by the reader.
+     * Reads a database element from the XML stream reader.
      * 
-     * @param reader The reader that returns the model XML
-     * @return The database model
+     * @param xmlReader The reader
+     * @return The database object
      */
-    public Database read(Reader reader) throws DdlUtilsException
+    private Database readDatabaseElement(XMLStreamReader xmlReader) throws XMLStreamException, IOException
     {
-        Database model = null;
+        Database model = new Database();
 
-        try
+        for (int idx = 0; idx < xmlReader.getAttributeCount(); idx++)
         {
-            model = (Database)getReader().parse(reader);
+            QName attrQName = xmlReader.getAttributeName(idx);
+
+            if (isSameAs(attrQName, QNAME_ATTRIBUTE_NAME))
+            {
+                model.setName(xmlReader.getAttributeValue(idx));
+            }
+            else if (isSameAs(attrQName, QNAME_ATTRIBUTE_DEFAULT_ID_METHOD))
+            {
+                model.setIdMethod(xmlReader.getAttributeValue(idx));
+            }
+            else if (isSameAs(attrQName, QNAME_ATTRIBUTE_VERSION))
+            {
+                model.setVersion(xmlReader.getAttributeValue(idx));
+            }
         }
-        catch (Exception ex)
+        readTableElements(xmlReader, model);
+        consumeRestOfElement(xmlReader);
+        return model;
+    }
+
+    /**
+     * Reads table elements from the XML stream reader and adds them to the given
+     * database model.
+     * 
+     * @param xmlReader The reader
+     * @param model     The database model to add the table objects to
+     */
+    private void readTableElements(XMLStreamReader xmlReader, Database model) throws XMLStreamException, IOException
+    {
+        int eventType = XMLStreamReader.START_ELEMENT;
+
+        while (eventType != XMLStreamReader.END_ELEMENT)
         {
-            throw new DdlUtilsException(ex);
+            eventType = xmlReader.nextTag();
+            if (eventType == XMLStreamReader.START_ELEMENT)
+            {
+                if (isSameAs(xmlReader.getName(), QNAME_ELEMENT_TABLE)) {
+                    model.addTable(readTableElement(xmlReader));
+                }
+                else {
+                    readOverElement(xmlReader);
+                }
+            }
         }
-        model.initialize();
-        return model;
     }
 
     /**
-     * Reads the database model from the given input source.
-     *
-     * @param source The input source
-     * @return The database model
+     * Reads a table element from the XML stream reader.
+     * 
+     * @param xmlReader The reader
+     * @return The table object
      */
-    public Database read(InputSource source) throws DdlUtilsException
+    private Table readTableElement(XMLStreamReader xmlReader) throws XMLStreamException, IOException
     {
-        Database model = null;
+        Table table = new Table();
 
-        try
+        for (int idx = 0; idx < xmlReader.getAttributeCount(); idx++)
         {
-            model = (Database)getReader().parse(source);
+            QName attrQName = xmlReader.getAttributeName(idx);
+
+            if (isSameAs(attrQName, QNAME_ATTRIBUTE_NAME))
+            {
+                table.setName(xmlReader.getAttributeValue(idx));
+            }
+            else if (isSameAs(attrQName, QNAME_ATTRIBUTE_DESCRIPTION))
+            {
+                table.setDescription(xmlReader.getAttributeValue(idx));
+            }
         }
-        catch (Exception ex)
+        readTableSubElements(xmlReader, table);
+        consumeRestOfElement(xmlReader);
+        return table;
+    }
+
+    /**
+     * Reads table sub elements (column, foreign key, index) from the XML stream reader and adds
+     * them to the given table.
+     * 
+     * @param xmlReader The reader
+     * @param table     The table
+     */
+    private void readTableSubElements(XMLStreamReader xmlReader, Table table) throws XMLStreamException, IOException
+    {
+        int eventType = XMLStreamReader.START_ELEMENT;
+
+        while (eventType != XMLStreamReader.END_ELEMENT)
         {
-            throw new DdlUtilsException(ex);
+            eventType = xmlReader.nextTag();
+            if (eventType == XMLStreamReader.START_ELEMENT)
+            {
+                QName elemQName = xmlReader.getName();
+
+                if (isSameAs(elemQName, QNAME_ELEMENT_COLUMN))
+                {
+                    table.addColumn(readColumnElement(xmlReader));
+                }
+                else if (isSameAs(elemQName, QNAME_ELEMENT_FOREIGN_KEY))
+                {
+                    table.addForeignKey(readForeignKeyElement(xmlReader));
+                }
+                else if (isSameAs(elemQName, QNAME_ELEMENT_INDEX))
+                {
+                    table.addIndex(readIndexElement(xmlReader));
+                }
+                else if (isSameAs(elemQName, QNAME_ELEMENT_UNIQUE))
+                {
+                    table.addIndex(readUniqueElement(xmlReader));
+                }
+                else {
+                    readOverElement(xmlReader);
+                }
+            }
+        }
+    }
+
+    /**
+     * Reads a column element from the XML stream reader.
+     * 
+     * @param xmlReader The reader
+     * @return The column object
+     */
+    private Column readColumnElement(XMLStreamReader xmlReader) throws XMLStreamException, IOException
+    {
+        Column column = new Column();
+
+        for (int idx = 0; idx < xmlReader.getAttributeCount(); idx++)
+        {
+            QName attrQName = xmlReader.getAttributeName(idx);
+
+            if (isSameAs(attrQName, QNAME_ATTRIBUTE_NAME))
+            {
+                column.setName(xmlReader.getAttributeValue(idx));
+            }
+            else if (isSameAs(attrQName, QNAME_ATTRIBUTE_PRIMARY_KEY))
+            {
+                column.setPrimaryKey(getAttributeValueAsBoolean(xmlReader, idx));
+            }
+            else if (isSameAs(attrQName, QNAME_ATTRIBUTE_REQUIRED))
+            {
+                column.setRequired(getAttributeValueAsBoolean(xmlReader, idx));
+            }
+            else if (isSameAs(attrQName, QNAME_ATTRIBUTE_TYPE))
+            {
+                column.setType(xmlReader.getAttributeValue(idx));
+            }
+            else if (isSameAs(attrQName, QNAME_ATTRIBUTE_SIZE))
+            {
+                column.setSize(xmlReader.getAttributeValue(idx));
+            }
+            else if (isSameAs(attrQName, QNAME_ATTRIBUTE_DEFAULT))
+            {
+                column.setDefaultValue(xmlReader.getAttributeValue(idx));
+            }
+            else if (isSameAs(attrQName, QNAME_ATTRIBUTE_AUTO_INCREMENT))
+            {
+                column.setAutoIncrement(getAttributeValueAsBoolean(xmlReader, idx));
+            }
+            else if (isSameAs(attrQName, QNAME_ATTRIBUTE_DESCRIPTION))
+            {
+                column.setDescription(xmlReader.getAttributeValue(idx));
+            }
+            else if (isSameAs(attrQName, QNAME_ATTRIBUTE_JAVA_NAME))
+            {
+                column.setJavaName(xmlReader.getAttributeValue(idx));
+            }
+        }
+        consumeRestOfElement(xmlReader);
+        return column;
+    }
+
+    /**
+     * Reads a foreign key element from the XML stream reader.
+     * 
+     * @param xmlReader The reader
+     * @return The foreign key object
+     */
+    private ForeignKey readForeignKeyElement(XMLStreamReader xmlReader) throws XMLStreamException, IOException
+    {
+        ForeignKey foreignKey = new ForeignKey();
+
+        for (int idx = 0; idx < xmlReader.getAttributeCount(); idx++)
+        {
+            QName attrQName = xmlReader.getAttributeName(idx);
+
+            if (isSameAs(attrQName, QNAME_ATTRIBUTE_FOREIGN_TABLE))
+            {
+                foreignKey.setForeignTableName(xmlReader.getAttributeValue(idx));
+            }
+            else if (isSameAs(attrQName, QNAME_ATTRIBUTE_NAME))
+            {
+                foreignKey.setName(xmlReader.getAttributeValue(idx));
+            }
+        }
+        readReferenceElements(xmlReader, foreignKey);
+        consumeRestOfElement(xmlReader);
+        return foreignKey;
+    }
+
+    /**
+     * Reads reference elements from the XML stream reader and adds them to the given
+     * foreign key.
+     * 
+     * @param xmlReader  The reader
+     * @param foreignKey The foreign key
+     */
+    private void readReferenceElements(XMLStreamReader xmlReader, ForeignKey foreignKey) throws XMLStreamException, IOException
+    {
+        int eventType = XMLStreamReader.START_ELEMENT;
+
+        while (eventType != XMLStreamReader.END_ELEMENT)
+        {
+            eventType = xmlReader.nextTag();
+            if (eventType == XMLStreamReader.START_ELEMENT)
+            {
+                QName elemQName = xmlReader.getName();
+
+                if (isSameAs(elemQName, QNAME_ELEMENT_REFERENCE))
+                {
+                    foreignKey.addReference(readReferenceElement(xmlReader));
+                }
+                else {
+                    readOverElement(xmlReader);
+                }
+            }
+        }
+    }
+
+    /**
+     * Reads a reference element from the XML stream reader.
+     * 
+     * @param xmlReader The reader
+     * @return The reference object
+     */
+    private Reference readReferenceElement(XMLStreamReader xmlReader) throws XMLStreamException, IOException
+    {
+        Reference reference = new Reference();
+
+        for (int idx = 0; idx < xmlReader.getAttributeCount(); idx++)
+        {
+            QName attrQName = xmlReader.getAttributeName(idx);
+
+            if (isSameAs(attrQName, QNAME_ATTRIBUTE_LOCAL))
+            {
+                reference.setLocalColumnName(xmlReader.getAttributeValue(idx));
+            }
+            else if (isSameAs(attrQName, QNAME_ATTRIBUTE_FOREIGN))
+            {
+                reference.setForeignColumnName(xmlReader.getAttributeValue(idx));
+            }
+        }
+        consumeRestOfElement(xmlReader);
+        return reference;
+    }
+
+    /**
+     * Reads an index element from the XML stream reader.
+     * 
+     * @param xmlReader The reader
+     * @return The index object
+     */
+    private Index readIndexElement(XMLStreamReader xmlReader) throws XMLStreamException, IOException
+    {
+        Index index = new NonUniqueIndex();
+
+        for (int idx = 0; idx < xmlReader.getAttributeCount(); idx++)
+        {
+            QName attrQName = xmlReader.getAttributeName(idx);
+
+            if (isSameAs(attrQName, QNAME_ATTRIBUTE_NAME))
+            {
+                index.setName(xmlReader.getAttributeValue(idx));
+            }
+        }
+        readIndexColumnElements(xmlReader, index);
+        consumeRestOfElement(xmlReader);
+        return index;
+    }
+
+    /**
+     * Reads an unique index element from the XML stream reader.
+     * 
+     * @param xmlReader The reader
+     * @return The unique index object
+     */
+    private Index readUniqueElement(XMLStreamReader xmlReader) throws XMLStreamException, IOException
+    {
+        Index index = new UniqueIndex();
+
+        for (int idx = 0; idx < xmlReader.getAttributeCount(); idx++)
+        {
+            QName attrQName = xmlReader.getAttributeName(idx);
+
+            if (isSameAs(attrQName, QNAME_ATTRIBUTE_NAME))
+            {
+                index.setName(xmlReader.getAttributeValue(idx));
+            }
+        }
+        readUniqueColumnElements(xmlReader, index);
+        consumeRestOfElement(xmlReader);
+        return index;
+    }
+
+    /**
+     * Reads index column elements from the XML stream reader and adds them to the given
+     * index object.
+     * 
+     * @param xmlReader The reader
+     * @param index     The index object
+     */
+    private void readIndexColumnElements(XMLStreamReader xmlReader, Index index) throws XMLStreamException, IOException
+    {
+        int eventType = XMLStreamReader.START_ELEMENT;
+
+        while (eventType != XMLStreamReader.END_ELEMENT)
+        {
+            eventType = xmlReader.nextTag();
+            if (eventType == XMLStreamReader.START_ELEMENT)
+            {
+                QName elemQName = xmlReader.getName();
+
+                if (isSameAs(elemQName, QNAME_ELEMENT_INDEX_COLUMN))
+                {
+                    index.addColumn(readIndexColumnElement(xmlReader));
+                }
+                else {
+                    readOverElement(xmlReader);
+                }
+            }
+        }
+    }
+
+    /**
+     * Reads unique index column elements from the XML stream reader and adds them to the given
+     * index object.
+     * 
+     * @param xmlReader The reader
+     * @param index     The index object
+     */
+    private void readUniqueColumnElements(XMLStreamReader xmlReader, Index index) throws XMLStreamException, IOException
+    {
+        int eventType = XMLStreamReader.START_ELEMENT;
+
+        while (eventType != XMLStreamReader.END_ELEMENT)
+        {
+            eventType = xmlReader.nextTag();
+            if (eventType == XMLStreamReader.START_ELEMENT)
+            {
+                QName elemQName = xmlReader.getName();
+
+                if (isSameAs(elemQName, QNAME_ELEMENT_UNIQUE_COLUMN))
+                {
+                    index.addColumn(readIndexColumnElement(xmlReader));
+                }
+                else {
+                    readOverElement(xmlReader);
+                }
+            }
+        }
+    }
+
+    /**
+     * Reads an index column element from the XML stream reader.
+     * 
+     * @param xmlReader The reader
+     * @return The index column object
+     */
+    private IndexColumn readIndexColumnElement(XMLStreamReader xmlReader) throws XMLStreamException, IOException
+    {
+        IndexColumn indexColumn = new IndexColumn();
+
+        for (int idx = 0; idx < xmlReader.getAttributeCount(); idx++)
+        {
+            QName attrQName = xmlReader.getAttributeName(idx);
+
+            if (isSameAs(attrQName, QNAME_ATTRIBUTE_NAME))
+            {
+                indexColumn.setName(xmlReader.getAttributeValue(idx));
+            }
+            else if (isSameAs(attrQName, QNAME_ATTRIBUTE_SIZE))
+            {
+                indexColumn.setSize(xmlReader.getAttributeValue(idx));
+            }
+        }
+        consumeRestOfElement(xmlReader);
+        return indexColumn;
+    }
+
+    /**
+     * Compares the given qnames. This specifically ignores the namespace
+     * uri of the other qname if the namespace of the current element is
+     * empty.
+     * 
+     * @param curElemQName The qname of the current element
+     * @param qName        The qname to compare to
+     * @return <code>true</code> if they are the same
+     */
+    private boolean isSameAs(QName curElemQName, QName qName)
+    {
+        if (StringUtils.isEmpty(curElemQName.getNamespaceURI()))
+        {
+            return qName.getLocalPart().equals(curElemQName.getLocalPart());
+        }
+        else
+        {
+            return qName.equals(curElemQName);
+        }
+    }
+
+    /**
+     * Returns the value of the indicated attribute of the current element as a boolean.
+     * If the value is not a valid boolean, then an exception is thrown.
+     * 
+     * @param xmlReader    The xml reader
+     * @param attributeIdx The index of the attribute
+     * @return The attribute's value as a boolean
+     */
+    private boolean getAttributeValueAsBoolean(XMLStreamReader xmlReader, int attributeIdx) throws DdlUtilsException
+    {
+        String value = xmlReader.getAttributeValue(attributeIdx);
+
+        if ("true".equalsIgnoreCase(value))
+        {
+            return true;
+        }
+        else if ("false".equalsIgnoreCase(value))
+        {
+            return false;
+        }
+        else
+        {
+            throw new DdlUtilsException("Illegal boolean value '" + value +"' for attribute " + xmlReader.getAttributeLocalName(attributeIdx));
+        }
+    }
+
+    /**
+     * Consumes the rest of the current element. This assumes that the current XML stream
+     * event type is not START_ELEMENT.
+     * 
+     * @param reader The xml reader
+     */
+    private void consumeRestOfElement(XMLStreamReader reader) throws XMLStreamException
+    {
+        int eventType = reader.getEventType();
+
+        while ((eventType != XMLStreamReader.END_ELEMENT) && (eventType != XMLStreamReader.END_DOCUMENT))
+        {
+            eventType = reader.nextTag();
+        }
+    }
+
+    /**
+     * 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.nextTag();
+
+            if (eventType == XMLStreamReader.START_ELEMENT)
+            {
+                depth++;
+            }
+            else if (eventType == XMLStreamReader.END_ELEMENT)
+            {
+                depth--;
+            }
         }
-        model.initialize();
-        return model;
     }
 
     /**
@@ -247,7 +772,7 @@
      * @param model    The database model
      * @param filename The model file name
      */
-    public void write(Database model, String filename) throws DdlUtilsException
+    public void write(Database model, String filename) throws DdlUtilsXMLException
     {
         try
         {
@@ -276,44 +801,222 @@
 
     /**
      * Writes the database model to the given output stream. Note that this method
-     * does not flush the stream.
+     * does not flush or close the stream.
      * 
      * @param model  The database model
      * @param output The output stream
      */
-    public void write(Database model, OutputStream output) throws DdlUtilsException
+    public void write(Database model, OutputStream output) throws DdlUtilsXMLException
     {
-        write(model, getWriter(new OutputStreamWriter(output)));
+        write(model, new OutputStreamWriter(output));
     }
 
     /**
      * Writes the database model to the given output writer. Note that this method
-     * does not flush the writer.
+     * does not flush or close the writer.
      * 
      * @param model  The database model
      * @param output The output writer
      */
-    public void write(Database model, Writer output) throws DdlUtilsException
+    public void write(Database model, Writer output) throws DdlUtilsXMLException
     {
-        write(model, getWriter(output));
+        PrettyPrintingXmlWriter xmlWriter = new PrettyPrintingXmlWriter(output, "UTF-8");
+
+        xmlWriter.setDefaultNamespace(DDLUTILS_NAMESPACE);
+        xmlWriter.writeDocumentStart();
+        writeDatabaseElement(model, xmlWriter);
+        xmlWriter.writeDocumentEnd();
     }
 
     /**
-     * Internal method that writes the database model using the given bean writer.
+     * Writes the database model to the given XML writer.
      * 
-     * @param model  The database model
-     * @param writer The bean writer
+     * @param model     The database model
+     * @param xmlWriter The XML writer
      */
-    private void write(Database model, BeanWriter writer) throws DdlUtilsException
+    private void writeDatabaseElement(Database model, PrettyPrintingXmlWriter xmlWriter) throws DdlUtilsXMLException
     {
-        try
+        writeElementStart(xmlWriter, QNAME_ELEMENT_DATABASE);
+        writeAttribute(xmlWriter, QNAME_ATTRIBUTE_NAME,              model.getName());
+        writeAttribute(xmlWriter, QNAME_ATTRIBUTE_DEFAULT_ID_METHOD, model.getIdMethod());
+        writeAttribute(xmlWriter, QNAME_ATTRIBUTE_VERSION,           model.getVersion());
+        if (model.getTableCount() > 0)
         {
-            writer.writeXmlDeclaration("<?xml version=\"1.0\"?>\n<!DOCTYPE database SYSTEM \"" + LocalEntityResolver.DTD_PREFIX + "\">");
-            writer.write(model);
+            xmlWriter.printlnIfPrettyPrinting();
+            for (int idx = 0; idx < model.getTableCount(); idx++)
+            {
+                writeTableElement(model.getTable(idx), xmlWriter);
+            }
         }
-        catch (Exception ex)
+        writeElementEnd(xmlWriter);
+    }
+
+    /**
+     * Writes the table object to the given XML writer.
+     * 
+     * @param table     The table object
+     * @param xmlWriter The XML writer
+     */
+    private void writeTableElement(Table table, PrettyPrintingXmlWriter xmlWriter) throws DdlUtilsXMLException
+    {
+        xmlWriter.indentIfPrettyPrinting(1);
+        writeElementStart(xmlWriter, QNAME_ELEMENT_TABLE);
+        writeAttribute(xmlWriter, QNAME_ATTRIBUTE_NAME,        table.getName());
+        writeAttribute(xmlWriter, QNAME_ATTRIBUTE_DESCRIPTION, table.getDescription());
+        if ((table.getColumnCount() > 0) || (table.getForeignKeyCount() > 0) || (table.getIndexCount() > 0))
         {
-            throw new DdlUtilsException(ex);
+            xmlWriter.printlnIfPrettyPrinting();
+            for (int idx = 0; idx < table.getColumnCount(); idx++)
+            {
+                writeColumnElement(table.getColumn(idx), xmlWriter);
+            }
+            for (int idx = 0; idx < table.getForeignKeyCount(); idx++)
+            {
+                writeForeignKeyElement(table.getForeignKey(idx), xmlWriter);
+            }
+            for (int idx = 0; idx < table.getIndexCount(); idx++)
+            {
+                writeIndexElement(table.getIndex(idx), xmlWriter);
+            }
+            xmlWriter.indentIfPrettyPrinting(1);
+        }
+        writeElementEnd(xmlWriter);
+    }
+
+    /**
+     * Writes the column object to the given XML writer.
+     * 
+     * @param column    The column object
+     * @param xmlWriter The XML writer
+     */
+    private void writeColumnElement(Column column, PrettyPrintingXmlWriter xmlWriter) throws DdlUtilsXMLException
+    {
+        xmlWriter.indentIfPrettyPrinting(2);
+        writeElementStart(xmlWriter, QNAME_ELEMENT_COLUMN);
+        writeAttribute(xmlWriter, QNAME_ATTRIBUTE_NAME,           column.getName());
+        writeAttribute(xmlWriter, QNAME_ATTRIBUTE_PRIMARY_KEY,    String.valueOf(column.isPrimaryKey()));
+        writeAttribute(xmlWriter, QNAME_ATTRIBUTE_REQUIRED,       String.valueOf(column.isRequired()));
+        writeAttribute(xmlWriter, QNAME_ATTRIBUTE_TYPE,           column.getType());
+        writeAttribute(xmlWriter, QNAME_ATTRIBUTE_SIZE,           column.getSize());
+        writeAttribute(xmlWriter, QNAME_ATTRIBUTE_DEFAULT,        column.getDefaultValue());
+        writeAttribute(xmlWriter, QNAME_ATTRIBUTE_AUTO_INCREMENT, String.valueOf(column.isAutoIncrement()));
+        writeAttribute(xmlWriter, QNAME_ATTRIBUTE_DESCRIPTION,    column.getDescription());
+        writeAttribute(xmlWriter, QNAME_ATTRIBUTE_JAVA_NAME,      column.getJavaName());
+        writeElementEnd(xmlWriter);
+    }
+
+    /**
+     * Writes the foreign key object to the given XML writer.
+     * 
+     * @param foreignKey The foreign key object
+     * @param xmlWriter  The XML writer
+     */
+    private void writeForeignKeyElement(ForeignKey foreignKey, PrettyPrintingXmlWriter xmlWriter) throws DdlUtilsXMLException
+    {
+        xmlWriter.indentIfPrettyPrinting(2);
+        writeElementStart(xmlWriter, QNAME_ELEMENT_FOREIGN_KEY);
+        writeAttribute(xmlWriter, QNAME_ATTRIBUTE_FOREIGN_TABLE, foreignKey.getForeignTableName());
+        writeAttribute(xmlWriter, QNAME_ATTRIBUTE_NAME,          foreignKey.getName());
+        if (foreignKey.getReferenceCount() > 0)
+        {
+            xmlWriter.printlnIfPrettyPrinting();
+            for (int idx = 0; idx < foreignKey.getReferenceCount(); idx++)
+            {
+                writeReferenceElement(foreignKey.getReference(idx), xmlWriter);
+            }
+            xmlWriter.indentIfPrettyPrinting(2);
         }
+        writeElementEnd(xmlWriter);
+    }
+
+    /**
+     * Writes the reference object to the given XML writer.
+     * 
+     * @param reference The reference object
+     * @param xmlWriter The XML writer
+     */
+    private void writeReferenceElement(Reference reference, PrettyPrintingXmlWriter xmlWriter) throws DdlUtilsXMLException
+    {
+        xmlWriter.indentIfPrettyPrinting(3);
+        writeElementStart(xmlWriter, QNAME_ELEMENT_REFERENCE);
+        writeAttribute(xmlWriter, QNAME_ATTRIBUTE_LOCAL,   reference.getLocalColumnName());
+        writeAttribute(xmlWriter, QNAME_ATTRIBUTE_FOREIGN, reference.getForeignColumnName());
+        writeElementEnd(xmlWriter);
+    }
+
+    /**
+     * Writes the index object to the given XML writer.
+     * 
+     * @param index     The index object
+     * @param xmlWriter The XML writer
+     */
+    private void writeIndexElement(Index index, PrettyPrintingXmlWriter xmlWriter) throws DdlUtilsXMLException
+    {
+        xmlWriter.indentIfPrettyPrinting(2);
+        writeElementStart(xmlWriter, index.isUnique() ? QNAME_ELEMENT_UNIQUE : QNAME_ELEMENT_INDEX);
+        writeAttribute(xmlWriter, QNAME_ATTRIBUTE_NAME, index.getName());
+        if (index.getColumnCount() > 0)
+        {
+            xmlWriter.printlnIfPrettyPrinting();
+            for (int idx = 0; idx < index.getColumnCount(); idx++)
+            {
+                writeIndexColumnElement(index.getColumn(idx), index.isUnique(), xmlWriter);
+            }
+            xmlWriter.indentIfPrettyPrinting(2);
+        }
+        writeElementEnd(xmlWriter);
+    }
+
+    /**
+     * Writes the index column object to the given XML writer.
+     * 
+     * @param indexColumn The index column object
+     * @param isUnique    Whether the index that the index column belongs to, is unique
+     * @param xmlWriter   The XML writer
+     */
+    private void writeIndexColumnElement(IndexColumn indexColumn, boolean isUnique, PrettyPrintingXmlWriter xmlWriter) throws DdlUtilsXMLException
+    {
+        xmlWriter.indentIfPrettyPrinting(3);
+        writeElementStart(xmlWriter, isUnique ? QNAME_ELEMENT_UNIQUE_COLUMN : QNAME_ELEMENT_INDEX_COLUMN);
+        writeAttribute(xmlWriter, QNAME_ATTRIBUTE_NAME, indexColumn.getName());
+        writeAttribute(xmlWriter, QNAME_ATTRIBUTE_SIZE, indexColumn.getSize());
+        writeElementEnd(xmlWriter);
+    }
+
+    /**
+     * Writes the start of the specified XML element to the given XML writer.
+     * 
+     * @param xmlWriter The xml writer
+     * @param qName     The qname of the XML element
+     */
+    private void writeElementStart(PrettyPrintingXmlWriter xmlWriter, QName qName) throws DdlUtilsXMLException
+    {
+        xmlWriter.writeElementStart(null, qName.getLocalPart());
+    }
+
+    /**
+     * Writes an attribute to the given XML writer.
+     * 
+     * @param xmlWriter The xml writer
+     * @param qName     The qname of the attribute
+     * @param value     The value; if empty, then nothing is written
+     */
+    private void writeAttribute(PrettyPrintingXmlWriter xmlWriter, QName qName, String value) throws DdlUtilsXMLException
+    {
+        if (!StringUtils.isEmpty(value))
+        {
+            xmlWriter.writeAttribute(null, qName.getLocalPart(), value);
+        }
+    }
+
+    /**
+     * Writes the end of the current XML element to the given XML writer.
+     * 
+     * @param xmlWriter The xml writer
+     */
+    private void writeElementEnd(PrettyPrintingXmlWriter xmlWriter) throws DdlUtilsXMLException
+    {
+        xmlWriter.writeElementEnd();
+        xmlWriter.printlnIfPrettyPrinting();
     }
 }

Added: db/ddlutils/trunk/src/java/org/apache/ddlutils/io/DdlUtilsXMLException.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/io/DdlUtilsXMLException.java?rev=572524&view=auto
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/io/DdlUtilsXMLException.java (added)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/io/DdlUtilsXMLException.java Mon Sep  3 21:58:10 2007
@@ -0,0 +1,72 @@
+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.DdlUtilsException;
+
+/**
+ * Base class for exceptions generated by DdlUtils when handling XML.
+ * 
+ * @version $Revision: $
+ */
+public class DdlUtilsXMLException extends DdlUtilsException
+{
+    /** Unique id for serialization purposes. */
+    private static final long serialVersionUID = 3464139163788952051L;
+
+    /**
+     * Creates a new exception object.
+     */
+    public DdlUtilsXMLException()
+    {
+        super();
+    }
+
+    /**
+     * Creates a new exception object.
+     * 
+     * @param message The exception message
+     */
+    public DdlUtilsXMLException(String message)
+    {
+        super(message);
+    }
+
+    /**
+     * Creates a new exception object.
+     * 
+     * @param baseEx The base exception
+     */
+    public DdlUtilsXMLException(Throwable baseEx)
+    {
+        super(baseEx);
+    }
+
+    /**
+     * Creates a new exception object.
+     * 
+     * @param message The exception message
+     * @param baseEx  The base exception
+     */
+    public DdlUtilsXMLException(String message, Throwable baseEx)
+    {
+        super(message, baseEx);
+    }
+}

Added: db/ddlutils/trunk/src/java/org/apache/ddlutils/io/PrettyPrintingXmlWriter.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/io/PrettyPrintingXmlWriter.java?rev=572524&view=auto
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/io/PrettyPrintingXmlWriter.java (added)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/io/PrettyPrintingXmlWriter.java Mon Sep  3 21:58:10 2007
@@ -0,0 +1,318 @@
+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.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.Writer;
+
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+/**
+ * Helper class that writes XML data with or without pretty printing.
+ * 
+ * @version $Revision: $
+ */
+public class PrettyPrintingXmlWriter
+{
+    /** The indentation string. */
+    private static final String INDENT_STRING = "  ";
+
+    /** The output stream. */
+    private PrintWriter _output;
+    /** The xml writer. */
+    private XMLStreamWriter _writer;
+    /** The output encoding. */
+    private String _encoding;
+    /** Whether we're pretty-printing. */
+    private boolean _prettyPrinting = true;
+
+    /**
+     * Creates a xml writer instance using UTF-8 encoding.
+     * 
+     * @param output The target to write the data XML to
+     */
+    public PrettyPrintingXmlWriter(OutputStream output) throws DdlUtilsXMLException
+    {
+        this(output, null);
+    }
+
+    /**
+     * Creates a xml writer instance.
+     * 
+     * @param output   The target to write the data XML to
+     * @param encoding The encoding of the XML file
+     */
+    public PrettyPrintingXmlWriter(OutputStream output, String encoding) throws DdlUtilsXMLException
+    {
+        _output = new PrintWriter(output);
+        if ((encoding == null) || (encoding.length() == 0))
+        {
+            _encoding = "UTF-8";
+        }
+        else
+        {
+            _encoding = encoding;
+        }
+
+        try
+        {
+            XMLOutputFactory factory = XMLOutputFactory.newInstance();
+
+            _writer  = factory.createXMLStreamWriter(output, _encoding);
+        }
+        catch (XMLStreamException ex)
+        {
+            throwException(ex);
+        }
+    }
+
+    /**
+     * Creates a xml writer instance using the specified writer. Note that the writer
+     * needs to be configured using the specified encoding.
+     * 
+     * @param output   The target to write the data XML to
+     * @param encoding The encoding of the writer
+     */
+    public PrettyPrintingXmlWriter(Writer output, String encoding) throws DdlUtilsXMLException
+    {
+        _output   = new PrintWriter(output);
+        _encoding = encoding;
+        try
+        {
+            XMLOutputFactory factory = XMLOutputFactory.newInstance();
+
+            _writer = factory.createXMLStreamWriter(_output);
+        }
+        catch (XMLStreamException ex)
+        {
+            throwException(ex);
+        }
+    }
+
+    /**
+     * Rethrows the given exception, wrapped in a {@link DdlUtilsXMLException}. This
+     * method allows subclasses to throw their own subclasses of this exception.
+     * 
+     * @param baseEx The original exception
+     * @throws DdlUtilsXMLException The wrapped exception
+     */
+    protected void throwException(Exception baseEx) throws DdlUtilsXMLException
+    {
+        throw new DdlUtilsXMLException(baseEx);
+    }
+
+    /**
+     * Determines whether the output shall be pretty-printed.
+     *
+     * @return <code>true</code> if the output is pretty-printed
+     */
+    public boolean isPrettyPrinting()
+    {
+        return _prettyPrinting;
+    }
+
+    /**
+     * Specifies whether the output shall be pretty-printed.
+     *
+     * @param prettyPrinting <code>true</code> if the output is pretty-printed
+     */
+    public void setPrettyPrinting(boolean prettyPrinting)
+    {
+        _prettyPrinting = prettyPrinting;
+    }
+
+    /**
+     * Sets the default namespace.
+     * 
+     * @param uri The namespace uri
+     */
+    public void setDefaultNamespace(String uri) throws DdlUtilsXMLException
+    {
+        try
+        {
+            _writer.setDefaultNamespace(uri);
+        }
+        catch (XMLStreamException ex)
+        {
+            throwException(ex);
+        }
+    }
+    
+    /**
+     * Prints a newline if we're pretty-printing.
+     */
+    public void printlnIfPrettyPrinting() throws DdlUtilsXMLException
+    {
+        if (_prettyPrinting)
+        {
+            try
+            {
+                _writer.writeCharacters("\n");
+            }
+            catch (XMLStreamException ex)
+            {
+                throwException(ex);
+            }
+        }
+    }
+
+    /**
+     * Prints the indentation if we're pretty-printing.
+     * 
+     * @param level The indentation level
+     */
+    public void indentIfPrettyPrinting(int level) throws DdlUtilsXMLException
+    {
+        if (_prettyPrinting)
+        {
+            try
+            {
+                for (int idx = 0; idx < level; idx++)
+                {
+                    _writer.writeCharacters(INDENT_STRING);
+                }
+            }
+            catch (XMLStreamException ex)
+            {
+                throwException(ex);
+            }
+        }
+    }
+
+    /**
+     * Writes the start of the XML document, i.e. the "<?xml?>" section and the start of the
+     * root node.
+     */
+    public void writeDocumentStart() throws DdlUtilsXMLException
+    {
+        try
+        {
+            _writer.writeStartDocument(_encoding, "1.0");
+            printlnIfPrettyPrinting();
+        }
+        catch (XMLStreamException ex)
+        {
+            throwException(ex);
+        }
+    }
+
+    /**
+     * Writes the end of the XML document, i.e. end of the root node.
+     */
+    public void writeDocumentEnd() throws DdlUtilsXMLException
+    {
+        try
+        {
+            _writer.writeEndDocument();
+            _writer.flush();
+            _writer.close();
+        }
+        catch (XMLStreamException ex)
+        {
+            throwException(ex);
+        }
+    }
+
+    /**
+     * Writes the start of the indicated XML element.
+     * 
+     * @param namespaceUri The namespace uri, can be <code>null</code>
+     * @param localPart    The local part of the element's qname
+     */
+    public void writeElementStart(String namespaceUri, String localPart) throws DdlUtilsXMLException
+    {
+        try
+        {
+            if (namespaceUri == null)
+            {
+                _writer.writeStartElement(localPart);
+            }
+            else
+            {
+                _writer.writeStartElement(namespaceUri, localPart);
+            }
+        }
+        catch (XMLStreamException ex)
+        {
+            throwException(ex);
+        }
+    }
+
+    /**
+     * Writes the end of the current XML element.
+     */
+    public void writeElementEnd() throws DdlUtilsXMLException
+    {
+        try
+        {
+            _writer.writeEndElement();
+        }
+        catch (XMLStreamException ex)
+        {
+            throwException(ex);
+        }
+    }
+
+    /**
+     * Writes an XML attribute.
+     * 
+     * @param namespaceUri The namespace uri, can be <code>null</code>
+     * @param localPart    The local part of the attribute's qname
+     * @param value        The value; if <code>null</code> then no attribute is written
+     */
+    public void writeAttribute(String namespaceUri, String localPart, String value) throws DdlUtilsXMLException
+    {
+        try
+        {
+            if (namespaceUri == null)
+            {
+                _writer.writeAttribute(localPart, value);
+            }
+            else
+            {
+                _writer.writeAttribute(namespaceUri, localPart, value);
+            }
+        }
+        catch (XMLStreamException ex)
+        {
+            throwException(ex);
+        }
+    }
+
+    /**
+     * Writes a CDATA segment.
+     * 
+     * @param data The data to write
+     */
+    public void writeCData(String data) throws DdlUtilsXMLException
+    {
+        try
+        {
+            _writer.writeCData(data);
+        }
+        catch (XMLStreamException ex)
+        {
+            throwException(ex);
+        }
+    }
+}

Added: db/ddlutils/trunk/src/java/org/apache/ddlutils/model/CascadeActionEnum.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/model/CascadeActionEnum.java?rev=572524&view=auto
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/model/CascadeActionEnum.java (added)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/model/CascadeActionEnum.java Mon Sep  3 21:58:10 2007
@@ -0,0 +1,125 @@
+package org.apache.ddlutils.model;
+
+/*
+ * 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 java.util.Map;
+
+import org.apache.commons.lang.enums.ValuedEnum;
+
+/**
+ * Represents the different cascade actions for {@link ForeignKey#onDelete} and
+ * {@link ForeignKey#onUdate}.
+ * 
+ * @version $Revision: $
+ */
+public class CascadeActionEnum extends ValuedEnum
+{
+    /** The integer value for the enum value for a cascading change. */
+    public static final int VALUE_CASCADE  = 1;
+    /** The integer value for the enum value for a set-null change. */
+    public static final int VALUE_SETNULL  = 2;
+    /** The integer value for the enum value for a restrict change. */
+    public static final int VALUE_RESTRICT = 3;
+    /** The integer value for the enum value for no-change. */
+    public static final int VALUE_NONE     = 4;
+
+    /** The enum value for a cascade action which directs the database to change the value
+        of local column to the new value of the referenced column when it changes. */
+    public static final CascadeActionEnum CASCADE  = new CascadeActionEnum("cascade",  VALUE_CASCADE);
+    /** The enum value for a cascade action which directs the database to set the local
+        column to null when the referenced column changes. */
+    public static final CascadeActionEnum SETNULL  = new CascadeActionEnum("setnull",  VALUE_SETNULL);
+    /** The enum value for a cascade action which directs the database to restrict the change
+        changes to the referenced column. The interpretation of this is database-dependent. */
+    public static final CascadeActionEnum RESTRICT = new CascadeActionEnum("restrict", VALUE_RESTRICT);
+    /** The enum value for a cascade action which directs the database to take do nothing
+        to the local column when the value of the referenced column changes. */
+    public static final CascadeActionEnum NONE     = new CascadeActionEnum("none",     VALUE_NONE);
+
+    /** Version id for this class as relevant for serialization. */
+    private static final long serialVersionUID = -6378050861446415790L;
+
+    /**
+     * Creates a new enum object.
+     * 
+     * @param defaultTextRep The textual representation
+     * @param value          The corresponding integer value
+     */
+    private CascadeActionEnum(String defaultTextRep, int value)
+    {
+        super(defaultTextRep, value);
+    }
+
+    /**
+     * Returns the enum value that corresponds to the given textual
+     * representation.
+     * 
+     * @param defaultTextRep The textual representation
+     * @return The enum value
+     */
+    public static CascadeActionEnum getEnum(String defaultTextRep)
+    {
+        return (CascadeActionEnum)getEnum(CascadeActionEnum.class, defaultTextRep);
+    }
+    
+    /**
+     * Returns the enum value that corresponds to the given integer
+     * representation.
+     * 
+     * @param intValue The integer value
+     * @return The enum value
+     */
+    public static CascadeActionEnum getEnum(int intValue)
+    {
+        return (CascadeActionEnum)getEnum(CascadeActionEnum.class, intValue);
+    }
+
+    /**
+     * Returns the map of enum values.
+     * 
+     * @return The map of enum values
+     */
+    public static Map getEnumMap()
+    {
+        return getEnumMap(CascadeActionEnum.class);
+    }
+
+    /**
+     * Returns a list of all enum values.
+     * 
+     * @return The list of enum values
+     */
+    public static List getEnumList()
+    {
+        return getEnumList(CascadeActionEnum.class);
+    }
+
+    /**
+     * Returns an iterator of all enum values.
+     * 
+     * @return The iterator
+     */
+    public static Iterator iterator()
+    {
+        return iterator(CascadeActionEnum.class);
+    }
+}

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/model/ForeignKey.java
URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/model/ForeignKey.java?rev=572524&r1=572523&r2=572524&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/model/ForeignKey.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/model/ForeignKey.java Mon Sep  3 21:58:10 2007
@@ -39,6 +39,10 @@
     private Table _foreignTable;
     /** The name of the foreign table. */
     private String _foreignTableName;
+    /** The action to perform when the value of the referenced column changes. */
+    private CascadeActionEnum _onUpdate = CascadeActionEnum.NONE;
+    /** The action to perform when the referenced row is deleted. */
+    private CascadeActionEnum _onDelete = CascadeActionEnum.NONE;
     /** The references between local and remote columns. */
     private ListOrderedSet _references = new ListOrderedSet();
     /** Whether this foreign key has an associated auto-generated index. */
@@ -127,6 +131,56 @@
             _foreignTable = null;
         }
         _foreignTableName = foreignTableName;
+    }
+
+    /**
+     * Returns the action for this foreignkey for when the referenced row is deleted.
+     * 
+     * @return The action
+     */
+    public CascadeActionEnum getOnDelete()
+    {
+        return _onDelete;
+    }
+
+    /**
+     * Sets the action for this foreignkey for when the referenced row is deleted.
+     * 
+     * @param onDelete The action
+     * @throws NullPointerException If <code>onDelete</code> is null
+     */
+    public void setOnDelete(CascadeActionEnum onDelete) throws NullPointerException
+    {
+        if (onDelete == null)
+        {
+            throw new NullPointerException("The onDelete action cannot be null");
+        }
+        _onDelete = onDelete;
+    }
+
+    /**
+     * Returns the action for this foreignkey for when the referenced row is changed.
+     * 
+     * @return The action
+     */
+    public CascadeActionEnum getOnUpdate()
+    {
+        return _onUpdate;
+    }
+
+    /**
+     * Sets the action for this foreignkey for when the referenced row is changed.
+     * 
+     * @param onUpdate The action
+     * @throws NullPointerException If <code>onUdate</code> is null
+     */
+    public void setOnUpdate(CascadeActionEnum onUpdate) throws NullPointerException
+    {
+        if (onUpdate == null)
+        {
+            throw new NullPointerException("The onUpdate action cannot be null");
+        }
+        _onUpdate = onUpdate;
     }
 
     /**



Mime
View raw message