From b7c32e2c92756c5cce4f0a06c271467d144a536c Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Mon, 31 Oct 2011 15:14:45 +0000 Subject: [PATCH] ALF-11032: Load file in to object graph Added facility to load an object graph from an XML input stream. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@31568 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../util/schemacomp/SchemaCompTestSuite.java | 3 +- .../schemacomp/SchemaCompTestingUtils.java | 6 + .../util/schemacomp/SchemaToXMLTest.java | 5 +- .../org/alfresco/util/schemacomp/XML.java | 46 ++++ .../alfresco/util/schemacomp/XMLToSchema.java | 220 ++++++++++++++++++ .../util/schemacomp/XMLToSchemaTest.java | 102 ++++++++ .../util/schemacomp/model/Column.java | 5 + .../util/schemacomp/model/ForeignKey.java | 6 +- .../alfresco/util/schemacomp/model/Index.java | 13 +- .../util/schemacomp/model/PrimaryKey.java | 13 +- .../util/schemacomp/model/Sequence.java | 6 + .../alfresco/util/schemacomp/model/Table.java | 11 + .../util/schemacomp/xml_to_schema_test.xml | 47 ++++ 13 files changed, 474 insertions(+), 9 deletions(-) create mode 100644 source/java/org/alfresco/util/schemacomp/XML.java create mode 100644 source/java/org/alfresco/util/schemacomp/XMLToSchema.java create mode 100644 source/java/org/alfresco/util/schemacomp/XMLToSchemaTest.java create mode 100644 source/java/org/alfresco/util/schemacomp/xml_to_schema_test.xml diff --git a/source/java/org/alfresco/util/schemacomp/SchemaCompTestSuite.java b/source/java/org/alfresco/util/schemacomp/SchemaCompTestSuite.java index 570c454001..33d505d5d2 100644 --- a/source/java/org/alfresco/util/schemacomp/SchemaCompTestSuite.java +++ b/source/java/org/alfresco/util/schemacomp/SchemaCompTestSuite.java @@ -34,7 +34,8 @@ import org.junit.runners.Suite; DefaultComparisonUtilsTest.class, SchemaComparatorTest.class, ValidatingVisitorTest.class, - SchemaToXMLTest.class + SchemaToXMLTest.class, + XMLToSchemaTest.class }) public class SchemaCompTestSuite { diff --git a/source/java/org/alfresco/util/schemacomp/SchemaCompTestingUtils.java b/source/java/org/alfresco/util/schemacomp/SchemaCompTestingUtils.java index 555df4751d..9cf7c50935 100644 --- a/source/java/org/alfresco/util/schemacomp/SchemaCompTestingUtils.java +++ b/source/java/org/alfresco/util/schemacomp/SchemaCompTestingUtils.java @@ -29,6 +29,7 @@ import org.alfresco.util.schemacomp.model.Column; import org.alfresco.util.schemacomp.model.ForeignKey; import org.alfresco.util.schemacomp.model.Index; import org.alfresco.util.schemacomp.model.PrimaryKey; +import org.alfresco.util.schemacomp.model.Sequence; import org.alfresco.util.schemacomp.model.Table; import org.apache.commons.lang.ArrayUtils; @@ -112,4 +113,9 @@ public class SchemaCompTestingUtils } return Arrays.asList(indexes); } + + public static Sequence sequence(String name) + { + return new Sequence(name); + } } diff --git a/source/java/org/alfresco/util/schemacomp/SchemaToXMLTest.java b/source/java/org/alfresco/util/schemacomp/SchemaToXMLTest.java index a25ec005ae..4e9b2f4263 100644 --- a/source/java/org/alfresco/util/schemacomp/SchemaToXMLTest.java +++ b/source/java/org/alfresco/util/schemacomp/SchemaToXMLTest.java @@ -25,6 +25,7 @@ import static org.alfresco.util.schemacomp.SchemaCompTestingUtils.fkeys; import static org.alfresco.util.schemacomp.SchemaCompTestingUtils.indexes; import static org.alfresco.util.schemacomp.SchemaCompTestingUtils.pk; import static org.alfresco.util.schemacomp.SchemaCompTestingUtils.table; +import static org.alfresco.util.schemacomp.SchemaCompTestingUtils.sequence; import static org.junit.Assert.assertEquals; import java.io.BufferedReader; @@ -65,7 +66,9 @@ public class SchemaToXMLTest "name VARCHAR2(150)"), pk("pk_node", "id"), fkeys(fk("fk_node_noderef", "nodeRef", "node", "nodeRef")), - indexes("idx_node_by_id id nodeRef")) ); + indexes("idx_node_by_id id nodeRef"))); + schema.add(sequence("node_seq")); + schema.add(sequence("content_seq")); SchemaToXML transformer = new SchemaToXML(schema, out); diff --git a/source/java/org/alfresco/util/schemacomp/XML.java b/source/java/org/alfresco/util/schemacomp/XML.java new file mode 100644 index 0000000000..7b7cd569bc --- /dev/null +++ b/source/java/org/alfresco/util/schemacomp/XML.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2005-2011 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.util.schemacomp; + +import org.alfresco.util.schemacomp.model.*; + +/** + * Constants relating to the XML representation of the schema data model. + * + * @author Matt Ward + */ +public abstract class XML +{ + public static final String EL_SCHEMA = Schema.class.getSimpleName().toLowerCase(); + public static final String EL_TABLE = Table.class.getSimpleName().toLowerCase(); + public static final String EL_COLUMN = Column.class.getSimpleName().toLowerCase(); + public static final String EL_PRIMARY_KEY = PrimaryKey.class.getSimpleName().toLowerCase(); + public static final String EL_FOREIGN_KEY = ForeignKey.class.getSimpleName().toLowerCase(); + public static final String EL_INDEX = Index.class.getSimpleName().toLowerCase(); + public static final String EL_SEQUENCE = Sequence.class.getSimpleName().toLowerCase(); + public static final String EL_TYPE = "type"; + public static final String EL_NULLABLE = "nullable"; + public static final String EL_COLUMN_NAME = "columnname"; + public static final String EL_COLUMN_NAMES = "columnnames"; + public static final String EL_LOCAL_COLUMN = "localcolumn"; + public static final String EL_TARGET_COLUMN = "targetcolumn"; + public static final String EL_TARGET_TABLE = "targettable"; + + public static final String ATTR_NAME = "name"; +} diff --git a/source/java/org/alfresco/util/schemacomp/XMLToSchema.java b/source/java/org/alfresco/util/schemacomp/XMLToSchema.java new file mode 100644 index 0000000000..75459e888b --- /dev/null +++ b/source/java/org/alfresco/util/schemacomp/XMLToSchema.java @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2005-2011 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.util.schemacomp; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Stack; + +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.alfresco.util.schemacomp.model.Column; +import org.alfresco.util.schemacomp.model.DbObject; +import org.alfresco.util.schemacomp.model.ForeignKey; +import org.alfresco.util.schemacomp.model.Index; +import org.alfresco.util.schemacomp.model.PrimaryKey; +import org.alfresco.util.schemacomp.model.Schema; +import org.alfresco.util.schemacomp.model.Sequence; +import org.alfresco.util.schemacomp.model.Table; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +/** + * Parse an XML document representing a database schema. + * + * @author Matt Ward + */ +public class XMLToSchema extends DefaultHandler +{ + private SAXParser parser; + private InputStream in; + private Schema schema; + private Stack dboStack = new Stack(); + private String lastTag; + private String lastText; + + + public XMLToSchema(InputStream in, SAXParserFactory saxParserFactory) + { + this.in = in; + try + { + parser = saxParserFactory.newSAXParser(); + } + catch (Throwable e) + { + throw new RuntimeException("Cannot create parser.", e); + } + } + + public XMLToSchema(InputStream in) + { + this(in, SAXParserFactory.newInstance()); + } + + public void parse() + { + try + { + parser.parse(in, this); + } + catch (SAXException error) + { + throw new RuntimeException("Unable to parse input stream.", error); + } + catch (IOException error) + { + throw new RuntimeException("Unable to parse input stream.", error); + } + } + + public Schema getSchema() + { + return this.schema; + } + + + @Override + public void endElement(String uri, String localName, String qName) throws SAXException + { + if (qName.equals(XML.EL_TABLE)) + { + Table table = (Table) dboStack.pop(); + schema.add(table); + } + else if (qName.equals(XML.EL_COLUMN)) + { + Column column = (Column) dboStack.pop(); + Table table = (Table) dboStack.peek(); + table.getColumns().add(column); + } + else if (qName.equals(XML.EL_PRIMARY_KEY)) + { + PrimaryKey pk = (PrimaryKey) dboStack.pop(); + Table table = (Table) dboStack.peek(); + table.setPrimaryKey(pk); + } + else if (qName.equals(XML.EL_FOREIGN_KEY)) + { + ForeignKey fk = (ForeignKey) dboStack.pop(); + Table table = (Table) dboStack.peek(); + table.getForeignKeys().add(fk); + } + else if (qName.equals(XML.EL_INDEX)) + { + Index index = (Index) dboStack.pop(); + Table table = (Table) dboStack.peek(); + table.getIndexes().add(index); + } + else if (qName.equals(XML.EL_SEQUENCE)) + { + Sequence seq = (Sequence) dboStack.pop(); + schema.add(seq); + } + } + + + + + @Override + public void startElement(String uri, String localName, String qName, Attributes atts) + throws SAXException + { + lastTag = qName; + + if (qName.equals(XML.EL_SCHEMA)) + { + schema = new Schema(atts.getValue(XML.ATTR_NAME)); + } + else if (qName.equals(XML.EL_TABLE)) + { + dboStack.push(new Table(atts.getValue(XML.ATTR_NAME))); + } + else if (qName.equals(XML.EL_COLUMN)) + { + dboStack.push(new Column(atts.getValue(XML.ATTR_NAME))); + } + else if (qName.equals(XML.EL_PRIMARY_KEY)) + { + dboStack.push(new PrimaryKey(atts.getValue(XML.ATTR_NAME))); + } + else if (qName.equals(XML.EL_FOREIGN_KEY)) + { + dboStack.push(new ForeignKey(atts.getValue(XML.ATTR_NAME))); + } + else if (qName.equals(XML.EL_INDEX)) + { + dboStack.push(new Index(atts.getValue(XML.ATTR_NAME))); + } + else if (qName.equals(XML.EL_SEQUENCE)) + { + dboStack.push(new Sequence(atts.getValue(XML.ATTR_NAME))); + } + } + + @Override + public void characters(char[] ch, int start, int length) throws SAXException + { + lastText = new String(ch, start, length).trim(); + + if (lastText.length() != 0) + { + if (lastTag.equals(XML.EL_TYPE)) + { + Column column = (Column) dboStack.peek(); + column.setType(lastText); + } + else if (lastTag.equals(XML.EL_NULLABLE)) + { + Column column = (Column) dboStack.peek(); + column.setNullable(Boolean.parseBoolean(lastText)); + } + else if (lastTag.equals(XML.EL_COLUMN_NAME)) + { + if (dboStack.peek() instanceof PrimaryKey) + { + PrimaryKey pk = (PrimaryKey) dboStack.peek(); + pk.getColumnNames().add(lastText); + } + else if (dboStack.peek() instanceof Index) + { + Index index = (Index) dboStack.peek(); + index.getColumnNames().add(lastText); + } + } + else if (lastTag.equals(XML.EL_LOCAL_COLUMN)) + { + ForeignKey fk = (ForeignKey) dboStack.peek(); + fk.setLocalColumn(lastText); + } + else if (lastTag.equals(XML.EL_TARGET_TABLE)) + { + ForeignKey fk = (ForeignKey) dboStack.peek(); + fk.setTargetTable(lastText); + } + else if (lastTag.equals(XML.EL_TARGET_COLUMN)) + { + ForeignKey fk = (ForeignKey) dboStack.peek(); + fk.setTargetColumn(lastText); + } + } + } +} diff --git a/source/java/org/alfresco/util/schemacomp/XMLToSchemaTest.java b/source/java/org/alfresco/util/schemacomp/XMLToSchemaTest.java new file mode 100644 index 0000000000..512f460499 --- /dev/null +++ b/source/java/org/alfresco/util/schemacomp/XMLToSchemaTest.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2005-2011 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.util.schemacomp; + + +import static org.junit.Assert.assertNotNull; + +import java.io.BufferedInputStream; +import java.io.InputStream; +import java.util.Iterator; + +import org.alfresco.util.schemacomp.model.DbObject; +import org.alfresco.util.schemacomp.model.Schema; +import org.alfresco.util.schemacomp.model.Sequence; +import org.alfresco.util.schemacomp.model.Table; +import org.junit.Before; +import org.junit.Test; +import static org.junit.Assert.*; + +/** + * Tests for the XMLToSchema class. + * + * @author Matt Ward + */ +public class XMLToSchemaTest +{ + private XMLToSchema xmlToSchema; + private InputStream in; + + @Before + public void setUp() throws Exception + { + in = new BufferedInputStream(getClass().getResourceAsStream("xml_to_schema_test.xml")); + xmlToSchema = new XMLToSchema(in); + } + + @Test + public void canReadSchemaXML() + { + xmlToSchema.parse(); + Schema schema = xmlToSchema.getSchema(); + + assertNotNull("A null Schema object was returned", schema); + assertEquals("alfresco", schema.getName()); + + Iterator objects = schema.iterator(); + + Table table = (Table) objects.next(); + assertEquals("node", table.getName()); + assertEquals(3, table.getColumns().size()); + + assertEquals("id", table.getColumns().get(0).getName()); + assertEquals("NUMBER(10)", table.getColumns().get(0).getType()); + assertEquals(false, table.getColumns().get(0).isNullable()); + + assertEquals("nodeRef", table.getColumns().get(1).getName()); + assertEquals("VARCHAR2(200)", table.getColumns().get(1).getType()); + assertEquals(false, table.getColumns().get(1).isNullable()); + + assertEquals("name", table.getColumns().get(2).getName()); + assertEquals("VARCHAR2(150)", table.getColumns().get(2).getType()); + assertEquals(true, table.getColumns().get(2).isNullable()); + + assertEquals("pk_node", table.getPrimaryKey().getName()); + assertEquals(1, table.getPrimaryKey().getColumnNames().size()); + assertEquals("id", table.getPrimaryKey().getColumnNames().get(0)); + + assertEquals(1, table.getForeignKeys().size()); + assertEquals("fk_node_noderef", table.getForeignKeys().get(0).getName()); + assertEquals("nodeRef", table.getForeignKeys().get(0).getLocalColumn()); + assertEquals("node", table.getForeignKeys().get(0).getTargetTable()); + assertEquals("nodeRef", table.getForeignKeys().get(0).getTargetColumn()); + + assertEquals(1, table.getIndexes().size()); + assertEquals("idx_node_by_id", table.getIndexes().get(0).getName()); + assertEquals(2, table.getIndexes().get(0).getColumnNames().size()); + assertEquals("id", table.getIndexes().get(0).getColumnNames().get(0)); + assertEquals("nodeRef", table.getIndexes().get(0).getColumnNames().get(1)); + + assertEquals("node_seq", ((Sequence) objects.next()).getName()); + assertEquals("person_seq", ((Sequence) objects.next()).getName()); + assertEquals("content_seq", ((Sequence) objects.next()).getName()); + + assertFalse("Should be no more DB objects", objects.hasNext()); + } +} diff --git a/source/java/org/alfresco/util/schemacomp/model/Column.java b/source/java/org/alfresco/util/schemacomp/model/Column.java index b5861aa116..358f7c2962 100644 --- a/source/java/org/alfresco/util/schemacomp/model/Column.java +++ b/source/java/org/alfresco/util/schemacomp/model/Column.java @@ -35,6 +35,11 @@ public class Column extends AbstractDbObject private boolean nullable; + public Column(String name) + { + super(null, name); + } + /** * Construct a Column. * diff --git a/source/java/org/alfresco/util/schemacomp/model/ForeignKey.java b/source/java/org/alfresco/util/schemacomp/model/ForeignKey.java index ecc42e2c7e..d17756e706 100644 --- a/source/java/org/alfresco/util/schemacomp/model/ForeignKey.java +++ b/source/java/org/alfresco/util/schemacomp/model/ForeignKey.java @@ -21,7 +21,6 @@ package org.alfresco.util.schemacomp.model; import org.alfresco.util.schemacomp.DbObjectVisitor; import org.alfresco.util.schemacomp.DbProperty; import org.alfresco.util.schemacomp.DiffContext; -import org.alfresco.util.schemacomp.Results; import org.alfresco.util.schemacomp.Result.Strength; @@ -38,6 +37,11 @@ public class ForeignKey extends AbstractDbObject private String targetColumn; + public ForeignKey(String name) + { + super(null, name); + } + /** * Constructor. * diff --git a/source/java/org/alfresco/util/schemacomp/model/Index.java b/source/java/org/alfresco/util/schemacomp/model/Index.java index ab5ce00617..56bf52390b 100644 --- a/source/java/org/alfresco/util/schemacomp/model/Index.java +++ b/source/java/org/alfresco/util/schemacomp/model/Index.java @@ -18,6 +18,7 @@ */ package org.alfresco.util.schemacomp.model; +import java.util.ArrayList; import java.util.List; import org.alfresco.util.schemacomp.DbObjectVisitor; @@ -32,9 +33,14 @@ import org.alfresco.util.schemacomp.Result.Strength; */ public class Index extends AbstractDbObject { - private List columnNames; + private final List columnNames = new ArrayList(); + public Index(String name) + { + super(null, name); + } + /** * @param table the parent table * @param columnNames @@ -42,7 +48,7 @@ public class Index extends AbstractDbObject public Index(Table table, String name, List columnNames) { super(table, name); - this.columnNames = columnNames; + this.columnNames.addAll(columnNames); setNameStrength(Strength.WARN); } @@ -59,7 +65,8 @@ public class Index extends AbstractDbObject */ public void setColumnNames(List columnNames) { - this.columnNames = columnNames; + this.columnNames.clear(); + this.columnNames.addAll(columnNames); } @Override diff --git a/source/java/org/alfresco/util/schemacomp/model/PrimaryKey.java b/source/java/org/alfresco/util/schemacomp/model/PrimaryKey.java index 2bb41e5fd4..9175d24cf6 100644 --- a/source/java/org/alfresco/util/schemacomp/model/PrimaryKey.java +++ b/source/java/org/alfresco/util/schemacomp/model/PrimaryKey.java @@ -18,6 +18,7 @@ */ package org.alfresco.util.schemacomp.model; +import java.util.ArrayList; import java.util.List; import org.alfresco.util.schemacomp.DbObjectVisitor; @@ -32,9 +33,14 @@ import org.alfresco.util.schemacomp.Result.Strength; */ public class PrimaryKey extends AbstractDbObject { - private List columnNames; + private final List columnNames = new ArrayList(); + public PrimaryKey(String name) + { + super(null, name); + } + /** * Constructor * @param table the parent table @@ -44,7 +50,7 @@ public class PrimaryKey extends AbstractDbObject public PrimaryKey(Table table, String name, List columnNames) { super(table, name); - this.columnNames = columnNames; + this.columnNames.addAll(columnNames); } /** @@ -60,7 +66,8 @@ public class PrimaryKey extends AbstractDbObject */ public void setColumnNames(List columnNames) { - this.columnNames = columnNames; + this.columnNames.clear(); + this.columnNames.addAll(columnNames); } @Override diff --git a/source/java/org/alfresco/util/schemacomp/model/Sequence.java b/source/java/org/alfresco/util/schemacomp/model/Sequence.java index 71ac0b80dd..6b2ebd02fc 100644 --- a/source/java/org/alfresco/util/schemacomp/model/Sequence.java +++ b/source/java/org/alfresco/util/schemacomp/model/Sequence.java @@ -28,6 +28,12 @@ import org.alfresco.util.schemacomp.DbObjectVisitor; */ public class Sequence extends AbstractDbObject { + + public Sequence(String name) + { + super(null, name); + } + public Sequence(DbObject parent, String name) { super(parent, name); diff --git a/source/java/org/alfresco/util/schemacomp/model/Table.java b/source/java/org/alfresco/util/schemacomp/model/Table.java index 65f9d17dbe..159552b469 100644 --- a/source/java/org/alfresco/util/schemacomp/model/Table.java +++ b/source/java/org/alfresco/util/schemacomp/model/Table.java @@ -39,6 +39,17 @@ public class Table extends AbstractDbObject private final List indexes = new ArrayList(); + public Table(String name) + { + super(null, name); + } + + public Table(String name, Collection columns, PrimaryKey primaryKey, + Collection foreignKeys, Collection indexes) + { + this(null, name, columns, primaryKey, foreignKeys, indexes); + } + public Table(Schema parentSchema, String name, Collection columns, PrimaryKey primaryKey, Collection foreignKeys, Collection indexes) { diff --git a/source/java/org/alfresco/util/schemacomp/xml_to_schema_test.xml b/source/java/org/alfresco/util/schemacomp/xml_to_schema_test.xml new file mode 100644 index 0000000000..9788c96a47 --- /dev/null +++ b/source/java/org/alfresco/util/schemacomp/xml_to_schema_test.xml @@ -0,0 +1,47 @@ + + + + + + + + NUMBER(10) + false + + + VARCHAR2(200) + false + + + VARCHAR2(150) + true + + + + + id + + + + + nodeRef + node + nodeRef + + + + + + id + nodeRef + + + +
+ + + +
+