diff --git a/source/java/org/alfresco/util/schemacomp/ComparisonUtils.java b/source/java/org/alfresco/util/schemacomp/ComparisonUtils.java
new file mode 100644
index 0000000000..189dac3a9a
--- /dev/null
+++ b/source/java/org/alfresco/util/schemacomp/ComparisonUtils.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;
+
+import java.util.Collection;
+
+import org.alfresco.util.schemacomp.Result.Strength;
+import org.alfresco.util.schemacomp.model.DbObject;
+
+/**
+ * Utilities for comparing data structures in the context of comparing two database schemas.
+ *
+ * @author Matt Ward
+ */
+public interface ComparisonUtils
+{
+ /**
+ * @param objToFind
+ * @return
+ */
+ DbObject findSameObjectAs(Collection extends DbObject> objects, final DbObject objToFind);
+
+ void compareSimpleCollections(Collection extends Object> leftCollection,
+ Collection extends Object> rightCollection, Differences differences,
+ Strength strength);
+
+ /**
+ * Compare collections, reporting differences using the default {@link Result.Strength}
+ *
+ * @see #compareCollections(Collection, Collection, Differences, Strength)
+ */
+ void compareCollections(Collection extends DbObject> leftCollection,
+ Collection extends DbObject> rightCollection, Differences differences);
+
+ /**
+ * Compare collections of {@link DbObject}s using their {@link DbObject#diff(DbObject, Differences)} method.
+ * Differences are reported using the specified {@link Result.Strength}.
+ *
+ * @param leftCollection
+ * @param rightCollection
+ * @param differences
+ * @param strength
+ */
+ void compareCollections(Collection extends DbObject> leftCollection,
+ Collection extends DbObject> rightCollection, Differences differences,
+ Strength strength);
+
+ /**
+ * Compare two simple objects. Differences are reported using the default Result.Strength.
+ *
+ * @see #compareSimple(Object, Object, Differences, Strength)
+ */
+ void compareSimple(Object left, Object right, Differences differences);
+
+ /**
+ * Compare two 'simple' (i.e. non-{@link DbObject} objects) using their {@link Object#equals(Object)} method
+ * to decide if there is a difference. Differences are reported using the Result.Strength specified.
+ *
+ * @param left
+ * @param right
+ * @param differences
+ * @param strength
+ */
+ void compareSimple(Object left, Object right, Differences differences, Strength strength);
+
+}
\ No newline at end of file
diff --git a/source/java/org/alfresco/util/schemacomp/DefaultComparisonUtils.java b/source/java/org/alfresco/util/schemacomp/DefaultComparisonUtils.java
new file mode 100644
index 0000000000..3c48e649e7
--- /dev/null
+++ b/source/java/org/alfresco/util/schemacomp/DefaultComparisonUtils.java
@@ -0,0 +1,197 @@
+/*
+ * 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.Collection;
+
+import org.alfresco.util.schemacomp.Result.Strength;
+import org.alfresco.util.schemacomp.Result.Where;
+import org.alfresco.util.schemacomp.model.DbObject;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.collections.Predicate;
+
+/**
+ * A collection of utility methods for determining differences between two database schemas.
+ *
+ * @author Matt Ward
+ */
+public class DefaultComparisonUtils implements ComparisonUtils
+{
+ /**
+ * @param objToFind
+ * @return
+ */
+ @Override
+ public DbObject findSameObjectAs(Collection extends DbObject> objects, final DbObject objToFind)
+ {
+ return (DbObject) CollectionUtils.find(objects, new Predicate()
+ {
+ @Override
+ public boolean evaluate(Object o)
+ {
+ DbObject object = (DbObject) o;
+ return object.sameAs(objToFind);
+ }
+ });
+ }
+
+
+ @Override
+ public void compareSimpleCollections(Collection extends Object> leftCollection,
+ Collection extends Object> rightCollection, Differences differences, Strength strength)
+ {
+ for (Object leftObj : leftCollection)
+ {
+ if (rightCollection.contains(leftObj))
+ {
+ // The same valued object in the right hand collection as in the left.
+ // Note: it isn't possible to determine a result of Where.IN_BOTH_BUT_DIFFERENCE
+ // with a 'simple' value — as there is no way of knowing if the term represents the same value
+ // (e.g. two strings {red_value, green_value}, are these meant to be the same or different?)
+ differences.add(Where.IN_BOTH_NO_DIFFERENCE, leftObj, leftObj, strength);
+ }
+ else
+ {
+ // No equivalent object in the right hand collection.
+ differences.add(Where.ONLY_IN_LEFT, leftObj, null, strength);
+ }
+ }
+
+ // Identify objects in the right collection but not the left
+ for (Object rightObj : rightCollection)
+ {
+ if (!leftCollection.contains(rightObj))
+ {
+ // No equivalent object in the left hand collection.
+ differences.add(Where.ONLY_IN_RIGHT, null, rightObj, strength);
+ }
+ }
+ }
+
+ /**
+ * Compare collections, reporting differences using the default {@link Result.Strength}
+ *
+ * @see #compareCollections(Collection, Collection, Differences, Strength)
+ */
+ @Override
+ public void compareCollections(Collection extends DbObject> leftCollection,
+ Collection extends DbObject> rightCollection, Differences differences)
+ {
+ compareCollections(leftCollection, rightCollection, differences, null);
+ }
+
+ /**
+ * Compare collections of {@link DbObject}s using their {@link DbObject#diff(DbObject, Differences)} method.
+ * Differences are reported using the specified {@link Result.Strength}.
+ *
+ * @param leftCollection
+ * @param rightCollection
+ * @param differences
+ * @param strength
+ */
+ @Override
+ public void compareCollections(Collection extends DbObject> leftCollection,
+ Collection extends DbObject> rightCollection, Differences differences, Strength strength)
+ {
+ for (DbObject leftObj : leftCollection)
+ {
+ DbObject rightObj = findSameObjectAs(rightCollection, leftObj);
+
+ if (rightObj != null)
+ {
+ // There is an equivalent object in the right hand collection as
+ // in the left.
+ leftObj.diff(rightObj, differences, strength);
+ }
+ else
+ {
+ // No equivalent object in the right hand collection.
+ differences.add(Where.ONLY_IN_LEFT, leftObj, null, strength);
+ }
+ }
+
+ // Identify objects in the right collection but not the left
+ for (DbObject rightObj : rightCollection)
+ {
+ if (!leftCollection.contains(rightObj))
+ {
+ // No equivalent object in the left hand collection.
+ differences.add(Where.ONLY_IN_RIGHT, null, rightObj, strength);
+ }
+ }
+ }
+
+ /**
+ * Compare two simple objects. Differences are reported using the default Result.Strength.
+ *
+ * @see #compareSimple(Object, Object, Differences, Strength)
+ */
+ @Override
+ public void compareSimple(Object left, Object right, Differences differences)
+ {
+ compareSimple(left, right, differences, null);
+ }
+
+ /**
+ * Compare two 'simple' (i.e. non-{@link DbObject} objects) using their {@link Object#equals(Object)} method
+ * to decide if there is a difference. Differences are reported using the Result.Strength specified.
+ *
+ * @param left
+ * @param right
+ * @param differences
+ * @param strength
+ */
+ @Override
+ public void compareSimple(Object left, Object right, Differences differences, Strength strength)
+ {
+
+ Where where = null;
+
+ if (left == right)
+ {
+ // Same object, or both nulls
+ where = Where.IN_BOTH_NO_DIFFERENCE;
+ }
+ else if (left == null)
+ {
+ // right can't be null, or left == right would have been true
+ where = Where.ONLY_IN_RIGHT;
+ }
+ else if (right == null)
+ {
+ // left can't be null, or left == right would have been true
+ where = Where.ONLY_IN_LEFT;
+ }
+ else
+ {
+ // neither are null
+ if (left.equals(right))
+ {
+ where = Where.IN_BOTH_NO_DIFFERENCE;
+ }
+ else
+ {
+ where = Where.IN_BOTH_BUT_DIFFERENCE;
+ }
+ }
+
+ differences.add(where, left, right, strength);
+ }
+}
diff --git a/source/java/org/alfresco/util/schemacomp/DefaultComparisonUtilsTest.java b/source/java/org/alfresco/util/schemacomp/DefaultComparisonUtilsTest.java
new file mode 100644
index 0000000000..b712b3ee7d
--- /dev/null
+++ b/source/java/org/alfresco/util/schemacomp/DefaultComparisonUtilsTest.java
@@ -0,0 +1,193 @@
+/*
+ * 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.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.alfresco.util.schemacomp.Result.Strength;
+import org.alfresco.util.schemacomp.Result.Where;
+import org.alfresco.util.schemacomp.model.DbObject;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+/**
+ * Tests for the SchemaUtils class.
+ *
+ * @author Matt Ward
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class DefaultComparisonUtilsTest
+{
+ private @Mock Differences differences;
+ private DefaultComparisonUtils comparisonUtils;
+
+ @Before
+ public void setUp()
+ {
+ comparisonUtils = new DefaultComparisonUtils();
+ }
+
+ @Test
+ public void compareSimple()
+ {
+ comparisonUtils.compareSimple(null, null, differences, Strength.ERROR);
+ verify(differences).add(Where.IN_BOTH_NO_DIFFERENCE, null, null, Strength.ERROR);
+
+ comparisonUtils.compareSimple("not_null_string", "not_null_string", differences, Strength.ERROR);
+ verify(differences).add(Where.IN_BOTH_NO_DIFFERENCE, "not_null_string", "not_null_string", Strength.ERROR);
+
+ comparisonUtils.compareSimple("left", "right", differences, Strength.ERROR);
+ verify(differences).add(Where.IN_BOTH_BUT_DIFFERENCE, "left", "right", Strength.ERROR);
+
+ comparisonUtils.compareSimple("left", null, differences, Strength.ERROR);
+ verify(differences).add(Where.ONLY_IN_LEFT, "left", null, Strength.ERROR);
+
+ comparisonUtils.compareSimple(null, "right", differences, Strength.ERROR);
+ verify(differences).add(Where.ONLY_IN_RIGHT, null, "right", Strength.ERROR);
+ }
+
+
+ @Test
+ public void compareCollections()
+ {
+ DbObject db1 = mock(DbObject.class);
+ when(db1.sameAs(db1)).thenReturn(true);
+ DbObject db2 = mock(DbObject.class); // only in left
+ when(db2.sameAs(db2)).thenReturn(true);
+ DbObject db3 = mock(DbObject.class); // only in right
+ when(db3.sameAs(db3)).thenReturn(true);
+ DbObject db4 = mock(DbObject.class);
+ when(db4.sameAs(db4)).thenReturn(true);
+
+ Collection left = new ArrayList();
+ Collections.addAll(left, db1, db2, db4);
+
+ Collection right = new ArrayList();
+ Collections.addAll(right, db1, db3, db4);
+
+ comparisonUtils.compareCollections(left, right, differences, Strength.ERROR);
+
+ // Objects in both are asked for their differences
+ verify(db1).diff(db1, differences, Strength.ERROR);
+ verify(db4).diff(db4, differences, Strength.ERROR);
+
+ // Objects in only one collections are marked as such
+ verify(differences).add(Where.ONLY_IN_LEFT, db2, null, Strength.ERROR);
+ verify(differences).add(Where.ONLY_IN_RIGHT, null, db3, Strength.ERROR);
+ }
+
+
+ @Test
+ public void compareSimpleCollections()
+ {
+ Collection