mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-06-30 18:15:39 +00:00
ALF-7260: schema comparator
* replace path/push/pop mechanism as it doesn't work well at reporting where differences/validation errors occur. * add getParent() to DbObject - so that a path-style identifier can be deduced for a DbObject when needed * add DbProperty to specify a specific DbObject's property and value -- acts as a schema location pointer * refactored Result code (need difference result and validation error result) git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@31527 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
parent
385003c6c9
commit
723fe98cf2
@ -37,11 +37,11 @@ public interface ComparisonUtils
|
||||
*/
|
||||
DbObject findSameObjectAs(Collection<? extends DbObject> objects, final DbObject objToFind);
|
||||
|
||||
void compareSimpleCollections(Collection<? extends Object> leftCollection,
|
||||
Collection<? extends Object> rightCollection, DiffContext ctx, Strength strength);
|
||||
void compareSimpleCollections(DbProperty leftProperty, DbProperty rightProperty,
|
||||
DiffContext ctx, Strength strength);
|
||||
|
||||
/**
|
||||
* Compare collections, reporting differences using the default {@link Result.Strength}
|
||||
* Compare collections, reporting differences using the default {@link Difference.Strength}
|
||||
*
|
||||
* @see #compareCollections(Collection, Collection, Differences, Strength)
|
||||
*/
|
||||
@ -50,7 +50,7 @@ public interface ComparisonUtils
|
||||
|
||||
/**
|
||||
* Compare collections of {@link DbObject}s using their {@link DbObject#diff(DbObject, Differences)} method.
|
||||
* Differences are reported using the specified {@link Result.Strength}.
|
||||
* Differences are reported using the specified {@link Difference.Strength}.
|
||||
*
|
||||
* @param leftCollection
|
||||
* @param rightCollection
|
||||
@ -66,7 +66,7 @@ public interface ComparisonUtils
|
||||
*
|
||||
* @see #compareSimple(Object, Object, Differences, Strength)
|
||||
*/
|
||||
void compareSimple(Object left, Object right, DiffContext ctx);
|
||||
void compareSimple(DbProperty left, DbProperty right, DiffContext ctx);
|
||||
|
||||
/**
|
||||
* Compare two 'simple' (i.e. non-{@link DbObject} objects) using their {@link Object#equals(Object)} method
|
||||
@ -77,6 +77,6 @@ public interface ComparisonUtils
|
||||
* @param differences
|
||||
* @param strength
|
||||
*/
|
||||
void compareSimple(Object left, Object right, DiffContext ctx, Strength strength);
|
||||
void compareSimple(DbProperty left, DbProperty right, DiffContext ctx, Strength strength);
|
||||
|
||||
}
|
@ -18,27 +18,14 @@
|
||||
*/
|
||||
package org.alfresco.util.schemacomp;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* Defines a visitor that can operate on a DbObject.
|
||||
*
|
||||
* @author Matt Ward
|
||||
*/
|
||||
public interface DbObjectVisitor
|
||||
{
|
||||
void visit(DbObject dbObject);
|
||||
// void visit(Column column);
|
||||
// void visit(ForeignKey fk);
|
||||
// void visit(Index index);
|
||||
// void visit(PrimaryKey pk);
|
||||
// void visit(Schema schema);
|
||||
// void visit(Sequence sequence);
|
||||
// void visit(Table table);
|
||||
}
|
||||
|
239
source/java/org/alfresco/util/schemacomp/DbProperty.java
Normal file
239
source/java/org/alfresco/util/schemacomp/DbProperty.java
Normal file
@ -0,0 +1,239 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.util.schemacomp;
|
||||
|
||||
import org.alfresco.util.schemacomp.model.DbObject;
|
||||
import org.apache.commons.beanutils.PropertyUtils;
|
||||
|
||||
/**
|
||||
* A pointer to a specific DbObject property and its value (at time of creating the DbProperty object).
|
||||
*
|
||||
* @author Matt Ward
|
||||
*/
|
||||
public class DbProperty
|
||||
{
|
||||
private final DbObject dbObject;
|
||||
private final String propertyName;
|
||||
private final Object propertyValue;
|
||||
|
||||
/**
|
||||
* Full constructor allowing control over whether the property name should be indexed (e.g. colours[3]),
|
||||
* whether the current value of the property should be retrieved automatically or whether to use the
|
||||
* supplied value (useful when performing comparisons - construct one with a particular/expected value and
|
||||
* construct another with the current value by reflection).
|
||||
* <p>
|
||||
* The public constructors provide a more usable API with select sets of arguments.
|
||||
*
|
||||
* @param dbObject
|
||||
* @param propertyName
|
||||
* @param propertyValue
|
||||
*/
|
||||
protected DbProperty(DbObject dbObject, String propertyName, int index, boolean useSuppliedValue, Object propertyValue)
|
||||
{
|
||||
if (dbObject == null)
|
||||
{
|
||||
throw new IllegalArgumentException("dbObject cannot be null.");
|
||||
}
|
||||
this.dbObject = dbObject;
|
||||
|
||||
if (propertyName == null)
|
||||
{
|
||||
if (index > -1 || useSuppliedValue)
|
||||
{
|
||||
throw new IllegalArgumentException("propertyName cannot be null.");
|
||||
}
|
||||
}
|
||||
if (index > -1)
|
||||
{
|
||||
this.propertyName = propertyName+"["+index+"]";
|
||||
}
|
||||
else
|
||||
{
|
||||
this.propertyName = propertyName;
|
||||
}
|
||||
|
||||
// Unfortunetely, this boolean is required, since we may want to set the property value to null.
|
||||
if (useSuppliedValue)
|
||||
{
|
||||
this.propertyValue = propertyValue;
|
||||
}
|
||||
else if (propertyName != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.propertyValue = PropertyUtils.getProperty(dbObject, this.propertyName);
|
||||
}
|
||||
catch (Throwable error)
|
||||
{
|
||||
throw new IllegalArgumentException("Cannot get value for property named \"" + propertyName + "\"", error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// No property is being referred to by this object.
|
||||
this.propertyValue = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a pointer to a database object only (no property within).
|
||||
*
|
||||
* @param dbObject
|
||||
*/
|
||||
public DbProperty(DbObject dbObject)
|
||||
{
|
||||
this(dbObject, null, -1, false, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a DbProperty by supplying the DbObject and the property name. The
|
||||
* value at time of creation will be populate automatically.
|
||||
*
|
||||
* @param dbObject
|
||||
* @param propertyName
|
||||
*/
|
||||
public DbProperty(DbObject dbObject, String propertyName)
|
||||
{
|
||||
this(dbObject, propertyName, -1, false, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a DbProperty with an indexed value, e.g. for propertyName "myCollection" and
|
||||
* index 4, the propertyName will be converted to "myCollection[4]" and the propertValue
|
||||
* will be populated with the value at index 4 of myCollection.
|
||||
*
|
||||
* @param dbObject
|
||||
* @param propertyName
|
||||
* @param index
|
||||
*/
|
||||
public DbProperty(DbObject dbObject, String propertyName, int index)
|
||||
{
|
||||
this(dbObject, propertyName, index, false, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the dbObject
|
||||
*/
|
||||
public DbObject getDbObject()
|
||||
{
|
||||
return this.dbObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the propertyName
|
||||
*/
|
||||
public String getPropertyName()
|
||||
{
|
||||
return this.propertyName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the propertyValue
|
||||
*/
|
||||
public Object getPropertyValue()
|
||||
{
|
||||
return this.propertyValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((this.dbObject == null) ? 0 : this.dbObject.hashCode());
|
||||
result = prime * result + ((this.propertyName == null) ? 0 : this.propertyName.hashCode());
|
||||
result = prime * result
|
||||
+ ((this.propertyValue == null) ? 0 : this.propertyValue.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;
|
||||
DbProperty other = (DbProperty) obj;
|
||||
if (this.dbObject == null)
|
||||
{
|
||||
if (other.dbObject != null) return false;
|
||||
}
|
||||
else if (!this.dbObject.equals(other.dbObject)) return false;
|
||||
if (this.propertyName == null)
|
||||
{
|
||||
if (other.propertyName != null) return false;
|
||||
}
|
||||
else if (!this.propertyName.equals(other.propertyName)) return false;
|
||||
if (this.propertyValue == null)
|
||||
{
|
||||
if (other.propertyValue != null) return false;
|
||||
}
|
||||
else if (!this.propertyValue.equals(other.propertyValue)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "DbProperty [dbObject=" + this.dbObject + ", propertyName=" + this.propertyName
|
||||
+ ", propertyValue=" + this.propertyValue + "]";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Work backwards from this DbProperty's DbObject to the root object to create a path in the
|
||||
* following format:
|
||||
* <p>
|
||||
* root.child.grandchild[...].property
|
||||
* <p>
|
||||
* e.g. myschema.person.age.nullable
|
||||
* <p>
|
||||
* This isn't exactly the same as a FQ database object name, for example the property name could be indexed:
|
||||
* <p>
|
||||
* e.g. myschema.person.pk_person.columnNames[2]
|
||||
* <p>
|
||||
* to reflect the third column name in the primary key named "pk_person" on the person table.
|
||||
*
|
||||
* @return String path
|
||||
*/
|
||||
public String getPath()
|
||||
{
|
||||
StringBuffer sb = new StringBuffer();
|
||||
|
||||
if (getPropertyName() != null)
|
||||
{
|
||||
sb.append(".");
|
||||
sb.append(getPropertyName());
|
||||
}
|
||||
|
||||
for (DbObject pathElement = dbObject; pathElement != null; pathElement = pathElement.getParent())
|
||||
{
|
||||
sb.insert(0, pathElement.getName());
|
||||
if (pathElement.getParent() != null)
|
||||
{
|
||||
sb.insert(0, ".");
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
}
|
115
source/java/org/alfresco/util/schemacomp/DbPropertyTest.java
Normal file
115
source/java/org/alfresco/util/schemacomp/DbPropertyTest.java
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.util.schemacomp;
|
||||
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.util.schemacomp.model.AbstractDbObject;
|
||||
import org.alfresco.util.schemacomp.model.DbObject;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
public class DbPropertyTest
|
||||
{
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void cannotHaveNullDbObject()
|
||||
{
|
||||
new DbProperty(null, "theProperty");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void propertyValueCanBeRetrievedByReflection()
|
||||
{
|
||||
DbObjectWithIndexedProp dbo = Mockito.mock(DbObjectWithIndexedProp.class);
|
||||
Mockito.when(dbo.getTheProperty()).thenReturn("This is the property value");
|
||||
|
||||
DbProperty dbProperty = new DbProperty(dbo, "theProperty");
|
||||
|
||||
assertEquals("This is the property value", dbProperty.getPropertyValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void indexedPropertyValueCanBeRetrievedByReflection()
|
||||
{
|
||||
DbObjectWithIndexedProp dbo = Mockito.mock(DbObjectWithIndexedProp.class);
|
||||
Mockito.when(dbo.getColours()).thenReturn(Arrays.asList("red", "green", "blue"));
|
||||
|
||||
DbProperty greenProperty = new DbProperty(dbo, "colours[1]");
|
||||
DbProperty blueProperty = new DbProperty(dbo, "colours", 2);
|
||||
|
||||
assertEquals("green", greenProperty.getPropertyValue());
|
||||
assertEquals("blue", blueProperty.getPropertyValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canGetPath()
|
||||
{
|
||||
new MyDbObject("root", 1).
|
||||
add(new MyDbObject("child", 2)).
|
||||
add(new MyDbObject("grandchild", 3)).
|
||||
add(new MyDbObject("greatgrandchild", 4));
|
||||
|
||||
DbProperty levelProp = new DbProperty(MyDbObject.lastAdded, "level");
|
||||
assertEquals("Incorrect path", "root.child.grandchild.greatgrandchild.level", levelProp.getPath());
|
||||
|
||||
DbProperty greatGrandChildProp = new DbProperty(MyDbObject.lastAdded);
|
||||
assertEquals("Incorrect path", "root.child.grandchild.greatgrandchild", greatGrandChildProp.getPath());
|
||||
}
|
||||
|
||||
|
||||
private interface DbObjectWithIndexedProp extends DbObject
|
||||
{
|
||||
String getTheProperty();
|
||||
List<String> getColours();
|
||||
}
|
||||
|
||||
public static class MyDbObject extends AbstractDbObject
|
||||
{
|
||||
public static MyDbObject lastAdded;
|
||||
private int level;
|
||||
|
||||
public MyDbObject(String name, int level)
|
||||
{
|
||||
super(null, name);
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(DbObjectVisitor visitor)
|
||||
{
|
||||
}
|
||||
|
||||
public MyDbObject add(MyDbObject child)
|
||||
{
|
||||
child.setParent(this);
|
||||
lastAdded = child;
|
||||
return child;
|
||||
}
|
||||
|
||||
public int getLevel()
|
||||
{
|
||||
return this.level;
|
||||
}
|
||||
}
|
||||
}
|
@ -19,10 +19,11 @@
|
||||
|
||||
package org.alfresco.util.schemacomp;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.alfresco.util.schemacomp.Result.Strength;
|
||||
import org.alfresco.util.schemacomp.Result.Where;
|
||||
import org.alfresco.util.schemacomp.Difference.Where;
|
||||
import org.alfresco.util.schemacomp.model.DbObject;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.collections.Predicate;
|
||||
@ -54,42 +55,60 @@ public class DefaultComparisonUtils implements ComparisonUtils
|
||||
|
||||
|
||||
@Override
|
||||
public void compareSimpleCollections(Collection<? extends Object> leftCollection,
|
||||
Collection<? extends Object> rightCollection, DiffContext ctx, Strength strength)
|
||||
public void compareSimpleCollections(DbProperty leftProp,
|
||||
DbProperty rightProp, DiffContext ctx, Strength strength)
|
||||
{
|
||||
Differences differences = ctx.getDifferences();
|
||||
for (Object leftObj : leftCollection)
|
||||
@SuppressWarnings("unchecked")
|
||||
Collection<? extends Object> leftCollection = (Collection<? extends Object>) leftProp.getPropertyValue();
|
||||
@SuppressWarnings("unchecked")
|
||||
Collection<? extends Object> rightCollection = (Collection<? extends Object>) rightProp.getPropertyValue();
|
||||
|
||||
// TODO: Temporary code during refactoring
|
||||
ArrayList<? extends Object> leftList = new ArrayList<Object>(leftCollection);
|
||||
ArrayList<? extends Object> rightList = new ArrayList<Object>(rightCollection);
|
||||
|
||||
Results differences = ctx.getDifferences();
|
||||
|
||||
for (int leftIndex = 0; leftIndex < leftList.size(); leftIndex++)
|
||||
{
|
||||
if (rightCollection.contains(leftObj))
|
||||
Object leftObj = leftList.get(leftIndex);
|
||||
DbProperty leftIndexedProp = new DbProperty(leftProp.getDbObject(), leftProp.getPropertyName(), leftIndex);
|
||||
|
||||
int rightIndex;
|
||||
if ((rightIndex = rightList.indexOf(leftObj)) != -1)
|
||||
{
|
||||
// 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);
|
||||
DbProperty rightIndexedProp = new DbProperty(rightProp.getDbObject(), rightProp.getPropertyName(), rightIndex);
|
||||
differences.add(Where.IN_BOTH_NO_DIFFERENCE, leftIndexedProp, rightIndexedProp, strength);
|
||||
}
|
||||
else
|
||||
{
|
||||
// No equivalent object in the right hand collection.
|
||||
differences.add(Where.ONLY_IN_LEFT, leftObj, null, strength);
|
||||
// Using rightIndexedProperty would result in index out of bounds error.
|
||||
differences.add(Where.ONLY_IN_LEFT, leftIndexedProp, rightProp, strength);
|
||||
}
|
||||
}
|
||||
|
||||
// Identify objects in the right collection but not the left
|
||||
for (Object rightObj : rightCollection)
|
||||
for (int rightIndex = 0; rightIndex < rightList.size(); rightIndex++)
|
||||
{
|
||||
Object rightObj = rightList.get(rightIndex);
|
||||
if (!leftCollection.contains(rightObj))
|
||||
{
|
||||
DbProperty rightIndexedProp = new DbProperty(rightProp.getDbObject(), rightProp.getPropertyName(), rightIndex);
|
||||
// No equivalent object in the left hand collection.
|
||||
differences.add(Where.ONLY_IN_RIGHT, null, rightObj, strength);
|
||||
differences.add(Where.ONLY_IN_RIGHT, leftProp, rightIndexedProp, strength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare collections, reporting differences using the default {@link Result.Strength}
|
||||
* Compare collections, reporting differences using the default {@link Difference.Strength}
|
||||
*
|
||||
* @see #compareCollections(Collection, Collection, Differences, Strength)
|
||||
* @see #compareCollections(Collection, Collection, Results, Strength)
|
||||
*/
|
||||
@Override
|
||||
public void compareCollections(Collection<? extends DbObject> leftCollection,
|
||||
@ -99,8 +118,8 @@ public class DefaultComparisonUtils implements ComparisonUtils
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare collections of {@link DbObject}s using their {@link DbObject#diff(DbObject, Differences)} method.
|
||||
* Differences are reported using the specified {@link Result.Strength}.
|
||||
* Compare collections of {@link DbObject}s using their {@link DbObject#diff(DbObject, Results)} method.
|
||||
* Differences are reported using the specified {@link Difference.Strength}.
|
||||
*
|
||||
* @param leftCollection
|
||||
* @param rightCollection
|
||||
@ -111,7 +130,7 @@ public class DefaultComparisonUtils implements ComparisonUtils
|
||||
public void compareCollections(Collection<? extends DbObject> leftCollection,
|
||||
Collection<? extends DbObject> rightCollection, DiffContext ctx, Strength strength)
|
||||
{
|
||||
Differences differences = ctx.getDifferences();
|
||||
Results differences = ctx.getDifferences();
|
||||
for (DbObject leftObj : leftCollection)
|
||||
{
|
||||
DbObject rightObj = findSameObjectAs(rightCollection, leftObj);
|
||||
@ -125,17 +144,19 @@ public class DefaultComparisonUtils implements ComparisonUtils
|
||||
else
|
||||
{
|
||||
// No equivalent object in the right hand collection.
|
||||
differences.add(Where.ONLY_IN_LEFT, leftObj, null, strength);
|
||||
differences.add(Where.ONLY_IN_LEFT, new DbProperty(leftObj, null), null, strength);
|
||||
}
|
||||
}
|
||||
|
||||
// Identify objects in the right collection but not the left
|
||||
for (DbObject rightObj : rightCollection)
|
||||
{
|
||||
if (!leftCollection.contains(rightObj))
|
||||
DbObject leftObj = findSameObjectAs(leftCollection, rightObj);
|
||||
|
||||
if (leftObj == null)
|
||||
{
|
||||
// No equivalent object in the left hand collection.
|
||||
differences.add(Where.ONLY_IN_RIGHT, null, rightObj, strength);
|
||||
differences.add(Where.ONLY_IN_RIGHT, null, new DbProperty(rightObj, null), strength);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -143,10 +164,10 @@ public class DefaultComparisonUtils implements ComparisonUtils
|
||||
/**
|
||||
* Compare two simple objects. Differences are reported using the default Result.Strength.
|
||||
*
|
||||
* @see #compareSimple(Object, Object, Differences, Strength)
|
||||
* @see #compareSimple(Object, Object, Results, Strength)
|
||||
*/
|
||||
@Override
|
||||
public void compareSimple(Object left, Object right, DiffContext ctx)
|
||||
public void compareSimple(DbProperty left, DbProperty right, DiffContext ctx)
|
||||
{
|
||||
compareSimple(left, right, ctx, null);
|
||||
}
|
||||
@ -161,11 +182,16 @@ public class DefaultComparisonUtils implements ComparisonUtils
|
||||
* @param strength
|
||||
*/
|
||||
@Override
|
||||
public void compareSimple(Object left, Object right, DiffContext ctx, Strength strength)
|
||||
public void compareSimple(DbProperty leftProperty, DbProperty rightProperty, DiffContext ctx, Strength strength)
|
||||
{
|
||||
|
||||
Where where = null;
|
||||
|
||||
Object left = leftProperty.getPropertyValue();
|
||||
checkNotDbObject(left);
|
||||
Object right = rightProperty.getPropertyValue();
|
||||
checkNotDbObject(right);
|
||||
|
||||
if (left == right)
|
||||
{
|
||||
// Same object, or both nulls
|
||||
@ -194,6 +220,19 @@ public class DefaultComparisonUtils implements ComparisonUtils
|
||||
}
|
||||
}
|
||||
|
||||
ctx.getDifferences().add(where, left, right, strength);
|
||||
ctx.getDifferences().add(where, leftProperty, rightProperty, strength);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param obj
|
||||
*/
|
||||
private void checkNotDbObject(Object obj)
|
||||
{
|
||||
if (obj != null && DbObject.class.isAssignableFrom(obj.getClass()))
|
||||
{
|
||||
throw new IllegalArgumentException(
|
||||
"Property value is a DbObject - this method shouldn't be used to compare this type: " + obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -30,8 +30,9 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.util.schemacomp.Difference.Where;
|
||||
import org.alfresco.util.schemacomp.Result.Strength;
|
||||
import org.alfresco.util.schemacomp.Result.Where;
|
||||
import org.alfresco.util.schemacomp.model.AbstractDbObject;
|
||||
import org.alfresco.util.schemacomp.model.DbObject;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.junit.Before;
|
||||
@ -48,7 +49,7 @@ import org.mockito.runners.MockitoJUnitRunner;
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class DefaultComparisonUtilsTest
|
||||
{
|
||||
private @Mock Differences differences;
|
||||
private @Mock Results differences;
|
||||
private DefaultComparisonUtils comparisonUtils;
|
||||
private DiffContext ctx;
|
||||
private @Mock Dialect dialect;
|
||||
@ -63,22 +64,27 @@ public class DefaultComparisonUtilsTest
|
||||
@Test
|
||||
public void compareSimple()
|
||||
{
|
||||
comparisonUtils.compareSimple(null, null, ctx, Strength.ERROR);
|
||||
verify(differences).add(Where.IN_BOTH_NO_DIFFERENCE, null, null, Strength.ERROR);
|
||||
comparisonUtils.compareSimple(prop(null), prop(null), ctx, Strength.ERROR);
|
||||
verify(differences).add(Where.IN_BOTH_NO_DIFFERENCE, prop(null), prop(null), Strength.ERROR);
|
||||
|
||||
comparisonUtils.compareSimple("not_null_string", "not_null_string", ctx, Strength.ERROR);
|
||||
verify(differences).add(Where.IN_BOTH_NO_DIFFERENCE, "not_null_string", "not_null_string", Strength.ERROR);
|
||||
comparisonUtils.compareSimple(prop("not_null_string"), prop("not_null_string"), ctx, Strength.ERROR);
|
||||
verify(differences).add(Where.IN_BOTH_NO_DIFFERENCE, prop("not_null_string"), prop("not_null_string"), Strength.ERROR);
|
||||
|
||||
comparisonUtils.compareSimple("left", "right", ctx, Strength.ERROR);
|
||||
verify(differences).add(Where.IN_BOTH_BUT_DIFFERENCE, "left", "right", Strength.ERROR);
|
||||
comparisonUtils.compareSimple(prop("left"), prop("right"), ctx, Strength.ERROR);
|
||||
verify(differences).add(Where.IN_BOTH_BUT_DIFFERENCE, prop("left"), prop("right"), Strength.ERROR);
|
||||
|
||||
comparisonUtils.compareSimple("left", null, ctx, Strength.ERROR);
|
||||
verify(differences).add(Where.ONLY_IN_LEFT, "left", null, Strength.ERROR);
|
||||
comparisonUtils.compareSimple(prop("left"), prop(null), ctx, Strength.ERROR);
|
||||
verify(differences).add(Where.ONLY_IN_LEFT, prop("left"), prop(null), Strength.ERROR);
|
||||
|
||||
comparisonUtils.compareSimple(null, "right", ctx, Strength.ERROR);
|
||||
verify(differences).add(Where.ONLY_IN_RIGHT, null, "right", Strength.ERROR);
|
||||
comparisonUtils.compareSimple(prop(null), prop("right"), ctx, Strength.ERROR);
|
||||
verify(differences).add(Where.ONLY_IN_RIGHT, prop(null), prop("right"), Strength.ERROR);
|
||||
}
|
||||
|
||||
public DbProperty prop(String propValue)
|
||||
{
|
||||
DbObject dbo = new DbObjectWithCollection("dbo", null);
|
||||
return dbPropForValue(dbo, "someProperty", propValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compareCollections()
|
||||
@ -105,8 +111,8 @@ public class DefaultComparisonUtilsTest
|
||||
verify(db4).diff(db4, ctx, 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);
|
||||
verify(differences).add(Where.ONLY_IN_LEFT, new DbProperty(db2), null, Strength.ERROR);
|
||||
verify(differences).add(Where.ONLY_IN_RIGHT, null, new DbProperty(db3), Strength.ERROR);
|
||||
}
|
||||
|
||||
|
||||
@ -124,6 +130,8 @@ public class DefaultComparisonUtilsTest
|
||||
leftCollection.add(subCollectionLeft);
|
||||
leftCollection.add(456);
|
||||
leftCollection.add("left only");
|
||||
DbObject leftDbObj = new DbObjectWithCollection("left", leftCollection);
|
||||
DbProperty leftCollProp = new DbProperty(leftDbObj, "collection");
|
||||
|
||||
Collection<Object> rightCollection = new ArrayList<Object>();
|
||||
rightCollection.add(123);
|
||||
@ -133,20 +141,59 @@ public class DefaultComparisonUtilsTest
|
||||
rightCollection.add("right only");
|
||||
rightCollection.add("both");
|
||||
rightCollection.add("one more right only");
|
||||
DbObject rightDbObj = new DbObjectWithCollection("right", rightCollection);
|
||||
DbProperty rightCollProp = new DbProperty(rightDbObj, "collection");
|
||||
|
||||
comparisonUtils.compareSimpleCollections(leftCollection, rightCollection, ctx, Strength.WARN);
|
||||
comparisonUtils.compareSimpleCollections(leftCollProp, rightCollProp, ctx, Strength.WARN);
|
||||
|
||||
verify(differences).add(Where.IN_BOTH_NO_DIFFERENCE, 123, 123, Strength.WARN);
|
||||
verify(differences).add(Where.IN_BOTH_NO_DIFFERENCE, "both", "both", Strength.WARN);
|
||||
verify(differences).add(Where.IN_BOTH_NO_DIFFERENCE, subCollectionLeft, subCollectionRight, Strength.WARN);
|
||||
verify(differences).add(Where.ONLY_IN_LEFT, 456, null, Strength.WARN);
|
||||
verify(differences).add(Where.ONLY_IN_LEFT, "left only", null, Strength.WARN);
|
||||
|
||||
verify(differences).add(
|
||||
Where.IN_BOTH_NO_DIFFERENCE,
|
||||
dbPropForValue(leftDbObj, "collection[0]", 123),
|
||||
dbPropForValue(rightDbObj, "collection[0]", 123),
|
||||
Strength.WARN);
|
||||
verify(differences).add(
|
||||
Where.IN_BOTH_NO_DIFFERENCE,
|
||||
dbPropForValue(leftDbObj, "collection[1]", "both"),
|
||||
dbPropForValue(rightDbObj, "collection[4]", "both"),
|
||||
Strength.WARN);
|
||||
verify(differences).add(
|
||||
Where.IN_BOTH_NO_DIFFERENCE,
|
||||
dbPropForValue(leftDbObj, "collection[2]", subCollectionLeft),
|
||||
dbPropForValue(rightDbObj, "collection[2]", subCollectionRight),
|
||||
Strength.WARN);
|
||||
verify(differences).add(
|
||||
Where.ONLY_IN_LEFT,
|
||||
dbPropForValue(leftDbObj, "collection[3]", 456),
|
||||
dbPropForValue(rightDbObj, "collection", rightCollection),
|
||||
Strength.WARN);
|
||||
verify(differences).add(
|
||||
Where.ONLY_IN_LEFT,
|
||||
dbPropForValue(leftDbObj, "collection[4]", "left only"),
|
||||
dbPropForValue(rightDbObj, "collection", rightCollection),
|
||||
Strength.WARN);
|
||||
|
||||
verify(differences).add(Where.ONLY_IN_RIGHT, null, 789, Strength.WARN);
|
||||
verify(differences).add(Where.ONLY_IN_RIGHT, null, "right only", Strength.WARN);
|
||||
verify(differences).add(Where.ONLY_IN_RIGHT, null, "one more right only", Strength.WARN);
|
||||
verify(differences).add(
|
||||
Where.ONLY_IN_RIGHT,
|
||||
dbPropForValue(leftDbObj, "collection", leftCollection),
|
||||
dbPropForValue(rightDbObj, "collection[1]", 789),
|
||||
Strength.WARN);
|
||||
verify(differences).add(
|
||||
Where.ONLY_IN_RIGHT,
|
||||
dbPropForValue(leftDbObj, "collection", leftCollection),
|
||||
dbPropForValue(rightDbObj, "collection[3]", "right only"),
|
||||
Strength.WARN);
|
||||
verify(differences).add(
|
||||
Where.ONLY_IN_RIGHT,
|
||||
dbPropForValue(leftDbObj, "collection", leftCollection),
|
||||
dbPropForValue(rightDbObj, "collection[5]", "one more right only"),
|
||||
Strength.WARN);
|
||||
}
|
||||
|
||||
private DbProperty dbPropForValue(DbObject obj, String propName, Object propValue)
|
||||
{
|
||||
return new DbProperty(obj, propName, -1, true, propValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findSameObjectAsSuccessfulFind()
|
||||
@ -194,4 +241,26 @@ public class DefaultComparisonUtilsTest
|
||||
}
|
||||
return dbObjects;
|
||||
}
|
||||
|
||||
|
||||
public static class DbObjectWithCollection extends AbstractDbObject
|
||||
{
|
||||
private Collection<Object> collection;
|
||||
|
||||
public DbObjectWithCollection(String name, Collection<Object> collection)
|
||||
{
|
||||
super(null, name);
|
||||
this.collection = collection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(DbObjectVisitor visitor)
|
||||
{
|
||||
}
|
||||
|
||||
public Collection<Object> getCollection()
|
||||
{
|
||||
return this.collection;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,21 +25,21 @@ import org.hibernate.dialect.Dialect;
|
||||
/**
|
||||
* A context made available to schema differencing and validation operations. It supplies information
|
||||
* about the {@link Dialect database dialect} that should be used when validating database properties
|
||||
* and the {@link Differences} object that should be populated with schema differences and validation errors.
|
||||
* and the {@link Results} object that should be populated with schema differences and validation errors.
|
||||
*
|
||||
* @author Matt Ward
|
||||
*/
|
||||
public class DiffContext
|
||||
{
|
||||
private final Dialect dialect;
|
||||
private final Differences differences;
|
||||
private final Results differences;
|
||||
private final List<ValidationResult> validationResults;
|
||||
|
||||
/**
|
||||
* @param dialect
|
||||
* @param differences
|
||||
*/
|
||||
public DiffContext(Dialect dialect, Differences differences, List<ValidationResult> validationResults)
|
||||
public DiffContext(Dialect dialect, Results differences, List<ValidationResult> validationResults)
|
||||
{
|
||||
this.dialect = dialect;
|
||||
this.differences = differences;
|
||||
@ -57,7 +57,7 @@ public class DiffContext
|
||||
/**
|
||||
* @return the differences
|
||||
*/
|
||||
public Differences getDifferences()
|
||||
public Results getDifferences()
|
||||
{
|
||||
return this.differences;
|
||||
}
|
||||
|
80
source/java/org/alfresco/util/schemacomp/Difference.java
Normal file
80
source/java/org/alfresco/util/schemacomp/Difference.java
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.util.schemacomp;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Result of a comparison between two database objects.
|
||||
*
|
||||
* @author Matt Ward
|
||||
*/
|
||||
public final class Difference extends Result
|
||||
{
|
||||
/** Specifies the type of differences */
|
||||
public enum Where { ONLY_IN_LEFT, ONLY_IN_RIGHT, IN_BOTH_NO_DIFFERENCE, IN_BOTH_BUT_DIFFERENCE };
|
||||
private final Where where;
|
||||
private final DbProperty left;
|
||||
private final DbProperty right;
|
||||
|
||||
|
||||
public Difference(Where where, DbProperty left, DbProperty right)
|
||||
{
|
||||
this(where, left, right, null);
|
||||
}
|
||||
|
||||
public Difference(Where where, DbProperty left, DbProperty right, Strength strength)
|
||||
{
|
||||
super(null);
|
||||
this.where = where;
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the where
|
||||
*/
|
||||
public Where getWhere()
|
||||
{
|
||||
return this.where;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the left
|
||||
*/
|
||||
public DbProperty getLeft()
|
||||
{
|
||||
return this.left;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the right
|
||||
*/
|
||||
public DbProperty getRight()
|
||||
{
|
||||
return this.right;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "Difference [where=" + this.where + ", left=" + this.left + ", right=" + this.right
|
||||
+ ", strength=" + this.strength + "]";
|
||||
}
|
||||
}
|
@ -1,138 +0,0 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.util.schemacomp;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
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.lang.StringUtils;
|
||||
|
||||
/**
|
||||
* Collects differences so that tools can report on or respond to differences between database schemas.
|
||||
*
|
||||
* @author Matt Ward
|
||||
*/
|
||||
public class Differences implements Iterable<Result>
|
||||
{
|
||||
private final List<Result> items = new ArrayList<Result>();
|
||||
private final Path path = new Path();
|
||||
|
||||
|
||||
/**
|
||||
* @see Path
|
||||
*/
|
||||
public void pushPath(String component)
|
||||
{
|
||||
this.path.push(component);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Path
|
||||
*/
|
||||
public String popPath()
|
||||
{
|
||||
return this.path.pop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Record a difference between two objects, or specify that an object only appears in either the
|
||||
* 'left' or 'right' schemas.
|
||||
*
|
||||
* @param where The type of difference, see {@link Where}
|
||||
* @param left Left value, or null if the item appears in the right, but not left schema.
|
||||
* @param right Right value, or null if the item appears in the left, but not right schema.
|
||||
* @param strength The Result.Strength of the difference, e.g. WARN or ERROR.
|
||||
*/
|
||||
public void add(Where where, Object left, Object right, Strength strength)
|
||||
{
|
||||
Result result = new Result(where, left, right, path.getCurrentPath(), strength);
|
||||
items.add(result);
|
||||
}
|
||||
|
||||
|
||||
public void add(Where where, Object left, Object right)
|
||||
{
|
||||
add(where, left, right, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtain an iterator for the top-level items held in this schema - since this is a hierarchical model,
|
||||
* deeper items are obtained by navigating through the top-level items.
|
||||
*/
|
||||
@Override
|
||||
public Iterator<Result> iterator()
|
||||
{
|
||||
return items.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return How many top-level items are in the schema.
|
||||
*/
|
||||
public int size()
|
||||
{
|
||||
return items.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies where in a database schema a difference occurs - this is largely the same as the fully qualified
|
||||
* name of a database object, e.g. <code>public.alf_node</code> except that if an object doesn't have a name
|
||||
* then a suitable label will be provided for that path element.
|
||||
* <p>
|
||||
* Elements can be <code>push</code>ed onto the path and <code>pop</code>ped from the path, making it easier for a
|
||||
* {@link DbObject} to process that object's data as part of a heirachy - the parent object should push an
|
||||
* appropriate label onto the path for itself, before invoking any child objects'
|
||||
* {@link DbObject#diff(DbObject, Differences)} method.
|
||||
*
|
||||
* @author Matt Ward
|
||||
*/
|
||||
private static class Path
|
||||
{
|
||||
private Stack<String> components = new Stack<String>();
|
||||
private String current;
|
||||
|
||||
public void push(String component)
|
||||
{
|
||||
components.push(component);
|
||||
makeCurrentPath();
|
||||
}
|
||||
|
||||
public String pop()
|
||||
{
|
||||
String component = components.pop();
|
||||
makeCurrentPath();
|
||||
return component;
|
||||
}
|
||||
|
||||
public String getCurrentPath()
|
||||
{
|
||||
return current;
|
||||
}
|
||||
|
||||
private void makeCurrentPath()
|
||||
{
|
||||
current = StringUtils.join(components, ".");
|
||||
}
|
||||
}
|
||||
}
|
@ -18,77 +18,24 @@
|
||||
*/
|
||||
package org.alfresco.util.schemacomp;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Result of a comparison between two database objects.
|
||||
*
|
||||
* Base class for the result of a differencing or validation operation.
|
||||
*
|
||||
* @author Matt Ward
|
||||
*/
|
||||
public final class Result
|
||||
public class Result
|
||||
{
|
||||
/** Specifies the type of differences */
|
||||
public enum Where { ONLY_IN_LEFT, ONLY_IN_RIGHT, IN_BOTH_NO_DIFFERENCE, IN_BOTH_BUT_DIFFERENCE };
|
||||
public enum Strength { WARN, ERROR };
|
||||
private final Where where;
|
||||
private final Object left;
|
||||
private final Object right;
|
||||
private final String path;
|
||||
private final Strength strength;
|
||||
protected final Strength strength;
|
||||
|
||||
public Result(Where where, Object left, Object right, String path)
|
||||
/**
|
||||
* @param strength
|
||||
*/
|
||||
public Result(Strength strength)
|
||||
{
|
||||
this(where, left, right, path, null);
|
||||
}
|
||||
|
||||
public Result(Where where, Object left, Object right, String path, Strength strength)
|
||||
{
|
||||
this.where = where;
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
this.path = path;
|
||||
this.strength = (strength != null ? strength : Strength.ERROR);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the where
|
||||
*/
|
||||
public Where getWhere()
|
||||
{
|
||||
return this.where;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the left
|
||||
*/
|
||||
public Object getLeft()
|
||||
{
|
||||
return this.left;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the right
|
||||
*/
|
||||
public Object getRight()
|
||||
{
|
||||
return this.right;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return the path
|
||||
*/
|
||||
public String getPath()
|
||||
{
|
||||
return this.path;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return the strength
|
||||
*/
|
||||
@ -96,13 +43,4 @@ public final class Result
|
||||
{
|
||||
return this.strength;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "Result [where=" + this.where + ", left=" + this.left + ", right=" + this.right
|
||||
+ ", path=" + this.path + ", strength=" + this.strength + "]";
|
||||
}
|
||||
}
|
||||
|
82
source/java/org/alfresco/util/schemacomp/Results.java
Normal file
82
source/java/org/alfresco/util/schemacomp/Results.java
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.util.schemacomp;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.util.schemacomp.Difference.Where;
|
||||
import org.alfresco.util.schemacomp.Result.Strength;
|
||||
|
||||
/**
|
||||
* Collects differences so that tools can report on or respond to differences between database schemas.
|
||||
*
|
||||
* @author Matt Ward
|
||||
*/
|
||||
public class Results implements Iterable<Difference>
|
||||
{
|
||||
private final List<Difference> items = new ArrayList<Difference>();
|
||||
/** Temporary step during refactor - Where.IN_BOTH_NO_DIFFERENCE will be going altogether */
|
||||
private boolean reportNonDifferences = false;
|
||||
|
||||
|
||||
/**
|
||||
* Record a difference between two objects, or specify that an object only appears in either the
|
||||
* 'left' or 'right' schemas.
|
||||
*
|
||||
* @param where The type of difference, see {@link Where}
|
||||
* @param left Left value, or null if the item appears in the right, but not left schema.
|
||||
* @param right Right value, or null if the item appears in the left, but not right schema.
|
||||
* @param strength The Result.Strength of the difference, e.g. WARN or ERROR.
|
||||
*/
|
||||
public void add(Where where, DbProperty left, DbProperty right, Strength strength)
|
||||
{
|
||||
if (where != Where.IN_BOTH_NO_DIFFERENCE || reportNonDifferences)
|
||||
{
|
||||
Difference result = new Difference(where, left, right, strength);
|
||||
items.add(result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void add(Where where, DbProperty left, DbProperty right)
|
||||
{
|
||||
add(where, left, right, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtain an iterator for the top-level items held in this schema - since this is a hierarchical model,
|
||||
* deeper items are obtained by navigating through the top-level items.
|
||||
*/
|
||||
@Override
|
||||
public Iterator<Difference> iterator()
|
||||
{
|
||||
return items.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return How many top-level items are in the schema.
|
||||
*/
|
||||
public int size()
|
||||
{
|
||||
return items.size();
|
||||
}
|
||||
}
|
@ -29,6 +29,7 @@ import org.junit.runners.Suite;
|
||||
@RunWith(Suite.class)
|
||||
@Suite.SuiteClasses(
|
||||
{
|
||||
DbPropertyTest.class,
|
||||
DefaultComparisonUtilsTest.class,
|
||||
SchemaComparatorTest.class,
|
||||
ValidatingVisitorTest.class
|
||||
|
@ -47,7 +47,7 @@ public class SchemaComparator
|
||||
{
|
||||
this.leftSchema = left;
|
||||
this.rightSchema = right;
|
||||
this.ctx = new DiffContext(dialect, new Differences(), new ArrayList<ValidationResult>());
|
||||
this.ctx = new DiffContext(dialect, new Results(), new ArrayList<ValidationResult>());
|
||||
}
|
||||
|
||||
|
||||
@ -81,7 +81,7 @@ public class SchemaComparator
|
||||
/**
|
||||
* @return the differences
|
||||
*/
|
||||
public Differences getDifferences()
|
||||
public Results getDifferences()
|
||||
{
|
||||
return ctx.getDifferences();
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ package org.alfresco.util.schemacomp;
|
||||
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.Arrays;
|
||||
@ -28,10 +28,8 @@ import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.util.schemacomp.Result.Strength;
|
||||
import org.alfresco.util.schemacomp.Result.Where;
|
||||
import org.alfresco.util.schemacomp.Difference.Where;
|
||||
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;
|
||||
@ -68,18 +66,18 @@ public class SchemaComparatorTest
|
||||
public void canPerformDiff()
|
||||
{
|
||||
// Left hand side's database objects.
|
||||
left.add(new Table("tbl_no_diff", columns("id NUMBER(10)", "nodeRef VARCHAR2(200)", "name VARCHAR2(150)"),
|
||||
left.add(new Table(left, "tbl_no_diff", columns("id NUMBER(10)", "nodeRef VARCHAR2(200)", "name VARCHAR2(150)"),
|
||||
pk("pk_tbl_no_diff", "id"), fkeys(fk("fk_tbl_no_diff", "nodeRef", "node", "nodeRef")),
|
||||
indexes("idx_node id nodeRef")));
|
||||
left.add(table("table_in_left"));
|
||||
left.add(new Table("tbl_has_diff_pk", columns("id NUMBER(10)", "nodeRef VARCHAR2(200)"),
|
||||
left.add(new Table(left, "tbl_has_diff_pk", columns("id NUMBER(10)", "nodeRef VARCHAR2(200)"),
|
||||
pk("pk_is_diff", "id"), fkeys(), indexes()));
|
||||
|
||||
// Right hand side's database objects.
|
||||
right.add(new Table("tbl_no_diff", columns("id NUMBER(10)", "nodeRef VARCHAR2(200)", "name VARCHAR2(150)"),
|
||||
right.add(new Table(right, "tbl_no_diff", columns("id NUMBER(10)", "nodeRef VARCHAR2(200)", "name VARCHAR2(150)"),
|
||||
pk("pk_tbl_no_diff", "id"), fkeys(fk("fk_tbl_no_diff", "nodeRef", "node", "nodeRef")),
|
||||
indexes("idx_node id nodeRef")));
|
||||
right.add(new Table("tbl_has_diff_pk", columns("id NUMBER(10)", "nodeRef VARCHAR2(200)"),
|
||||
right.add(new Table(right, "tbl_has_diff_pk", columns("id NUMBER(10)", "nodeRef VARCHAR2(200)"),
|
||||
pk("pk_is_diff", "nodeRef"), fkeys(), indexes()));
|
||||
right.add(table("table_in_right"));
|
||||
|
||||
@ -87,53 +85,57 @@ public class SchemaComparatorTest
|
||||
comparator = new SchemaComparator(left, right, dialect);
|
||||
comparator.validateAndCompare();
|
||||
|
||||
// See stdout for diagnostics dump...
|
||||
dumpDiffs(comparator.getDifferences(), false);
|
||||
dumpValidation(comparator.getValidationResults());
|
||||
|
||||
Iterator<Result> it = comparator.getDifferences().iterator();
|
||||
|
||||
assertHasDifference("left_schema", "left_schema", "right_schema", it.next()); // schema names
|
||||
assertNoDifference("left_schema.tbl_no_diff", "tbl_no_diff", it.next());
|
||||
assertNoDifference("left_schema.tbl_no_diff.id", "id", it.next());
|
||||
assertNoDifference("left_schema.tbl_no_diff.id", "NUMBER(10)", it.next());
|
||||
assertNoDifference("left_schema.tbl_no_diff.id", Boolean.FALSE, it.next()); // nullable
|
||||
assertNoDifference("left_schema.tbl_no_diff.nodeRef", "nodeRef", it.next());
|
||||
assertNoDifference("left_schema.tbl_no_diff.nodeRef", "VARCHAR2(200)", it.next());
|
||||
assertNoDifference("left_schema.tbl_no_diff.nodeRef", Boolean.FALSE, it.next()); // nullable
|
||||
assertNoDifference("left_schema.tbl_no_diff.name", "name", it.next());
|
||||
assertNoDifference("left_schema.tbl_no_diff.name", "VARCHAR2(150)", it.next());
|
||||
assertNoDifference("left_schema.tbl_no_diff.name", Boolean.FALSE, it.next()); // nullable
|
||||
assertNoDifference("left_schema.tbl_no_diff.pk_tbl_no_diff", "pk_tbl_no_diff", it.next()); // name field
|
||||
assertNoDifference("left_schema.tbl_no_diff.pk_tbl_no_diff", "id", it.next()); // first (& only) column of list
|
||||
assertNoDifference("left_schema.tbl_no_diff.fk_tbl_no_diff", "fk_tbl_no_diff", it.next()); // name field
|
||||
assertNoDifference("left_schema.tbl_no_diff.fk_tbl_no_diff", "nodeRef", it.next()); // localColumn
|
||||
assertNoDifference("left_schema.tbl_no_diff.fk_tbl_no_diff", "node", it.next()); // targetTable
|
||||
assertNoDifference("left_schema.tbl_no_diff.fk_tbl_no_diff", "nodeRef", it.next()); // targetColumn
|
||||
assertNoDifference("left_schema.tbl_no_diff.idx_node", "idx_node", it.next()); // index name
|
||||
assertNoDifference("left_schema.tbl_no_diff.idx_node", "id", it.next()); // first indexed column
|
||||
assertNoDifference("left_schema.tbl_no_diff.idx_node", "nodeRef", it.next()); // second indexed column
|
||||
// TODO: why are diffs for table not flattened out as for index?
|
||||
assertOnlyInOne("left_schema", Where.ONLY_IN_LEFT, table("table_in_left"), it.next());
|
||||
|
||||
assertNoDifference("left_schema.tbl_has_diff_pk", "tbl_has_diff_pk", it.next());
|
||||
assertNoDifference("left_schema.tbl_has_diff_pk.id", "id", it.next());
|
||||
assertNoDifference("left_schema.tbl_has_diff_pk.id", "NUMBER(10)", it.next());
|
||||
assertNoDifference("left_schema.tbl_has_diff_pk.id", Boolean.FALSE, it.next()); // nullable
|
||||
assertNoDifference("left_schema.tbl_has_diff_pk.nodeRef", "nodeRef", it.next());
|
||||
assertNoDifference("left_schema.tbl_has_diff_pk.nodeRef", "VARCHAR2(200)", it.next());
|
||||
assertNoDifference("left_schema.tbl_has_diff_pk.nodeRef", Boolean.FALSE, it.next()); // nullable
|
||||
assertNoDifference("left_schema.tbl_has_diff_pk.pk_is_diff", "pk_is_diff", it.next()); // name field
|
||||
|
||||
// TODO: surely this should be a diff rather than a ONLY_IN_LEFT plus ONLY_IN_RIGHT?
|
||||
// assertHasDifference("left_schema.tbl_has_diff_pk.pk_is_diff", "id", "nodeRef", it.next()); // first (& only) column of list
|
||||
assertOnlyInOne("left_schema.tbl_has_diff_pk.pk_is_diff", Where.ONLY_IN_LEFT, "id", it.next()); // first (& only) column of list
|
||||
Results differences = comparator.getDifferences();
|
||||
assertEquals(5, differences.size());
|
||||
|
||||
// This belong to the pk_is_diff above.
|
||||
assertOnlyInOne("left_schema.tbl_has_diff_pk.pk_is_diff", Where.ONLY_IN_RIGHT, "nodeRef", it.next()); // first (& only) column of list
|
||||
Iterator<Difference> it = differences.iterator();
|
||||
|
||||
// Items that are ONLY_IN_RIGHT always come at the end
|
||||
assertEquals("Should be table with correct name", "tbl_has_diff_pk", ((DbObject) it.next().getRight()).getName());
|
||||
assertOnlyInOne("left_schema", Where.ONLY_IN_RIGHT, table("table_in_right"), it.next());
|
||||
// Schema names are different ("left_schema" vs "right_schema")
|
||||
Difference diff = it.next();
|
||||
assertEquals(Where.IN_BOTH_BUT_DIFFERENCE, diff.getWhere());
|
||||
assertEquals("left_schema.name", diff.getLeft().getPath());
|
||||
assertEquals("right_schema.name", diff.getRight().getPath());
|
||||
assertSame(left, diff.getLeft().getDbObject());
|
||||
assertSame(right, diff.getRight().getDbObject());
|
||||
assertEquals("name", diff.getLeft().getPropertyName());
|
||||
assertEquals("left_schema", diff.getLeft().getPropertyValue());
|
||||
assertEquals("name", diff.getRight().getPropertyName());
|
||||
assertEquals("right_schema", diff.getRight().getPropertyValue());
|
||||
|
||||
// Table table_in_left only appears in the left schema
|
||||
diff = it.next();
|
||||
assertEquals(Where.ONLY_IN_LEFT, diff.getWhere());
|
||||
assertEquals("left_schema.table_in_left", diff.getLeft().getPath());
|
||||
assertEquals(null, diff.getRight());
|
||||
assertEquals(null, diff.getLeft().getPropertyName());
|
||||
assertEquals(null, diff.getLeft().getPropertyValue());
|
||||
|
||||
// Table tbl_has_diff_pk has PK of "id" in left and "nodeRef" in right
|
||||
diff = it.next();
|
||||
assertEquals(Where.ONLY_IN_LEFT, diff.getWhere());
|
||||
assertEquals("left_schema.tbl_has_diff_pk.pk_is_diff.columnNames[0]", diff.getLeft().getPath());
|
||||
assertEquals("right_schema.tbl_has_diff_pk.pk_is_diff.columnNames", diff.getRight().getPath());
|
||||
assertEquals("columnNames[0]", diff.getLeft().getPropertyName());
|
||||
assertEquals("id", diff.getLeft().getPropertyValue());
|
||||
assertEquals("columnNames", diff.getRight().getPropertyName());
|
||||
assertEquals(Arrays.asList("nodeRef"), diff.getRight().getPropertyValue());
|
||||
|
||||
// Table tbl_has_diff_pk has PK of "id" in left and "nodeRef" in right
|
||||
diff = it.next();
|
||||
assertEquals(Where.ONLY_IN_RIGHT, diff.getWhere());
|
||||
assertEquals("left_schema.tbl_has_diff_pk.pk_is_diff.columnNames", diff.getLeft().getPath());
|
||||
assertEquals("right_schema.tbl_has_diff_pk.pk_is_diff.columnNames[0]", diff.getRight().getPath());
|
||||
assertEquals("columnNames", diff.getLeft().getPropertyName());
|
||||
assertEquals(Arrays.asList("id"), diff.getLeft().getPropertyValue());
|
||||
assertEquals("columnNames[0]", diff.getRight().getPropertyName());
|
||||
assertEquals("nodeRef", diff.getRight().getPropertyValue());
|
||||
|
||||
// Table table_in_right does not exist in the left schema
|
||||
}
|
||||
|
||||
|
||||
@ -145,111 +147,11 @@ public class SchemaComparatorTest
|
||||
System.out.println(r);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void canReportWarnings()
|
||||
{
|
||||
// Left hand side's database objects.
|
||||
left.add(new Table("tbl_example", columns("id NUMBER(10)"), pk("pk_tbl_example", "id"), fkeys(),
|
||||
indexes("idx_specified_name id")));
|
||||
|
||||
// Right hand side's database objects.
|
||||
right.add(new Table("tbl_example", columns("id NUMBER(10)"), pk("pk_tbl_example", "id"), fkeys(),
|
||||
indexes("sys_random_idx_name id")));
|
||||
|
||||
|
||||
comparator = new SchemaComparator(left, right, dialect);
|
||||
comparator.validateAndCompare();
|
||||
|
||||
dumpDiffs(comparator.getDifferences(), true);
|
||||
dumpValidation(comparator.getValidationResults());
|
||||
|
||||
Iterator<Result> it = comparator.getDifferences().iterator();
|
||||
assertHasDifference("left_schema", "left_schema", "right_schema", it.next());
|
||||
assertNoDifference("left_schema.tbl_example", "tbl_example", it.next());
|
||||
assertNoDifference("left_schema.tbl_example.id", "id", it.next());
|
||||
assertNoDifference("left_schema.tbl_example.id", "NUMBER(10)", it.next());
|
||||
assertNoDifference("left_schema.tbl_example.id", Boolean.FALSE, it.next());
|
||||
assertNoDifference("left_schema.tbl_example.pk_tbl_example", "pk_tbl_example", it.next());
|
||||
assertNoDifference("left_schema.tbl_example.pk_tbl_example", "id", it.next());
|
||||
|
||||
assertHasWarning(
|
||||
"left_schema.tbl_example.idx_specified_name",
|
||||
"idx_specified_name",
|
||||
"sys_random_idx_name",
|
||||
it.next());
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the result shows the value to have different values in the left and right items.
|
||||
*/
|
||||
private void assertHasDifference(String path, Object leftValue, Object rightValue,
|
||||
Result result, Strength strength)
|
||||
{
|
||||
assertEquals(strength, result.getStrength());
|
||||
assertEquals(Where.IN_BOTH_BUT_DIFFERENCE, result.getWhere());
|
||||
assertEquals(path, result.getPath());
|
||||
assertEquals(leftValue, result.getLeft());
|
||||
assertEquals(rightValue, result.getRight());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #assertHasDifference(String, Object, Object, Result, Strength)
|
||||
*/
|
||||
private void assertHasDifference(String path, Object leftValue, Object rightValue, Result result)
|
||||
{
|
||||
assertHasDifference(path, leftValue, rightValue, result, Strength.ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #assertHasDifference(String, Object, Object, Result, Strength)
|
||||
*/
|
||||
private void assertHasWarning(String path, Object leftValue, Object rightValue, Result result)
|
||||
{
|
||||
assertHasDifference(path, leftValue, rightValue, result, Strength.WARN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the result shows the value to be present only in either the left or right items.
|
||||
*/
|
||||
private void assertOnlyInOne(String path, Where which, Object value, Result result)
|
||||
{
|
||||
assertEquals(which, result.getWhere());
|
||||
assertEquals(path, result.getPath());
|
||||
|
||||
if (which == Where.ONLY_IN_LEFT)
|
||||
{
|
||||
assertEquals(value, result.getLeft());
|
||||
assertNull(result.getRight());
|
||||
}
|
||||
else if (which == Where.ONLY_IN_RIGHT)
|
||||
{
|
||||
assertNull(result.getLeft());
|
||||
assertEquals(value, result.getRight());
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalArgumentException("The 'which' argument should be ONLY_IN_LEFT or ONLY_IN_RIGHT.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the result shows no differences between the left and right items.
|
||||
*/
|
||||
private void assertNoDifference(String path, Object value, Result result)
|
||||
{
|
||||
assertEquals(Where.IN_BOTH_NO_DIFFERENCE, result.getWhere());
|
||||
assertEquals(path, result.getPath());
|
||||
assertEquals(value, result.getLeft());
|
||||
assertEquals(value, result.getRight());
|
||||
}
|
||||
|
||||
|
||||
private void dumpDiffs(Differences differences, boolean showNonDifferences)
|
||||
private void dumpDiffs(Results differences, boolean showNonDifferences)
|
||||
{
|
||||
System.out.println("Differences (" + differences.size() + ")");
|
||||
for (Result d : differences)
|
||||
for (Difference d : differences)
|
||||
{
|
||||
if (d.getWhere() != Where.IN_BOTH_NO_DIFFERENCE || showNonDifferences)
|
||||
{
|
||||
@ -260,7 +162,7 @@ public class SchemaComparatorTest
|
||||
|
||||
private Table table(String name)
|
||||
{
|
||||
return new Table(name, columns("id NUMBER(10)"), pk("pk_" + name, "id"), fkeys(), indexes());
|
||||
return new Table(null, name, columns("id NUMBER(10)"), pk("pk_" + name, "id"), fkeys(), indexes());
|
||||
}
|
||||
|
||||
private Collection<Column> columns(String... colDefs)
|
||||
@ -271,7 +173,7 @@ public class SchemaComparatorTest
|
||||
for (int i = 0; i < colDefs.length; i++)
|
||||
{
|
||||
String[] parts = colDefs[i].split(" ");
|
||||
columns[i] = new Column(parts[0], parts[1], false);
|
||||
columns[i] = new Column(null, parts[0], parts[1], false);
|
||||
}
|
||||
return Arrays.asList(columns);
|
||||
}
|
||||
@ -279,7 +181,7 @@ public class SchemaComparatorTest
|
||||
private PrimaryKey pk(String name, String... columnNames)
|
||||
{
|
||||
assertTrue("No columns specified", columnNames.length > 0);
|
||||
PrimaryKey pk = new PrimaryKey(name, Arrays.asList(columnNames));
|
||||
PrimaryKey pk = new PrimaryKey(null, name, Arrays.asList(columnNames));
|
||||
return pk;
|
||||
}
|
||||
|
||||
@ -290,7 +192,7 @@ public class SchemaComparatorTest
|
||||
|
||||
private ForeignKey fk(String fkName, String localColumn, String targetTable, String targetColumn)
|
||||
{
|
||||
return new ForeignKey(fkName, localColumn, targetTable, targetColumn);
|
||||
return new ForeignKey(null, fkName, localColumn, targetTable, targetColumn);
|
||||
}
|
||||
|
||||
private Collection<Index> indexes(String... indexDefs)
|
||||
@ -301,7 +203,7 @@ public class SchemaComparatorTest
|
||||
String[] parts = indexDefs[i].split(" ");
|
||||
String name = parts[0];
|
||||
String[] columns = (String[]) ArrayUtils.subarray(parts, 1, parts.length);
|
||||
indexes[i] = new Index(name, Arrays.asList(columns));
|
||||
indexes[i] = new Index(null, name, Arrays.asList(columns));
|
||||
}
|
||||
return Arrays.asList(indexes);
|
||||
}
|
||||
|
@ -19,10 +19,9 @@
|
||||
package org.alfresco.util.schemacomp;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import static org.junit.Assert.assertSame;
|
||||
|
||||
import javax.faces.validator.Validator;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.alfresco.util.schemacomp.model.Column;
|
||||
import org.alfresco.util.schemacomp.model.ForeignKey;
|
||||
@ -33,17 +32,14 @@ import org.alfresco.util.schemacomp.model.Sequence;
|
||||
import org.alfresco.util.schemacomp.model.Table;
|
||||
import org.alfresco.util.schemacomp.validator.DbValidator;
|
||||
import org.alfresco.util.schemacomp.validator.NameValidator;
|
||||
import org.alfresco.util.schemacomp.validator.NullValidator;
|
||||
import org.hibernate.dialect.MySQL5InnoDBDialect;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.validateMockitoUsage;
|
||||
|
||||
/**
|
||||
* TODO: comment me!
|
||||
* Tests for the ValidatingVisitor class.
|
||||
*
|
||||
* @author Matt Ward
|
||||
*/
|
||||
public class ValidatingVisitorTest
|
||||
@ -54,7 +50,7 @@ public class ValidatingVisitorTest
|
||||
@Before
|
||||
public void setUp() throws Exception
|
||||
{
|
||||
ctx = new DiffContext(new MySQL5InnoDBDialect(), new Differences(), new ArrayList<ValidationResult>());
|
||||
ctx = new DiffContext(new MySQL5InnoDBDialect(), new Results(), new ArrayList<ValidationResult>());
|
||||
visitor = new ValidatingVisitor(ctx);
|
||||
}
|
||||
|
||||
@ -78,7 +74,7 @@ public class ValidatingVisitorTest
|
||||
public void canValidate()
|
||||
{
|
||||
visitor.indexNameValidator = Mockito.mock(NameValidator.class);
|
||||
Index index = new Index("index_name", new ArrayList<String>());
|
||||
Index index = new Index(null, "index_name", new ArrayList<String>());
|
||||
|
||||
visitor.visit(index);
|
||||
|
||||
|
@ -19,26 +19,48 @@
|
||||
package org.alfresco.util.schemacomp;
|
||||
|
||||
/**
|
||||
* TODO: comment me!
|
||||
* Results of a validation operation.
|
||||
*
|
||||
* @author Matt Ward
|
||||
*/
|
||||
public class ValidationResult
|
||||
public class ValidationResult extends Result
|
||||
{
|
||||
private Object value;
|
||||
private DbProperty dbProperty;
|
||||
|
||||
/**
|
||||
* @param value
|
||||
*/
|
||||
public ValidationResult(Object value)
|
||||
|
||||
public ValidationResult(DbProperty dbProperty)
|
||||
{
|
||||
this.value = value;
|
||||
this(dbProperty, null);
|
||||
}
|
||||
|
||||
public ValidationResult(DbProperty dbProperty, Strength strength)
|
||||
{
|
||||
super(strength);
|
||||
this.dbProperty = dbProperty;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the dbProperty that was rejected.
|
||||
*/
|
||||
public DbProperty getDbProperty()
|
||||
{
|
||||
return this.dbProperty;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the value
|
||||
* @param dbProperty the dbProperty to set
|
||||
*/
|
||||
public void setDbProperty(DbProperty dbProperty)
|
||||
{
|
||||
this.dbProperty = dbProperty;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the value that was rejected.
|
||||
*/
|
||||
public Object getValue()
|
||||
{
|
||||
return this.value;
|
||||
return this.dbProperty.getPropertyValue();
|
||||
}
|
||||
}
|
||||
|
@ -18,17 +18,12 @@
|
||||
*/
|
||||
package org.alfresco.util.schemacomp.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.util.schemacomp.ComparisonUtils;
|
||||
import org.alfresco.util.schemacomp.DbObjectVisitor;
|
||||
import org.alfresco.util.schemacomp.DiffContext;
|
||||
import org.alfresco.util.schemacomp.Differences;
|
||||
import org.alfresco.util.schemacomp.Result.Strength;
|
||||
import org.alfresco.util.schemacomp.DbProperty;
|
||||
import org.alfresco.util.schemacomp.DefaultComparisonUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.alfresco.util.schemacomp.DiffContext;
|
||||
import org.alfresco.util.schemacomp.Result.Strength;
|
||||
import org.alfresco.util.schemacomp.Results;
|
||||
|
||||
/**
|
||||
* Useful base class for many, if not all the {@link DbObject} implementations.
|
||||
@ -37,25 +32,22 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
public abstract class AbstractDbObject implements DbObject
|
||||
{
|
||||
private DbObject parent;
|
||||
private String name;
|
||||
/** How differences in the name field should be reported */
|
||||
private Strength nameStrength = Strength.ERROR;
|
||||
protected ComparisonUtils comparisonUtils = new DefaultComparisonUtils();
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public AbstractDbObject()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate, giving the object a name.
|
||||
* Instantiate, giving the object a parent and a name.
|
||||
*
|
||||
* @param parent
|
||||
* @param name
|
||||
*/
|
||||
public AbstractDbObject(String name)
|
||||
public AbstractDbObject(DbObject parent, String name)
|
||||
{
|
||||
this.parent = parent;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@ -152,8 +144,8 @@ public abstract class AbstractDbObject implements DbObject
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides an implementation of {@link DbObject#diff(DbObject, Differences)}. The template
|
||||
* method {@link #doDiff(DbObject, Differences)} provides the subclass specific diffing logic,
|
||||
* Provides an implementation of {@link DbObject#diff(DbObject, Results)}. The template
|
||||
* method {@link #doDiff(DbObject, Results)} provides the subclass specific diffing logic,
|
||||
* whilst this method handles the workflow required in most cases: set the path's prefix that will be
|
||||
* used to explain where differences occur; compare the name fields of the two objects; delegate to the
|
||||
* subclass specific diffing (if any); remove the last path addition ready for the next object to perform
|
||||
@ -161,23 +153,30 @@ public abstract class AbstractDbObject implements DbObject
|
||||
*/
|
||||
@Override
|
||||
public void diff(DbObject right, DiffContext ctx, Strength strength)
|
||||
{
|
||||
Differences differences = ctx.getDifferences();
|
||||
{
|
||||
DbProperty leftNameProp = new DbProperty(this, "name");
|
||||
DbProperty rightNameProp = new DbProperty(right, "name");
|
||||
|
||||
comparisonUtils.compareSimple(leftNameProp, rightNameProp, ctx, getNameStrength());
|
||||
|
||||
if (name != null && StringUtils.hasText(name))
|
||||
{
|
||||
differences.pushPath(name);
|
||||
}
|
||||
else
|
||||
{
|
||||
differences.pushPath("<" + getClass().getSimpleName() + ">");
|
||||
}
|
||||
comparisonUtils.compareSimple(name, right.getName(), ctx, getNameStrength());
|
||||
doDiff(right, ctx, strength);
|
||||
differences.popPath();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public DbObject getParent()
|
||||
{
|
||||
return parent;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setParent(DbObject parent)
|
||||
{
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Override this method to provide subclass specific diffing logic.
|
||||
*
|
||||
|
@ -26,10 +26,11 @@ import static org.mockito.Mockito.inOrder;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.alfresco.util.schemacomp.DbObjectVisitor;
|
||||
import org.alfresco.util.schemacomp.DbProperty;
|
||||
import org.alfresco.util.schemacomp.DiffContext;
|
||||
import org.alfresco.util.schemacomp.Differences;
|
||||
import org.alfresco.util.schemacomp.Difference.Where;
|
||||
import org.alfresco.util.schemacomp.Result.Strength;
|
||||
import org.alfresco.util.schemacomp.Result.Where;
|
||||
import org.alfresco.util.schemacomp.Results;
|
||||
import org.alfresco.util.schemacomp.ValidationResult;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.junit.Before;
|
||||
@ -48,7 +49,7 @@ import org.mockito.runners.MockitoJUnitRunner;
|
||||
public class AbstractDbObjectTest
|
||||
{
|
||||
private ConcreteDbObject dbObject;
|
||||
private @Mock Differences differences;
|
||||
private @Mock Results differences;
|
||||
private DiffContext ctx;
|
||||
private @Mock Dialect dialect;
|
||||
|
||||
@ -93,37 +94,52 @@ public class AbstractDbObjectTest
|
||||
dbObject.diff(otherObject, ctx, Strength.ERROR);
|
||||
|
||||
InOrder inOrder = inOrder(differences);
|
||||
// The name of the object should be pushed on to the differences path.
|
||||
inOrder.verify(differences).pushPath("the_object");
|
||||
|
||||
// The name of the object should be diffed
|
||||
inOrder.verify(differences).add(Where.IN_BOTH_BUT_DIFFERENCE, "the_object", "the_other_object", Strength.WARN);
|
||||
inOrder.verify(differences).add(
|
||||
Where.IN_BOTH_BUT_DIFFERENCE,
|
||||
new DbProperty(dbObject, "name"),
|
||||
new DbProperty(otherObject, "name"),
|
||||
Strength.WARN);
|
||||
|
||||
// Then the doDiff() method should be processed
|
||||
inOrder.verify(differences).add(Where.IN_BOTH_BUT_DIFFERENCE, "left", "right");
|
||||
// Later, the path should be popped again
|
||||
inOrder.verify(differences).popPath();
|
||||
inOrder.verify(differences).add(
|
||||
Where.IN_BOTH_BUT_DIFFERENCE,
|
||||
new DbProperty(dbObject, "someProp"),
|
||||
new DbProperty(otherObject, "someProp"));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Concrete DbObject for testing the AbstractDbObject base class.
|
||||
*/
|
||||
private static class ConcreteDbObject extends AbstractDbObject
|
||||
public static class ConcreteDbObject extends AbstractDbObject
|
||||
{
|
||||
private String someProp = "property value";
|
||||
|
||||
public ConcreteDbObject(String name)
|
||||
{
|
||||
super(name);
|
||||
super(null, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doDiff(DbObject right, DiffContext ctx, Strength strength)
|
||||
{
|
||||
Differences differences = ctx.getDifferences();
|
||||
differences.add(Where.IN_BOTH_BUT_DIFFERENCE, "left", "right");
|
||||
Results differences = ctx.getDifferences();
|
||||
differences.add(
|
||||
Where.IN_BOTH_BUT_DIFFERENCE,
|
||||
new DbProperty(this, "someProp"),
|
||||
new DbProperty(right, "someProp"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(DbObjectVisitor visitor)
|
||||
{
|
||||
}
|
||||
|
||||
public String getSomeProp()
|
||||
{
|
||||
return this.someProp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,8 +19,9 @@
|
||||
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.Differences;
|
||||
import org.alfresco.util.schemacomp.Results;
|
||||
import org.alfresco.util.schemacomp.Result.Strength;
|
||||
|
||||
/**
|
||||
@ -37,13 +38,14 @@ public class Column extends AbstractDbObject
|
||||
/**
|
||||
* Construct a Column.
|
||||
*
|
||||
* @table the parent table
|
||||
* @param name
|
||||
* @param type
|
||||
* @param nullable
|
||||
*/
|
||||
public Column(String name, String type, boolean nullable)
|
||||
public Column(Table table, String name, String type, boolean nullable)
|
||||
{
|
||||
super(name);
|
||||
super(table, name);
|
||||
this.type = type;
|
||||
this.nullable = nullable;
|
||||
}
|
||||
@ -109,10 +111,16 @@ public class Column extends AbstractDbObject
|
||||
@Override
|
||||
protected void doDiff(DbObject right, DiffContext ctx, Strength strength)
|
||||
{
|
||||
Differences differences = ctx.getDifferences();
|
||||
Column rightColumn = (Column) right;
|
||||
comparisonUtils.compareSimple(type, rightColumn.type, ctx);
|
||||
comparisonUtils.compareSimple(nullable, rightColumn.nullable, ctx);
|
||||
Results differences = ctx.getDifferences();
|
||||
DbProperty thisTypeProp = new DbProperty(this, "type");
|
||||
DbProperty thisNullableProp = new DbProperty(this, "nullable");
|
||||
|
||||
Column thatColumn = (Column) right;
|
||||
DbProperty thatTypeProp = new DbProperty(thatColumn, "type");
|
||||
DbProperty thatNullableProp = new DbProperty(thatColumn, "nullable");
|
||||
|
||||
comparisonUtils.compareSimple(thisTypeProp, thatTypeProp, ctx);
|
||||
comparisonUtils.compareSimple(thisNullableProp, thatNullableProp, ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -19,6 +19,7 @@
|
||||
package org.alfresco.util.schemacomp.model;
|
||||
|
||||
|
||||
import org.alfresco.util.schemacomp.DbProperty;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import static org.mockito.Mockito.*;
|
||||
@ -36,8 +37,8 @@ public class ColumnTest extends DbObjectTestBase<Column>
|
||||
@Before
|
||||
public void setUp() throws Exception
|
||||
{
|
||||
thisColumn = new Column("this_column", "VARCHAR2(100)", false);
|
||||
thatColumn = new Column("this_column", "NUMBER(10)", true);
|
||||
thisColumn = new Column(null, "this_column", "VARCHAR2(100)", false);
|
||||
thatColumn = new Column(null, "that_column", "NUMBER(10)", true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -55,8 +56,14 @@ public class ColumnTest extends DbObjectTestBase<Column>
|
||||
@Override
|
||||
protected void doDiffTests()
|
||||
{
|
||||
inOrder.verify(comparisonUtils).compareSimple(thisColumn.getType(), thatColumn.getType(), ctx);
|
||||
inOrder.verify(comparisonUtils).compareSimple(thisColumn.isNullable(), thatColumn.isNullable(), ctx);
|
||||
DbProperty thisTypeProp = new DbProperty(thisColumn, "type");
|
||||
DbProperty thatTypeProp = new DbProperty(thatColumn, "type");
|
||||
inOrder.verify(comparisonUtils).compareSimple(thisTypeProp, thatTypeProp, ctx);
|
||||
|
||||
DbProperty thisNullableProp = new DbProperty(thisColumn, "nullable");
|
||||
DbProperty thatNullableProp = new DbProperty(thatColumn, "nullable");
|
||||
|
||||
inOrder.verify(comparisonUtils).compareSimple(thisNullableProp, thatNullableProp, ctx);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -20,7 +20,7 @@ package org.alfresco.util.schemacomp.model;
|
||||
|
||||
import org.alfresco.util.schemacomp.DbObjectVisitor;
|
||||
import org.alfresco.util.schemacomp.DiffContext;
|
||||
import org.alfresco.util.schemacomp.Differences;
|
||||
import org.alfresco.util.schemacomp.Results;
|
||||
import org.alfresco.util.schemacomp.Result.Strength;
|
||||
|
||||
/**
|
||||
@ -54,7 +54,7 @@ public interface DbObject
|
||||
|
||||
/**
|
||||
* Generate a report of differences between this object ('left') and another object ('right').
|
||||
* Differences between the left and right objects under inspection are captured in the {@link Differences}
|
||||
* Differences between the left and right objects under inspection are captured in the {@link Results}
|
||||
* object passed in to this method.
|
||||
*
|
||||
* @param right The object to compare against.
|
||||
@ -70,4 +70,20 @@ public interface DbObject
|
||||
* @param visitor
|
||||
*/
|
||||
void accept(DbObjectVisitor visitor);
|
||||
|
||||
/**
|
||||
* Get the parent object for which this object is a child. If this is the root object
|
||||
* then null should be returned.
|
||||
*
|
||||
* @return Parent reference or null
|
||||
*/
|
||||
DbObject getParent();
|
||||
|
||||
/**
|
||||
* Sets the parent object.
|
||||
*
|
||||
* @see #getParent()
|
||||
* @param parent
|
||||
*/
|
||||
void setParent(DbObject parent);
|
||||
}
|
||||
|
@ -25,8 +25,9 @@ import java.util.List;
|
||||
|
||||
import org.alfresco.util.schemacomp.ComparisonUtils;
|
||||
import org.alfresco.util.schemacomp.DbObjectVisitor;
|
||||
import org.alfresco.util.schemacomp.DbProperty;
|
||||
import org.alfresco.util.schemacomp.DiffContext;
|
||||
import org.alfresco.util.schemacomp.Differences;
|
||||
import org.alfresco.util.schemacomp.Results;
|
||||
import org.alfresco.util.schemacomp.Result.Strength;
|
||||
import org.alfresco.util.schemacomp.ValidationResult;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
@ -46,7 +47,7 @@ import org.mockito.runners.MockitoJUnitRunner;
|
||||
public abstract class DbObjectTestBase<T extends AbstractDbObject>
|
||||
{
|
||||
protected @Mock Dialect dialect;
|
||||
protected @Mock Differences differences;
|
||||
protected @Mock Results differences;
|
||||
protected DiffContext ctx;
|
||||
protected @Mock ComparisonUtils comparisonUtils;
|
||||
protected InOrder inOrder;
|
||||
@ -89,21 +90,15 @@ public abstract class DbObjectTestBase<T extends AbstractDbObject>
|
||||
// Invoke the method under test
|
||||
thisObject.diff(thatObject, ctx, Strength.ERROR);
|
||||
|
||||
// The name of the object should be pushed on to the differences path.
|
||||
inOrder.verify(differences).pushPath(thisObject.getName());
|
||||
|
||||
// The name of the object should be diffed
|
||||
inOrder.verify(comparisonUtils).compareSimple(
|
||||
thisObject.getName(),
|
||||
thatObject.getName(),
|
||||
new DbProperty(thisObject, "name"),
|
||||
new DbProperty(thatObject, "name"),
|
||||
ctx,
|
||||
thisObject.getNameStrength());
|
||||
|
||||
// Then the doDiff() method should be processed...
|
||||
doDiffTests();
|
||||
|
||||
// Later, the path should be popped again
|
||||
inOrder.verify(differences).popPath();
|
||||
}
|
||||
|
||||
protected abstract void doDiffTests();
|
||||
|
@ -19,8 +19,9 @@
|
||||
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.Differences;
|
||||
import org.alfresco.util.schemacomp.Results;
|
||||
import org.alfresco.util.schemacomp.Result.Strength;
|
||||
|
||||
|
||||
@ -40,14 +41,15 @@ public class ForeignKey extends AbstractDbObject
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param table the parent table
|
||||
* @param fkName
|
||||
* @param localColumn
|
||||
* @param targetTable
|
||||
* @param targetColumn
|
||||
*/
|
||||
public ForeignKey(String fkName, String localColumn, String targetTable, String targetColumn)
|
||||
public ForeignKey(Table table, String fkName, String localColumn, String targetTable, String targetColumn)
|
||||
{
|
||||
super(fkName);
|
||||
super(table, fkName);
|
||||
this.localColumn = localColumn;
|
||||
this.targetTable = targetTable;
|
||||
this.targetColumn = targetColumn;
|
||||
@ -141,11 +143,19 @@ public class ForeignKey extends AbstractDbObject
|
||||
@Override
|
||||
protected void doDiff(DbObject right, DiffContext ctx, Strength strength)
|
||||
{
|
||||
Differences differences = ctx.getDifferences();
|
||||
ForeignKey rightFK = (ForeignKey) right;
|
||||
comparisonUtils.compareSimple(localColumn, rightFK.localColumn, ctx);
|
||||
comparisonUtils.compareSimple(targetTable, rightFK.targetTable, ctx);
|
||||
comparisonUtils.compareSimple(targetColumn, rightFK.targetColumn, ctx);
|
||||
ForeignKey thatFK = (ForeignKey) right;
|
||||
comparisonUtils.compareSimple(
|
||||
new DbProperty(this, "localColumn"),
|
||||
new DbProperty(thatFK, "localColumn"),
|
||||
ctx);
|
||||
comparisonUtils.compareSimple(
|
||||
new DbProperty(this, "targetTable"),
|
||||
new DbProperty(thatFK, "targetTable"),
|
||||
ctx);
|
||||
comparisonUtils.compareSimple(
|
||||
new DbProperty(this, "targetColumn"),
|
||||
new DbProperty(thatFK, "targetColumn"),
|
||||
ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -21,6 +21,7 @@ package org.alfresco.util.schemacomp.model;
|
||||
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import org.alfresco.util.schemacomp.DbProperty;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
@ -37,8 +38,8 @@ public class ForeignKeyTest extends DbObjectTestBase<ForeignKey>
|
||||
@Before
|
||||
public void setUp() throws Exception
|
||||
{
|
||||
thisFK = new ForeignKey("this_fk", "local_col", "target_table", "target_col");
|
||||
thatFK = new ForeignKey("that_fk", "local_col", "target_table", "target_col");
|
||||
thisFK = new ForeignKey(null, "this_fk", "local_col", "target_table", "target_col");
|
||||
thatFK = new ForeignKey(null, "that_fk", "local_col", "target_table", "target_col");
|
||||
}
|
||||
|
||||
|
||||
@ -59,9 +60,18 @@ public class ForeignKeyTest extends DbObjectTestBase<ForeignKey>
|
||||
@Override
|
||||
protected void doDiffTests()
|
||||
{
|
||||
inOrder.verify(comparisonUtils).compareSimple(thisFK.getLocalColumn(), thatFK.getLocalColumn(), ctx);
|
||||
inOrder.verify(comparisonUtils).compareSimple(thisFK.getTargetTable(), thatFK.getTargetTable(), ctx);
|
||||
inOrder.verify(comparisonUtils).compareSimple(thisFK.getTargetColumn(), thatFK.getTargetColumn(), ctx);
|
||||
inOrder.verify(comparisonUtils).compareSimple(
|
||||
new DbProperty(thisFK, "localColumn"),
|
||||
new DbProperty(thatFK, "localColumn"),
|
||||
ctx);
|
||||
inOrder.verify(comparisonUtils).compareSimple(
|
||||
new DbProperty(thisFK, "targetTable"),
|
||||
new DbProperty(thatFK, "targetTable"),
|
||||
ctx);
|
||||
inOrder.verify(comparisonUtils).compareSimple(
|
||||
new DbProperty(thisFK, "targetColumn"),
|
||||
new DbProperty(thatFK, "targetColumn"),
|
||||
ctx);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -21,8 +21,8 @@ package org.alfresco.util.schemacomp.model;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.util.schemacomp.DbObjectVisitor;
|
||||
import org.alfresco.util.schemacomp.DbProperty;
|
||||
import org.alfresco.util.schemacomp.DiffContext;
|
||||
import org.alfresco.util.schemacomp.Differences;
|
||||
import org.alfresco.util.schemacomp.Result.Strength;
|
||||
|
||||
/**
|
||||
@ -36,11 +36,12 @@ public class Index extends AbstractDbObject
|
||||
|
||||
|
||||
/**
|
||||
* @param table the parent table
|
||||
* @param columnNames
|
||||
*/
|
||||
public Index(String name, List<String> columnNames)
|
||||
public Index(Table table, String name, List<String> columnNames)
|
||||
{
|
||||
super(name);
|
||||
super(table, name);
|
||||
this.columnNames = columnNames;
|
||||
setNameStrength(Strength.WARN);
|
||||
}
|
||||
@ -112,9 +113,12 @@ public class Index extends AbstractDbObject
|
||||
@Override
|
||||
protected void doDiff(DbObject right, DiffContext ctx, Strength strength)
|
||||
{
|
||||
Differences differences = ctx.getDifferences();
|
||||
Index rightIndex = (Index) right;
|
||||
comparisonUtils.compareSimpleCollections(columnNames, rightIndex.columnNames, ctx, strength);
|
||||
comparisonUtils.compareSimpleCollections(
|
||||
new DbProperty(this, "columnNames"),
|
||||
new DbProperty(rightIndex, "columnNames"),
|
||||
ctx,
|
||||
strength);
|
||||
}
|
||||
|
||||
|
||||
|
@ -20,6 +20,7 @@ package org.alfresco.util.schemacomp.model;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.alfresco.util.schemacomp.DbProperty;
|
||||
import org.alfresco.util.schemacomp.Result.Strength;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@ -39,8 +40,8 @@ public class IndexTest extends DbObjectTestBase<Index>
|
||||
@Before
|
||||
public void setUp()
|
||||
{
|
||||
thisIndex = new Index("this_index", Arrays.asList("id", "name", "age"));
|
||||
thatIndex = new Index("that_index", Arrays.asList("a", "b"));
|
||||
thisIndex = new Index(null, "this_index", Arrays.asList("id", "name", "age"));
|
||||
thatIndex = new Index(null, "that_index", Arrays.asList("a", "b"));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -59,8 +60,8 @@ public class IndexTest extends DbObjectTestBase<Index>
|
||||
protected void doDiffTests()
|
||||
{
|
||||
inOrder.verify(comparisonUtils).compareSimpleCollections(
|
||||
thisIndex.getColumnNames(),
|
||||
thatIndex.getColumnNames(),
|
||||
new DbProperty(thisIndex, "columnNames"),
|
||||
new DbProperty(thatIndex, "columnNames"),
|
||||
ctx,
|
||||
Strength.ERROR);
|
||||
}
|
||||
@ -77,19 +78,19 @@ public class IndexTest extends DbObjectTestBase<Index>
|
||||
public void sameAs()
|
||||
{
|
||||
assertTrue("Indexes should be logically the same.",
|
||||
thisIndex.sameAs(new Index("this_index", Arrays.asList("id", "name", "age"))));
|
||||
thisIndex.sameAs(new Index(null, "this_index", Arrays.asList("id", "name", "age"))));
|
||||
|
||||
assertTrue("Indexes should be logically the same, despite different names (as same column order)",
|
||||
thisIndex.sameAs(new Index("different_name", Arrays.asList("id", "name", "age"))));
|
||||
thisIndex.sameAs(new Index(null, "different_name", Arrays.asList("id", "name", "age"))));
|
||||
|
||||
assertTrue("Indexes should be identified as the same despite different column order (as same name).",
|
||||
thisIndex.sameAs(new Index("this_index", Arrays.asList("name", "id", "age"))));
|
||||
thisIndex.sameAs(new Index(null, "this_index", Arrays.asList("name", "id", "age"))));
|
||||
|
||||
assertFalse("Indexes should be identified different (different name and column order)",
|
||||
thisIndex.sameAs(new Index("different_name", Arrays.asList("name", "id", "age"))));
|
||||
thisIndex.sameAs(new Index(null, "different_name", Arrays.asList("name", "id", "age"))));
|
||||
|
||||
assertFalse("Indexes should be identified different (different name & different columns)",
|
||||
thisIndex.sameAs(new Index("different_name", Arrays.asList("node_ref", "url"))));
|
||||
thisIndex.sameAs(new Index(null, "different_name", Arrays.asList("node_ref", "url"))));
|
||||
}
|
||||
|
||||
|
||||
|
@ -21,8 +21,8 @@ package org.alfresco.util.schemacomp.model;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.util.schemacomp.DbObjectVisitor;
|
||||
import org.alfresco.util.schemacomp.DbProperty;
|
||||
import org.alfresco.util.schemacomp.DiffContext;
|
||||
import org.alfresco.util.schemacomp.Differences;
|
||||
import org.alfresco.util.schemacomp.Result.Strength;
|
||||
|
||||
/**
|
||||
@ -37,12 +37,13 @@ public class PrimaryKey extends AbstractDbObject
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param table the parent table
|
||||
* @param name
|
||||
* @param columnNames
|
||||
*/
|
||||
public PrimaryKey(String name, List<String> columnNames)
|
||||
public PrimaryKey(Table table, String name, List<String> columnNames)
|
||||
{
|
||||
super(name);
|
||||
super(table, name);
|
||||
this.columnNames = columnNames;
|
||||
}
|
||||
|
||||
@ -89,9 +90,12 @@ public class PrimaryKey extends AbstractDbObject
|
||||
@Override
|
||||
protected void doDiff(DbObject right, DiffContext ctx, Strength strength)
|
||||
{
|
||||
Differences differences = ctx.getDifferences();
|
||||
PrimaryKey rightPK = (PrimaryKey) right;
|
||||
comparisonUtils.compareSimpleCollections(columnNames, rightPK.columnNames, ctx, strength);
|
||||
comparisonUtils.compareSimpleCollections(
|
||||
new DbProperty(this, "columnNames"),
|
||||
new DbProperty(rightPK, "columnNames"),
|
||||
ctx,
|
||||
strength);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -22,6 +22,7 @@ import static org.mockito.Mockito.verify;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.alfresco.util.schemacomp.DbProperty;
|
||||
import org.alfresco.util.schemacomp.Result.Strength;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@ -40,8 +41,8 @@ public class PrimaryKeyTest extends DbObjectTestBase<PrimaryKey>
|
||||
@Before
|
||||
public void setUp()
|
||||
{
|
||||
thisPK = new PrimaryKey("this_pk", Arrays.asList("id", "name", "age"));
|
||||
thatPK = new PrimaryKey("that_pk", Arrays.asList("a", "b"));
|
||||
thisPK = new PrimaryKey(null, "this_pk", Arrays.asList("id", "name", "age"));
|
||||
thatPK = new PrimaryKey(null, "that_pk", Arrays.asList("a", "b"));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -60,8 +61,8 @@ public class PrimaryKeyTest extends DbObjectTestBase<PrimaryKey>
|
||||
protected void doDiffTests()
|
||||
{
|
||||
inOrder.verify(comparisonUtils).compareSimpleCollections(
|
||||
thisPK.getColumnNames(),
|
||||
thatPK.getColumnNames(),
|
||||
new DbProperty(thisPK, "columnNames"),
|
||||
new DbProperty(thatPK, "columnNames"),
|
||||
ctx,
|
||||
Strength.ERROR);
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ import java.util.List;
|
||||
|
||||
import org.alfresco.util.schemacomp.DbObjectVisitor;
|
||||
import org.alfresco.util.schemacomp.DiffContext;
|
||||
import org.alfresco.util.schemacomp.Differences;
|
||||
import org.alfresco.util.schemacomp.Results;
|
||||
import org.alfresco.util.schemacomp.Result.Strength;
|
||||
|
||||
/**
|
||||
@ -43,11 +43,18 @@ public class Schema extends AbstractDbObject implements Iterable<DbObject>
|
||||
*/
|
||||
public Schema(String name)
|
||||
{
|
||||
super(name);
|
||||
super(null, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an object to this schema - this method will set this schema
|
||||
* as the object's parent.
|
||||
*
|
||||
* @param dbObject
|
||||
*/
|
||||
public void add(DbObject dbObject)
|
||||
{
|
||||
dbObject.setParent(this);
|
||||
objects.add(dbObject);
|
||||
}
|
||||
|
||||
@ -94,7 +101,6 @@ public class Schema extends AbstractDbObject implements Iterable<DbObject>
|
||||
@Override
|
||||
protected void doDiff(DbObject right, DiffContext ctx, Strength strength)
|
||||
{
|
||||
Differences differences = ctx.getDifferences();
|
||||
Schema rightSchema = (Schema) right;
|
||||
comparisonUtils.compareCollections(objects, rightSchema.objects, ctx);
|
||||
}
|
||||
|
@ -28,9 +28,9 @@ import org.alfresco.util.schemacomp.DbObjectVisitor;
|
||||
*/
|
||||
public class Sequence extends AbstractDbObject
|
||||
{
|
||||
public Sequence(String name)
|
||||
public Sequence(DbObject parent, String name)
|
||||
{
|
||||
super(name);
|
||||
super(parent, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -21,7 +21,6 @@ package org.alfresco.util.schemacomp.model;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
@ -36,8 +35,8 @@ public class SequenceTest extends DbObjectTestBase<Sequence>
|
||||
@Before
|
||||
public void setUp()
|
||||
{
|
||||
thisSequence = new Sequence("this_sequence");
|
||||
thatSequence = new Sequence("that_sequence");
|
||||
thisSequence = new Sequence(null, "this_sequence");
|
||||
thatSequence = new Sequence(null, "that_sequence");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -24,7 +24,6 @@ import java.util.List;
|
||||
|
||||
import org.alfresco.util.schemacomp.DbObjectVisitor;
|
||||
import org.alfresco.util.schemacomp.DiffContext;
|
||||
import org.alfresco.util.schemacomp.Differences;
|
||||
import org.alfresco.util.schemacomp.Result.Strength;
|
||||
|
||||
/**
|
||||
@ -34,28 +33,29 @@ import org.alfresco.util.schemacomp.Result.Strength;
|
||||
*/
|
||||
public class Table extends AbstractDbObject
|
||||
{
|
||||
private List<Column> columns = new ArrayList<Column>();
|
||||
private final List<Column> columns = new ArrayList<Column>();
|
||||
private PrimaryKey primaryKey;
|
||||
private List<ForeignKey> foreignKeys = new ArrayList<ForeignKey>();
|
||||
private List<Index> indexes = new ArrayList<Index>();
|
||||
private final List<ForeignKey> foreignKeys = new ArrayList<ForeignKey>();
|
||||
private final List<Index> indexes = new ArrayList<Index>();
|
||||
|
||||
|
||||
public Table(String name, Collection<Column> columns, PrimaryKey primaryKey,
|
||||
public Table(Schema parentSchema, String name, Collection<Column> columns, PrimaryKey primaryKey,
|
||||
Collection<ForeignKey> foreignKeys, Collection<Index> indexes)
|
||||
{
|
||||
super(name);
|
||||
super(parentSchema, name);
|
||||
if (columns != null)
|
||||
{
|
||||
this.columns.addAll(columns);
|
||||
setColumns(columns);
|
||||
}
|
||||
primaryKey.setParent(this);
|
||||
this.primaryKey = primaryKey;
|
||||
if (foreignKeys != null)
|
||||
{
|
||||
this.foreignKeys.addAll(foreignKeys);
|
||||
setForeignKeys(foreignKeys);
|
||||
}
|
||||
if (indexes != null)
|
||||
{
|
||||
this.indexes.addAll(indexes);
|
||||
setIndexes(indexes);
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,9 +72,15 @@ public class Table extends AbstractDbObject
|
||||
/**
|
||||
* @param columns the columns to set
|
||||
*/
|
||||
public void setColumns(List<Column> columns)
|
||||
public void setColumns(Collection<Column> columns)
|
||||
{
|
||||
this.columns = columns;
|
||||
this.columns.clear();
|
||||
this.columns.addAll(columns);
|
||||
|
||||
for (Column column : columns)
|
||||
{
|
||||
column.setParent(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -92,6 +98,7 @@ public class Table extends AbstractDbObject
|
||||
*/
|
||||
public void setPrimaryKey(PrimaryKey primaryKey)
|
||||
{
|
||||
primaryKey.setParent(this);
|
||||
this.primaryKey = primaryKey;
|
||||
}
|
||||
|
||||
@ -108,9 +115,15 @@ public class Table extends AbstractDbObject
|
||||
/**
|
||||
* @param foreignKeys the foreignKeys to set
|
||||
*/
|
||||
public void setForeignKeys(List<ForeignKey> foreignKeys)
|
||||
public void setForeignKeys(Collection<ForeignKey> foreignKeys)
|
||||
{
|
||||
this.foreignKeys = foreignKeys;
|
||||
this.foreignKeys.clear();
|
||||
this.foreignKeys.addAll(foreignKeys);
|
||||
|
||||
for (ForeignKey fk : foreignKeys)
|
||||
{
|
||||
fk.setParent(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -126,9 +139,15 @@ public class Table extends AbstractDbObject
|
||||
/**
|
||||
* @param indexes the indexes to set
|
||||
*/
|
||||
public void setIndexes(List<Index> indexes)
|
||||
public void setIndexes(Collection<Index> indexes)
|
||||
{
|
||||
this.indexes = indexes;
|
||||
this.indexes.clear();
|
||||
this.indexes.addAll(indexes);
|
||||
|
||||
for (Index index : indexes)
|
||||
{
|
||||
index.setParent(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -179,7 +198,6 @@ public class Table extends AbstractDbObject
|
||||
@Override
|
||||
protected void doDiff(DbObject other, DiffContext ctx, Strength strength)
|
||||
{
|
||||
Differences differences = ctx.getDifferences();
|
||||
Table rightTable = (Table) other;
|
||||
comparisonUtils.compareCollections(columns, rightTable.columns, ctx);
|
||||
primaryKey.diff(rightTable.primaryKey, ctx, strength);
|
||||
|
@ -19,17 +19,12 @@
|
||||
package org.alfresco.util.schemacomp.model;
|
||||
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.util.schemacomp.Result.Strength;
|
||||
import org.apache.poi.ss.formula.functions.Columns;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@ -56,26 +51,11 @@ public class TableTest extends DbObjectTestBase<Table>
|
||||
@Before
|
||||
public void setUp() throws Exception
|
||||
{
|
||||
/*columns = asList(
|
||||
new Column("columnA", "VARCHAR2(50)", false),
|
||||
new Column("columnB", "VARCHAR2(100)", false),
|
||||
new Column("columnC", "VARCHAR2(200)", true));
|
||||
|
||||
foreignKeys = asList(new ForeignKey("fk", "localcolumn", "targettable", "targetcolumn"));
|
||||
|
||||
indexes = asList(new Index("an_index", asList("columnA", "columnC")));
|
||||
|
||||
table = new Table("the_table", columns, primaryKey, foreignKeys, indexes);
|
||||
otherTable = new Table("the_other_table", columns, primaryKey, foreignKeys, indexes);*/
|
||||
|
||||
columns = listOfMocks(Column.class, 3);
|
||||
|
||||
foreignKeys = listOfMocks(ForeignKey.class, 1);
|
||||
|
||||
indexes = listOfMocks(Index.class, 1);
|
||||
|
||||
table = new Table("the_table", columns, primaryKey, foreignKeys, indexes);
|
||||
otherTable = new Table("the_other_table", columns, primaryKey, foreignKeys, indexes);
|
||||
table = new Table(null, "the_table", columns, primaryKey, foreignKeys, indexes);
|
||||
otherTable = new Table(null, "the_other_table", columns, primaryKey, foreignKeys, indexes);
|
||||
}
|
||||
|
||||
|
||||
|
@ -22,7 +22,9 @@ import org.alfresco.util.schemacomp.DiffContext;
|
||||
import org.alfresco.util.schemacomp.model.DbObject;
|
||||
|
||||
/**
|
||||
* TODO: comment me!
|
||||
* DbObject validators must implement this interface. DbValidator instances
|
||||
* are used by the ValidatingVisitor class.
|
||||
*
|
||||
* @author Matt Ward
|
||||
*/
|
||||
public interface DbValidator
|
||||
|
@ -22,6 +22,7 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.alfresco.util.schemacomp.DbProperty;
|
||||
import org.alfresco.util.schemacomp.DiffContext;
|
||||
import org.alfresco.util.schemacomp.ValidationResult;
|
||||
import org.alfresco.util.schemacomp.model.DbObject;
|
||||
@ -47,7 +48,7 @@ public class NameValidator implements DbValidator
|
||||
|
||||
Pattern pattern = namePatterns.get(ctx.getDialect().getClass());
|
||||
|
||||
ValidationResult result = new ValidationResult(name);
|
||||
ValidationResult result = new ValidationResult(new DbProperty(dbo, "name"));
|
||||
|
||||
if (pattern != null && !pattern.matcher(name).matches())
|
||||
{
|
||||
|
@ -19,15 +19,16 @@
|
||||
package org.alfresco.util.schemacomp.validator;
|
||||
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.alfresco.util.schemacomp.DiffContext;
|
||||
import org.alfresco.util.schemacomp.Differences;
|
||||
import org.alfresco.util.schemacomp.Results;
|
||||
import org.alfresco.util.schemacomp.ValidationResult;
|
||||
import org.alfresco.util.schemacomp.model.DbObject;
|
||||
import org.alfresco.util.schemacomp.model.Index;
|
||||
@ -36,8 +37,6 @@ import org.hibernate.dialect.Oracle10gDialect;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Tests for the NameValidator class.
|
||||
*
|
||||
@ -54,7 +53,7 @@ public class NameValidatorTest
|
||||
{
|
||||
validator = new NameValidator();
|
||||
validationResults = new ArrayList<ValidationResult>();
|
||||
ctx = new DiffContext(new Oracle10gDialect(), new Differences(), validationResults);
|
||||
ctx = new DiffContext(new Oracle10gDialect(), new Results(), validationResults);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -88,6 +87,6 @@ public class NameValidatorTest
|
||||
|
||||
private DbObject indexForName(String name)
|
||||
{
|
||||
return new Index(name, new ArrayList<String>());
|
||||
return new Index(null, name, new ArrayList<String>());
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,8 @@ import org.alfresco.util.schemacomp.DiffContext;
|
||||
import org.alfresco.util.schemacomp.model.DbObject;
|
||||
|
||||
/**
|
||||
* TODO: comment me!
|
||||
* A 'do nothing' validator
|
||||
*
|
||||
* @author Matt Ward
|
||||
*/
|
||||
public class NullValidator implements DbValidator
|
||||
|
Loading…
x
Reference in New Issue
Block a user