Author: tomdz Date: Wed Sep 5 22:12:08 2007 New Revision: 573150 URL: http://svn.apache.org/viewvc?rev=573150&view=rev Log: Added reading and writing of onUpdate and onDelete attributes from/to XML
Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/io/DatabaseIO.java db/ddlutils/trunk/src/test/org/apache/ddlutils/io/TestDatabaseIO.java 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=573150&r1=573149&r2=573150&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 Wed Sep 5 22:12:08 2007 @@ -35,7 +35,7 @@ import javax.xml.stream.XMLStreamReader; import org.apache.commons.lang.StringUtils; -import org.apache.ddlutils.DdlUtilsException; +import org.apache.ddlutils.model.CascadeActionEnum; import org.apache.ddlutils.model.Column; import org.apache.ddlutils.model.Database; import org.apache.ddlutils.model.ForeignKey; @@ -98,6 +98,10 @@ 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 onDelete attribute. */ + public static final QName QNAME_ATTRIBUTE_ON_DELETE = new QName(DDLUTILS_NAMESPACE, "onDelete"); + /** Qualified name of the onUpdate attribute. */ + public static final QName QNAME_ATTRIBUTE_ON_UPDATE = new QName(DDLUTILS_NAMESPACE, "onUpdate"); /** 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. */ @@ -160,7 +164,7 @@ * @param filename The model file name * @return The database model */ - public Database read(String filename) throws DdlUtilsException + public Database read(String filename) throws DdlUtilsXMLException { try { @@ -168,7 +172,7 @@ } catch (IOException ex) { - throw new DdlUtilsException(ex); + throw new DdlUtilsXMLException(ex); } } @@ -178,7 +182,7 @@ * @param file The model file * @return The database model */ - public Database read(File file) throws DdlUtilsException + public Database read(File file) throws DdlUtilsXMLException { try { @@ -186,7 +190,7 @@ } catch (IOException ex) { - throw new DdlUtilsException(ex); + throw new DdlUtilsXMLException(ex); } } @@ -196,7 +200,7 @@ * @param reader The reader that returns the model XML * @return The database model */ - public Database read(Reader reader) throws DdlUtilsException + public Database read(Reader reader) throws DdlUtilsXMLException { try { @@ -204,7 +208,7 @@ } catch (XMLStreamException ex) { - throw new DdlUtilsException(ex); + throw new DdlUtilsXMLException(ex); } } @@ -214,7 +218,7 @@ * @param source The input source * @return The database model */ - public Database read(InputSource source) throws DdlUtilsException + public Database read(InputSource source) throws DdlUtilsXMLException { try { @@ -222,7 +226,7 @@ } catch (XMLStreamException ex) { - throw new DdlUtilsException(ex); + throw new DdlUtilsXMLException(ex); } } @@ -246,7 +250,7 @@ * @param xmlReader The reader * @return The database model */ - private Database read(XMLStreamReader xmlReader) throws DdlUtilsException + private Database read(XMLStreamReader xmlReader) throws DdlUtilsXMLException { Database model = null; @@ -266,11 +270,11 @@ } catch (IOException ex) { - throw new DdlUtilsException(ex); + throw new DdlUtilsXMLException(ex); } catch (XMLStreamException ex) { - throw new DdlUtilsException(ex); + throw new DdlUtilsXMLException(ex); } if (model != null) { @@ -483,6 +487,14 @@ { foreignKey.setName(xmlReader.getAttributeValue(idx)); } + else if (isSameAs(attrQName, QNAME_ATTRIBUTE_ON_UPDATE)) + { + foreignKey.setOnUpdate(getAttributeValueAsCascadeEnum(xmlReader, idx)); + } + else if (isSameAs(attrQName, QNAME_ATTRIBUTE_ON_DELETE)) + { + foreignKey.setOnDelete(getAttributeValueAsCascadeEnum(xmlReader, idx)); + } } readReferenceElements(xmlReader, foreignKey); consumeRestOfElement(xmlReader); @@ -707,7 +719,7 @@ * @param attributeIdx The index of the attribute * @return The attribute's value as a boolean */ - private boolean getAttributeValueAsBoolean(XMLStreamReader xmlReader, int attributeIdx) throws DdlUtilsException + private boolean getAttributeValueAsBoolean(XMLStreamReader xmlReader, int attributeIdx) throws DdlUtilsXMLException { String value = xmlReader.getAttributeValue(attributeIdx); @@ -721,7 +733,30 @@ } else { - throw new DdlUtilsException("Illegal boolean value '" + value +"' for attribute " + xmlReader.getAttributeLocalName(attributeIdx)); + throw new DdlUtilsXMLException("Illegal boolean value '" + value +"' for attribute " + xmlReader.getAttributeLocalName(attributeIdx)); + } + } + + /** + * 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 CascadeActionEnum getAttributeValueAsCascadeEnum(XMLStreamReader xmlReader, int attributeIdx) throws DdlUtilsXMLException + { + String value = xmlReader.getAttributeValue(attributeIdx); + CascadeActionEnum enumValue = value == null ? null : CascadeActionEnum.getEnum(value.toLowerCase()); + + if (enumValue == null) + { + throw new DdlUtilsXMLException("Illegal boolean value '" + value +"' for attribute " + xmlReader.getAttributeLocalName(attributeIdx)); + } + else + { + return enumValue; } } @@ -795,7 +830,7 @@ } catch (Exception ex) { - throw new DdlUtilsException(ex); + throw new DdlUtilsXMLException(ex); } } @@ -917,6 +952,14 @@ writeElementStart(xmlWriter, QNAME_ELEMENT_FOREIGN_KEY); writeAttribute(xmlWriter, QNAME_ATTRIBUTE_FOREIGN_TABLE, foreignKey.getForeignTableName()); writeAttribute(xmlWriter, QNAME_ATTRIBUTE_NAME, foreignKey.getName()); + if (foreignKey.getOnUpdate() != CascadeActionEnum.NONE) + { + writeAttribute(xmlWriter, QNAME_ATTRIBUTE_ON_UPDATE, foreignKey.getOnUpdate().getName()); + } + if (foreignKey.getOnDelete() != CascadeActionEnum.NONE) + { + writeAttribute(xmlWriter, QNAME_ATTRIBUTE_ON_DELETE, foreignKey.getOnDelete().getName()); + } if (foreignKey.getReferenceCount() > 0) { xmlWriter.printlnIfPrettyPrinting(); Modified: db/ddlutils/trunk/src/test/org/apache/ddlutils/io/TestDatabaseIO.java URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/test/org/apache/ddlutils/io/TestDatabaseIO.java?rev=573150&r1=573149&r2=573150&view=diff ============================================================================== --- db/ddlutils/trunk/src/test/org/apache/ddlutils/io/TestDatabaseIO.java (original) +++ db/ddlutils/trunk/src/test/org/apache/ddlutils/io/TestDatabaseIO.java Wed Sep 5 22:12:08 2007 @@ -22,6 +22,7 @@ import java.io.StringReader; import java.io.StringWriter; import java.sql.Types; +import java.util.Iterator; import junit.framework.TestCase; @@ -1034,6 +1035,344 @@ " </table>\n" + "</database>\n", model); + } + + /** + * Tests a database model containing foreignkeys with onUpdate values. + */ + public void testForeignkeysWithOnUpdate() throws Exception + { + StringBuffer modelXml = new StringBuffer(); + + modelXml.append("<database name='test'>\n"); + modelXml.append(" <table name='SomeTable'\n"); + modelXml.append(" description='Some table'>\n"); + modelXml.append(" <column name='ID'\n"); + modelXml.append(" type='VARCHAR'\n"); + modelXml.append(" size='16'\n"); + modelXml.append(" primaryKey='true'\n"); + modelXml.append(" required='true'\n"); + modelXml.append(" description='The primary key'/>\n"); + modelXml.append(" </table>\n"); + modelXml.append(" <table name='AnotherTable'\n"); + modelXml.append(" description='And another table'>\n"); + modelXml.append(" <column name='Some_ID'\n"); + modelXml.append(" type='VARCHAR'\n"); + modelXml.append(" size='16'\n"); + modelXml.append(" description='The foreign key'/>\n"); + for (Iterator it = CascadeActionEnum.iterator(); it.hasNext();) + { + CascadeActionEnum enumValue = (CascadeActionEnum)it.next(); + + modelXml.append(" <foreign-key name='foreignkey "); + modelXml.append(enumValue.getName()); + modelXml.append("' foreignTable='SomeTable' onUpdate='"); + modelXml.append(enumValue.getName()); + modelXml.append("'>\n"); + modelXml.append(" <reference local='Some_ID' foreign='ID'/>\n"); + modelXml.append(" </foreign-key>\n"); + } + modelXml.append(" </table>\n"); + modelXml.append("</database>"); + + Database model = readModel(modelXml.toString()); + + assertEquals("test", model.getName()); + assertEquals(2, model.getTableCount()); + + Table someTable = model.getTable(0); + + assertEquals("SomeTable", "Some table", 1, 1, 0, 0, 0, + someTable); + assertEquals("ID", Types.VARCHAR, 16, 0, null, "The primary key", null, true, true, false, + someTable.getColumn(0)); + + Table anotherTable = model.getTable(1); + + assertEquals("AnotherTable", "And another table", 1, 0, 0, CascadeActionEnum.getEnumList().size(), 0, + anotherTable); + assertEquals("Some_ID", Types.VARCHAR, 16, 0, null, "The foreign key", null, false, false, false, + anotherTable.getColumn(0)); + + int idx = 0; + + for (Iterator it = CascadeActionEnum.iterator(); it.hasNext(); idx++) + { + CascadeActionEnum enumValue = (CascadeActionEnum)it.next(); + ForeignKey fk = anotherTable.getForeignKey(idx); + + assertEquals("foreignkey " + enumValue.getName(), enumValue, CascadeActionEnum.NONE, someTable, 1, fk); + assertEquals(anotherTable.getColumn(0), someTable.getColumn(0), fk.getReference(0)); + } + + modelXml.setLength(0); + modelXml.append("<?xml version='1.0' encoding='UTF-8'?>\n"); + modelXml.append("<database name=\"test\">\n"); + modelXml.append(" <table name=\"SomeTable\" description=\"Some table\">\n"); + modelXml.append(" <column name=\"ID\" primaryKey=\"true\" required=\"true\" type=\"VARCHAR\" size=\"16\" autoIncrement=\"false\" description=\"The primary key\" />\n"); + modelXml.append(" </table>\n"); + modelXml.append(" <table name=\"AnotherTable\" description=\"And another table\">\n"); + modelXml.append(" <column name=\"Some_ID\" primaryKey=\"false\" required=\"false\" type=\"VARCHAR\" size=\"16\" autoIncrement=\"false\" description=\"The foreign key\" />\n"); + for (Iterator it = CascadeActionEnum.iterator(); it.hasNext(); idx++) + { + CascadeActionEnum enumValue = (CascadeActionEnum)it.next(); + + modelXml.append(" <foreign-key foreignTable=\"SomeTable\" name=\"foreignkey "); + modelXml.append(enumValue.getName()); + if (enumValue != CascadeActionEnum.NONE) + { + modelXml.append("\" onUpdate=\""); + modelXml.append(enumValue.getName()); + } + modelXml.append("\">\n"); + modelXml.append(" <reference local=\"Some_ID\" foreign=\"ID\" />\n"); + modelXml.append(" </foreign-key>\n"); + } + modelXml.append(" </table>\n"); + modelXml.append("</database>\n"); + + assertEquals(modelXml.toString(), model); + } + + /** + * Tests a database model containing foreignkeys with onDelete values. + */ + public void testForeignkeysWithOnDelete() throws Exception + { + StringBuffer modelXml = new StringBuffer(); + + modelXml.append("<database name='test'>\n"); + modelXml.append(" <table name='SomeTable'\n"); + modelXml.append(" description='Some table'>\n"); + modelXml.append(" <column name='ID'\n"); + modelXml.append(" type='VARCHAR'\n"); + modelXml.append(" size='16'\n"); + modelXml.append(" primaryKey='true'\n"); + modelXml.append(" required='true'\n"); + modelXml.append(" description='The primary key'/>\n"); + modelXml.append(" </table>\n"); + modelXml.append(" <table name='AnotherTable'\n"); + modelXml.append(" description='And another table'>\n"); + modelXml.append(" <column name='Some_ID'\n"); + modelXml.append(" type='VARCHAR'\n"); + modelXml.append(" size='16'\n"); + modelXml.append(" description='The foreign key'/>\n"); + for (Iterator it = CascadeActionEnum.iterator(); it.hasNext();) + { + CascadeActionEnum enumValue = (CascadeActionEnum)it.next(); + + modelXml.append(" <foreign-key name='foreignkey "); + modelXml.append(enumValue.getName()); + modelXml.append("' foreignTable='SomeTable' onDelete='"); + modelXml.append(enumValue.getName()); + modelXml.append("'>\n"); + modelXml.append(" <reference local='Some_ID' foreign='ID'/>\n"); + modelXml.append(" </foreign-key>\n"); + } + modelXml.append(" </table>\n"); + modelXml.append("</database>"); + + Database model = readModel(modelXml.toString()); + + assertEquals("test", model.getName()); + assertEquals(2, model.getTableCount()); + + Table someTable = model.getTable(0); + + assertEquals("SomeTable", "Some table", 1, 1, 0, 0, 0, + someTable); + assertEquals("ID", Types.VARCHAR, 16, 0, null, "The primary key", null, true, true, false, + someTable.getColumn(0)); + + Table anotherTable = model.getTable(1); + + assertEquals("AnotherTable", "And another table", 1, 0, 0, CascadeActionEnum.getEnumList().size(), 0, + anotherTable); + assertEquals("Some_ID", Types.VARCHAR, 16, 0, null, "The foreign key", null, false, false, false, + anotherTable.getColumn(0)); + + int idx = 0; + + for (Iterator it = CascadeActionEnum.iterator(); it.hasNext(); idx++) + { + CascadeActionEnum enumValue = (CascadeActionEnum)it.next(); + ForeignKey fk = anotherTable.getForeignKey(idx); + + assertEquals("foreignkey " + enumValue.getName(), CascadeActionEnum.NONE, enumValue, someTable, 1, fk); + assertEquals(anotherTable.getColumn(0), someTable.getColumn(0), fk.getReference(0)); + } + + modelXml.setLength(0); + modelXml.append("<?xml version='1.0' encoding='UTF-8'?>\n"); + modelXml.append("<database name=\"test\">\n"); + modelXml.append(" <table name=\"SomeTable\" description=\"Some table\">\n"); + modelXml.append(" <column name=\"ID\" primaryKey=\"true\" required=\"true\" type=\"VARCHAR\" size=\"16\" autoIncrement=\"false\" description=\"The primary key\" />\n"); + modelXml.append(" </table>\n"); + modelXml.append(" <table name=\"AnotherTable\" description=\"And another table\">\n"); + modelXml.append(" <column name=\"Some_ID\" primaryKey=\"false\" required=\"false\" type=\"VARCHAR\" size=\"16\" autoIncrement=\"false\" description=\"The foreign key\" />\n"); + for (Iterator it = CascadeActionEnum.iterator(); it.hasNext(); idx++) + { + CascadeActionEnum enumValue = (CascadeActionEnum)it.next(); + + modelXml.append(" <foreign-key foreignTable=\"SomeTable\" name=\"foreignkey "); + modelXml.append(enumValue.getName()); + if (enumValue != CascadeActionEnum.NONE) + { + modelXml.append("\" onDelete=\""); + modelXml.append(enumValue.getName()); + } + modelXml.append("\">\n"); + modelXml.append(" <reference local=\"Some_ID\" foreign=\"ID\" />\n"); + modelXml.append(" </foreign-key>\n"); + } + modelXml.append(" </table>\n"); + modelXml.append("</database>\n"); + + assertEquals(modelXml.toString(), model); + } + + /** + * Tests a foreign key with an illegal onUpdate value. + */ + public void testForeignKeyWithIllegalOnUpdateValue() + { + try + { + readModel( + "<database name='test'>\n" + + " <table name='SomeTable'\n" + + " description='Some table'>\n" + + " <column name='ID'\n" + + " type='VARCHAR'\n" + + " size='16'\n" + + " primaryKey='true'\n" + + " required='true'\n" + + " description='The primary key'/>\n" + + " </table>\n" + + " <table name='AnotherTable'\n" + + " description='And another table'>\n" + + " <column name='Some_ID'\n" + + " type='VARCHAR'\n" + + " size='16'\n" + + " description='The foreign key'/>\n" + + " <foreign-key foreignTable='SomeTable' onUpdate='illegal'>\n" + + " <reference local='Some_ID' foreign='ID'/>\n" + + " </foreign-key>\n" + + " </table>\n" + + "</database>"); + + fail(); + } + catch (DdlUtilsXMLException ex) + {} + } + + /** + * Tests a foreign key with an empty onUpdate value. + */ + public void testForeignKeyWithEmptyOnUpdateValue() + { + try + { + readModel( + "<database name='test'>\n" + + " <table name='SomeTable'\n" + + " description='Some table'>\n" + + " <column name='ID'\n" + + " type='VARCHAR'\n" + + " size='16'\n" + + " primaryKey='true'\n" + + " required='true'\n" + + " description='The primary key'/>\n" + + " </table>\n" + + " <table name='AnotherTable'\n" + + " description='And another table'>\n" + + " <column name='Some_ID'\n" + + " type='VARCHAR'\n" + + " size='16'\n" + + " description='The foreign key'/>\n" + + " <foreign-key foreignTable='SomeTable' onUpdate=''>\n" + + " <reference local='Some_ID' foreign='ID'/>\n" + + " </foreign-key>\n" + + " </table>\n" + + "</database>"); + + fail(); + } + catch (DdlUtilsXMLException ex) + {} + } + + /** + * Tests a foreign key with an illegal onDelete value. + */ + public void testForeignKeyWithIllegalOnDeleteValue() + { + try + { + readModel( + "<database name='test'>\n" + + " <table name='SomeTable'\n" + + " description='Some table'>\n" + + " <column name='ID'\n" + + " type='VARCHAR'\n" + + " size='16'\n" + + " primaryKey='true'\n" + + " required='true'\n" + + " description='The primary key'/>\n" + + " </table>\n" + + " <table name='AnotherTable'\n" + + " description='And another table'>\n" + + " <column name='Some_ID'\n" + + " type='VARCHAR'\n" + + " size='16'\n" + + " description='The foreign key'/>\n" + + " <foreign-key foreignTable='SomeTable' onDelete='illegal'>\n" + + " <reference local='Some_ID' foreign='ID'/>\n" + + " </foreign-key>\n" + + " </table>\n" + + "</database>"); + + fail(); + } + catch (DdlUtilsXMLException ex) + {} + } + + /** + * Tests a foreign key with an empty onDelete value. + */ + public void testForeignKeyWithEmptyOnDeleteValue() + { + try + { + readModel( + "<database name='test'>\n" + + " <table name='SomeTable'\n" + + " description='Some table'>\n" + + " <column name='ID'\n" + + " type='VARCHAR'\n" + + " size='16'\n" + + " primaryKey='true'\n" + + " required='true'\n" + + " description='The primary key'/>\n" + + " </table>\n" + + " <table name='AnotherTable'\n" + + " description='And another table'>\n" + + " <column name='Some_ID'\n" + + " type='VARCHAR'\n" + + " size='16'\n" + + " description='The foreign key'/>\n" + + " <foreign-key foreignTable='SomeTable' onDelete=''>\n" + + " <reference local='Some_ID' foreign='ID'/>\n" + + " </foreign-key>\n" + + " </table>\n" + + "</database>"); + + fail(); + } + catch (DdlUtilsXMLException ex) + {} } /**