diff --git a/source/java/org/alfresco/util/schemacomp/Differences.java b/source/java/org/alfresco/util/schemacomp/Differences.java
new file mode 100644
index 0000000000..668f1694d2
--- /dev/null
+++ b/source/java/org/alfresco/util/schemacomp/Differences.java
@@ -0,0 +1,33 @@
+/*
+ * 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.util.ArrayList;
+import java.util.List;
+
+/**
+ * Keeps a record of what differences, if any, exist between the two
+ * schemas being compared.
+ *
+ * @author Matt Ward
+ */
+public class Differences
+{
+ private List results = new ArrayList();
+}
diff --git a/source/java/org/alfresco/util/schemacomp/Result.java b/source/java/org/alfresco/util/schemacomp/Result.java
new file mode 100644
index 0000000000..313bac3f3e
--- /dev/null
+++ b/source/java/org/alfresco/util/schemacomp/Result.java
@@ -0,0 +1,59 @@
+/*
+ * 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.util.List;
+
+import org.alfresco.util.Pair;
+import org.alfresco.util.schemacomp.model.DbObject;
+
+/**
+ * Result of a comparison between two database objects.
+ *
+ * @author Matt Ward
+ */
+public class Result
+{
+ public enum Type { ONLY_IN_LEFT, ONLY_IN_RIGHT, IN_BOTH_NO_DIFFERENCE, IN_BOTH_BUT_DIFFERENCE };
+ private Type type;
+
+ // Field list, where differences lie - recorded for single level only, otherwise, an error deep down would end
+ // up having the whole schema as being different, but that isn't useful. During reporting, climb back up the tree
+ // to produce a path, e.g. "my_schema.my_table.my_column.nullable has differences"
+
+
+ // Could hold the two items that (may - see type above) differ?
+ // These objects are already structured, no field names required.
+ DbObject left;
+ DbObject right;
+
+ // or, could...
+ // Have differences
+
+
+ public static class DiffField
+ {
+ String leftFieldName;
+ String leftVal;
+
+ String rightFieldName;
+ String rightVal;
+ }
+
+}
diff --git a/source/java/org/alfresco/util/schemacomp/SchemaComparator.java b/source/java/org/alfresco/util/schemacomp/SchemaComparator.java
new file mode 100644
index 0000000000..adafe053f2
--- /dev/null
+++ b/source/java/org/alfresco/util/schemacomp/SchemaComparator.java
@@ -0,0 +1,75 @@
+/*
+ * 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.DbObject;
+import org.alfresco.util.schemacomp.model.Schema;
+
+/**
+ * TODO: comment me!
+ * @author Matt Ward
+ */
+public class SchemaComparator
+{
+ private Schema leftSchema;
+ private Schema rightSchema;
+
+ /**
+ * Construct a comparator to compare schemas left and right.
+ *
+ * @param left
+ * @param right
+ */
+ public SchemaComparator(Schema left, Schema right)
+ {
+ this.leftSchema = left;
+ this.rightSchema = right;
+ }
+
+ public void compare()
+ {
+ for (DbObject leftObj : leftSchema)
+ {
+ DbObject rightObj = rightSchema.get(leftObj.getIdentifier());
+ if (rightObj != null)
+ {
+ // There is an equivalent object in the right hand schema as in the left.
+ System.out.println("Both schemas have object: " + leftObj.getIdentifier() +
+ "(" + leftObj.getClass().getSimpleName() + ")");
+ }
+ else
+ {
+ // No equivalent object in the right hand schema.
+ System.out.println("No matching object in right schema: " + leftObj.getIdentifier() +
+ "(" + leftObj.getClass().getSimpleName() + ")");
+ }
+ }
+
+ // Identify objects in the right schema but not the left
+ for (DbObject rightObj : rightSchema)
+ {
+ if (!leftSchema.contains(rightObj.getIdentifier()))
+ {
+ // No equivalent object in the left hand schema.
+ System.out.println("No matching object in left schema: " + rightObj.getIdentifier() +
+ "(" + rightObj.getClass().getSimpleName() + ")");
+ }
+ }
+ }
+}
diff --git a/source/java/org/alfresco/util/schemacomp/SchemaComparatorTest.java b/source/java/org/alfresco/util/schemacomp/SchemaComparatorTest.java
new file mode 100644
index 0000000000..34c769d04a
--- /dev/null
+++ b/source/java/org/alfresco/util/schemacomp/SchemaComparatorTest.java
@@ -0,0 +1,62 @@
+/*
+ * 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.Schema;
+import org.alfresco.util.schemacomp.model.Table;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * TODO: comment me!
+ * @author Matt Ward
+ */
+public class SchemaComparatorTest
+{
+ private SchemaComparator comparator;
+ private Schema left;
+ private Schema right;
+
+ @Before
+ public void setup()
+ {
+ left = new Schema();
+ right = new Schema();
+ }
+
+ @Test
+ public void canDetermineSameTables()
+ {
+ left.put(new Table("alf_node"));
+ left.put(new Table("table_in_left"));
+ left.put(new Table("in_both_but_different"));
+ right.put(new Table("alf_node"));
+ // Note this table is in different position in the RHS list.
+ Table rightTable = new Table("in_both_but_different");
+ right.put(rightTable);
+ right.put(new Table("table_in_right"));
+
+ comparator = new SchemaComparator(left, right);
+ comparator.compare();
+ }
+}
diff --git a/source/java/org/alfresco/util/schemacomp/model/AbstractDbObject.java b/source/java/org/alfresco/util/schemacomp/model/AbstractDbObject.java
new file mode 100644
index 0000000000..ff66f88637
--- /dev/null
+++ b/source/java/org/alfresco/util/schemacomp/model/AbstractDbObject.java
@@ -0,0 +1,91 @@
+/*
+ * 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.model;
+
+/**
+ * TODO: comment me!
+ * @author Matt Ward
+ */
+public abstract class AbstractDbObject implements DbObject
+{
+ private String name;
+
+ /**
+ * Default constructor
+ */
+ public AbstractDbObject()
+ {
+ }
+
+ /**
+ * Instantiate, giving the object a name.
+ *
+ * @param name
+ */
+ public AbstractDbObject(String name)
+ {
+ this.name = name;
+ }
+
+ /**
+ * @return the name
+ */
+ public String getName()
+ {
+ return this.name;
+ }
+
+ /**
+ * @param name the name to set
+ */
+ public void setName(String name)
+ {
+ this.name = name;
+ }
+
+ @Override
+ public Object getIdentifier()
+ {
+ return getName();
+ }
+
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((this.name == null) ? 0 : this.name.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj) return true;
+ if (obj == null) return false;
+ if (getClass() != obj.getClass()) return false;
+ AbstractDbObject other = (AbstractDbObject) obj;
+ if (this.name == null)
+ {
+ if (other.name != null) return false;
+ }
+ else if (!this.name.equals(other.name)) return false;
+ return true;
+ }
+}
diff --git a/source/java/org/alfresco/util/schemacomp/model/Column.java b/source/java/org/alfresco/util/schemacomp/model/Column.java
new file mode 100644
index 0000000000..f7405d86ba
--- /dev/null
+++ b/source/java/org/alfresco/util/schemacomp/model/Column.java
@@ -0,0 +1,87 @@
+/*
+ * 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.model;
+
+/**
+ * TODO: comment me!
+ * @author Matt Ward
+ */
+public class Column extends AbstractDbObject
+{
+ private String type;
+ private boolean nullable;
+
+ /**
+ * @return the type
+ */
+ public String getType()
+ {
+ return this.type;
+ }
+
+ /**
+ * @param type the type to set
+ */
+ public void setType(String type)
+ {
+ this.type = type;
+ }
+
+ /**
+ * @return the nullable
+ */
+ public boolean isNullable()
+ {
+ return this.nullable;
+ }
+
+ /**
+ * @param nullable the nullable to set
+ */
+ public void setNullable(boolean nullable)
+ {
+ this.nullable = nullable;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + (this.nullable ? 1231 : 1237);
+ result = prime * result + ((this.type == null) ? 0 : this.type.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj) return true;
+ if (!super.equals(obj)) return false;
+ if (getClass() != obj.getClass()) return false;
+ Column other = (Column) obj;
+ if (this.nullable != other.nullable) return false;
+ if (this.type == null)
+ {
+ if (other.type != null) return false;
+ }
+ else if (!this.type.equals(other.type)) return false;
+ return true;
+ }
+}
diff --git a/source/java/org/alfresco/util/schemacomp/model/DbObject.java b/source/java/org/alfresco/util/schemacomp/model/DbObject.java
new file mode 100644
index 0000000000..3ea5c681a0
--- /dev/null
+++ b/source/java/org/alfresco/util/schemacomp/model/DbObject.java
@@ -0,0 +1,29 @@
+/*
+ * 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.model;
+
+/**
+ * All database objects to be modelled for schema comparisons must implement this interface.
+ *
+ * @author Matt Ward
+ */
+public interface DbObject
+{
+ Object getIdentifier();
+}
diff --git a/source/java/org/alfresco/util/schemacomp/model/ForeignKey.java b/source/java/org/alfresco/util/schemacomp/model/ForeignKey.java
new file mode 100644
index 0000000000..03c089fe34
--- /dev/null
+++ b/source/java/org/alfresco/util/schemacomp/model/ForeignKey.java
@@ -0,0 +1,112 @@
+/*
+ * 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.model;
+
+import java.util.List;
+
+/**
+ * TODO: comment me!
+ * @author Matt Ward
+ */
+public class ForeignKey extends AbstractDbObject
+{
+ private String localColumn;
+ private String targetTable;
+ private String targetColumn;
+
+
+ /**
+ * @return the localColumn
+ */
+ public String getLocalColumn()
+ {
+ return this.localColumn;
+ }
+ /**
+ * @param localColumn the localColumn to set
+ */
+ public void setLocalColumn(String localColumn)
+ {
+ this.localColumn = localColumn;
+ }
+ /**
+ * @return the targetTable
+ */
+ public String getTargetTable()
+ {
+ return this.targetTable;
+ }
+ /**
+ * @param targetTable the targetTable to set
+ */
+ public void setTargetTable(String targetTable)
+ {
+ this.targetTable = targetTable;
+ }
+ /**
+ * @return the targetColumn
+ */
+ public String getTargetColumn()
+ {
+ return this.targetColumn;
+ }
+ /**
+ * @param targetColumn the targetColumn to set
+ */
+ public void setTargetColumn(String targetColumn)
+ {
+ this.targetColumn = targetColumn;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + ((this.localColumn == null) ? 0 : this.localColumn.hashCode());
+ result = prime * result + ((this.targetColumn == null) ? 0 : this.targetColumn.hashCode());
+ result = prime * result + ((this.targetTable == null) ? 0 : this.targetTable.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj) return true;
+ if (!super.equals(obj)) return false;
+ if (getClass() != obj.getClass()) return false;
+ ForeignKey other = (ForeignKey) obj;
+ if (this.localColumn == null)
+ {
+ if (other.localColumn != null) return false;
+ }
+ else if (!this.localColumn.equals(other.localColumn)) return false;
+ if (this.targetColumn == null)
+ {
+ if (other.targetColumn != null) return false;
+ }
+ else if (!this.targetColumn.equals(other.targetColumn)) return false;
+ if (this.targetTable == null)
+ {
+ if (other.targetTable != null) return false;
+ }
+ else if (!this.targetTable.equals(other.targetTable)) return false;
+ return true;
+ }
+}
diff --git a/source/java/org/alfresco/util/schemacomp/model/Index.java b/source/java/org/alfresco/util/schemacomp/model/Index.java
new file mode 100644
index 0000000000..f6f9387cfc
--- /dev/null
+++ b/source/java/org/alfresco/util/schemacomp/model/Index.java
@@ -0,0 +1,83 @@
+/*
+ * 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.model;
+
+import java.util.List;
+
+/**
+ * TODO: comment me!
+ * @author Matt Ward
+ */
+public class Index extends AbstractDbObject
+{
+ private List columnNames;
+
+
+ /**
+ * @return the columnNames
+ */
+ public List getColumnNames()
+ {
+ return this.columnNames;
+ }
+
+ /**
+ * @param columnNames the columnNames to set
+ */
+ public void setColumnNames(List columnNames)
+ {
+ this.columnNames = columnNames;
+ }
+
+ /**
+ * TODO: column names should be fully qualified, OR an Index should have a table name field
+ * and the identifier should include it.
+ *
+ * @return the Index identifier
+ */
+ @Override
+ public Object getIdentifier()
+ {
+ return getColumnNames();
+ }
+
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + ((this.columnNames == null) ? 0 : this.columnNames.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj) return true;
+ if (!super.equals(obj)) return false;
+ if (getClass() != obj.getClass()) return false;
+ Index other = (Index) obj;
+ if (this.columnNames == null)
+ {
+ if (other.columnNames != null) return false;
+ }
+ else if (!this.columnNames.equals(other.columnNames)) return false;
+ return true;
+ }
+}
diff --git a/source/java/org/alfresco/util/schemacomp/model/PrimaryKey.java b/source/java/org/alfresco/util/schemacomp/model/PrimaryKey.java
new file mode 100644
index 0000000000..6c92480eb3
--- /dev/null
+++ b/source/java/org/alfresco/util/schemacomp/model/PrimaryKey.java
@@ -0,0 +1,71 @@
+/*
+ * 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.model;
+
+import java.util.List;
+
+/**
+ * TODO: comment me!
+ * @author Matt Ward
+ */
+public class PrimaryKey extends AbstractDbObject
+{
+ private List columnNames;
+
+
+ /**
+ * @return the columnNames
+ */
+ public List getColumnNames()
+ {
+ return this.columnNames;
+ }
+
+ /**
+ * @param columnNames the columnNames to set
+ */
+ public void setColumnNames(List columnNames)
+ {
+ this.columnNames = columnNames;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + ((this.columnNames == null) ? 0 : this.columnNames.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj) return true;
+ if (!super.equals(obj)) return false;
+ if (getClass() != obj.getClass()) return false;
+ PrimaryKey other = (PrimaryKey) obj;
+ if (this.columnNames == null)
+ {
+ if (other.columnNames != null) return false;
+ }
+ else if (!this.columnNames.equals(other.columnNames)) return false;
+ return true;
+ }
+}
diff --git a/source/java/org/alfresco/util/schemacomp/model/Schema.java b/source/java/org/alfresco/util/schemacomp/model/Schema.java
new file mode 100644
index 0000000000..e09084eb48
--- /dev/null
+++ b/source/java/org/alfresco/util/schemacomp/model/Schema.java
@@ -0,0 +1,91 @@
+/*
+ * 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.model;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Instances of this class will represent a database schema.
+ *
+ * @author Matt Ward
+ */
+public class
+Schema extends AbstractDbObject implements Iterable
+{
+ private final Map