mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
ALF-10772: schema comparator
Compares two abstract database schemas. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@31312 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -18,8 +18,13 @@
|
||||
*/
|
||||
package org.alfresco.util.schemacomp.model;
|
||||
|
||||
import org.alfresco.util.schemacomp.Differences;
|
||||
import org.alfresco.util.schemacomp.SchemaUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* TODO: comment me!
|
||||
* Useful base class for many, if not all the {@link DbObject} implementations.
|
||||
*
|
||||
* @author Matt Ward
|
||||
*/
|
||||
public abstract class AbstractDbObject implements DbObject
|
||||
@@ -60,9 +65,18 @@ public abstract class AbstractDbObject implements DbObject
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getIdentifier()
|
||||
public boolean sameAs(DbObject other)
|
||||
{
|
||||
return getName();
|
||||
if (getName() != null && other != null && other.getName() != null)
|
||||
{
|
||||
return getName().equals(other.getName());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only other way we can know if they are the same is if they are
|
||||
// the exact same object reference.
|
||||
return this == other;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -88,4 +102,60 @@ public abstract class AbstractDbObject implements DbObject
|
||||
else if (!this.name.equals(other.name)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append(getClass().getSimpleName());
|
||||
sb.append("[name=");
|
||||
|
||||
if (getName() != null)
|
||||
{
|
||||
sb.append(getName());
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append("null");
|
||||
}
|
||||
|
||||
sb.append("]");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides an implementation of {@link DbObject#diff(DbObject, Differences)}. The template
|
||||
* method {@link #doDiff(DbObject, Differences)} 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
|
||||
* its diff correctly.
|
||||
*/
|
||||
@Override
|
||||
public void diff(DbObject right, Differences differences)
|
||||
{
|
||||
if (name != null && StringUtils.hasText(name))
|
||||
{
|
||||
differences.pushPath(name);
|
||||
}
|
||||
else
|
||||
{
|
||||
differences.pushPath("<" + getClass().getSimpleName() + ">");
|
||||
}
|
||||
SchemaUtils.compareSimple(name, right.getName(), differences);
|
||||
doDiff(right, differences);
|
||||
differences.popPath();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Override this method to provide subclass specific diffing logic.
|
||||
*
|
||||
* @param right
|
||||
* @param differences
|
||||
*/
|
||||
protected void doDiff(DbObject right, Differences differences)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@@ -18,8 +18,12 @@
|
||||
*/
|
||||
package org.alfresco.util.schemacomp.model;
|
||||
|
||||
import org.alfresco.util.schemacomp.Differences;
|
||||
import org.alfresco.util.schemacomp.SchemaUtils;
|
||||
|
||||
/**
|
||||
* TODO: comment me!
|
||||
* Represents a column in a database table.
|
||||
*
|
||||
* @author Matt Ward
|
||||
*/
|
||||
public class Column extends AbstractDbObject
|
||||
@@ -27,6 +31,21 @@ public class Column extends AbstractDbObject
|
||||
private String type;
|
||||
private boolean nullable;
|
||||
|
||||
|
||||
/**
|
||||
* Construct a Column.
|
||||
*
|
||||
* @param name
|
||||
* @param type
|
||||
* @param nullable
|
||||
*/
|
||||
public Column(String name, String type, boolean nullable)
|
||||
{
|
||||
super(name);
|
||||
this.type = type;
|
||||
this.nullable = nullable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the type
|
||||
*/
|
||||
@@ -84,4 +103,12 @@ public class Column extends AbstractDbObject
|
||||
else if (!this.type.equals(other.type)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doDiff(DbObject right, Differences differences)
|
||||
{
|
||||
Column rightColumn = (Column) right;
|
||||
SchemaUtils.compareSimple(type, rightColumn.type, differences);
|
||||
SchemaUtils.compareSimple(nullable, rightColumn.nullable, differences);
|
||||
}
|
||||
}
|
||||
|
@@ -18,12 +18,39 @@
|
||||
*/
|
||||
package org.alfresco.util.schemacomp.model;
|
||||
|
||||
import org.alfresco.util.schemacomp.Differences;
|
||||
|
||||
/**
|
||||
* All database objects to be modelled for schema comparisons must implement this interface.
|
||||
* All database objects to be modelled for schema comparisons must implement this interface, examples
|
||||
* of which include: schemas, tables, indexes, primary keys, foreign keys, sequences and columns.
|
||||
*
|
||||
* @author Matt Ward
|
||||
*/
|
||||
public interface DbObject
|
||||
{
|
||||
Object getIdentifier();
|
||||
/**
|
||||
* Are the two <code>DbObject</code>s logically the same? For example two Index objects may have
|
||||
* different names, but are the same index as they both index the same columns for the same table.
|
||||
*
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
boolean sameAs(DbObject other);
|
||||
|
||||
/**
|
||||
* All items can be asked for their name, but it may be null.
|
||||
*
|
||||
* @return Name if available, null otherwise.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* 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}
|
||||
* object passed in to this method.
|
||||
*
|
||||
* @param right The object to compare against.
|
||||
* @param differences A collector of differences.
|
||||
*/
|
||||
void diff(DbObject right, Differences differences);
|
||||
}
|
||||
|
@@ -18,9 +18,14 @@
|
||||
*/
|
||||
package org.alfresco.util.schemacomp.model;
|
||||
|
||||
import org.alfresco.util.schemacomp.Differences;
|
||||
import org.alfresco.util.schemacomp.SchemaUtils;
|
||||
|
||||
|
||||
/**
|
||||
* TODO: comment me!
|
||||
* Represents a foreign key on a database table (<code>localColumn</code>) that references
|
||||
* <code>targetTable.targetColumn</code>
|
||||
*
|
||||
* @author Matt Ward
|
||||
*/
|
||||
public class ForeignKey extends AbstractDbObject
|
||||
@@ -30,6 +35,22 @@ public class ForeignKey extends AbstractDbObject
|
||||
private String targetColumn;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param fkName
|
||||
* @param localColumn
|
||||
* @param targetTable
|
||||
* @param targetColumn
|
||||
*/
|
||||
public ForeignKey(String fkName, String localColumn, String targetTable, String targetColumn)
|
||||
{
|
||||
super(fkName);
|
||||
this.localColumn = localColumn;
|
||||
this.targetTable = targetTable;
|
||||
this.targetColumn = targetColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the localColumn
|
||||
*/
|
||||
@@ -37,6 +58,7 @@ public class ForeignKey extends AbstractDbObject
|
||||
{
|
||||
return this.localColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param localColumn the localColumn to set
|
||||
*/
|
||||
@@ -44,6 +66,7 @@ public class ForeignKey extends AbstractDbObject
|
||||
{
|
||||
this.localColumn = localColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the targetTable
|
||||
*/
|
||||
@@ -51,6 +74,7 @@ public class ForeignKey extends AbstractDbObject
|
||||
{
|
||||
return this.targetTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param targetTable the targetTable to set
|
||||
*/
|
||||
@@ -58,6 +82,7 @@ public class ForeignKey extends AbstractDbObject
|
||||
{
|
||||
this.targetTable = targetTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the targetColumn
|
||||
*/
|
||||
@@ -65,6 +90,7 @@ public class ForeignKey extends AbstractDbObject
|
||||
{
|
||||
return this.targetColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param targetColumn the targetColumn to set
|
||||
*/
|
||||
@@ -107,5 +133,15 @@ public class ForeignKey extends AbstractDbObject
|
||||
}
|
||||
else if (!this.targetTable.equals(other.targetTable)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void doDiff(DbObject right, Differences differences)
|
||||
{
|
||||
ForeignKey rightFK = (ForeignKey) right;
|
||||
SchemaUtils.compareSimple(localColumn, rightFK.localColumn, differences);
|
||||
SchemaUtils.compareSimple(targetTable, rightFK.targetTable, differences);
|
||||
SchemaUtils.compareSimple(targetColumn, rightFK.targetColumn, differences);
|
||||
}
|
||||
}
|
||||
|
@@ -20,8 +20,12 @@ package org.alfresco.util.schemacomp.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.util.schemacomp.Differences;
|
||||
import org.alfresco.util.schemacomp.SchemaUtils;
|
||||
|
||||
/**
|
||||
* TODO: comment me!
|
||||
* Represents an index on a table.
|
||||
*
|
||||
* @author Matt Ward
|
||||
*/
|
||||
public class Index extends AbstractDbObject
|
||||
@@ -29,6 +33,15 @@ public class Index extends AbstractDbObject
|
||||
private List<String> columnNames;
|
||||
|
||||
|
||||
/**
|
||||
* @param columnNames
|
||||
*/
|
||||
public Index(String name, List<String> columnNames)
|
||||
{
|
||||
super(name);
|
||||
this.columnNames = columnNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the columnNames
|
||||
*/
|
||||
@@ -45,18 +58,6 @@ public class Index extends AbstractDbObject
|
||||
this.columnNames = columnNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: column names should be fully qualified, OR an Index should have a table name field
|
||||
* and the identifier should include it.
|
||||
*
|
||||
* @return the Index identifier
|
||||
*/
|
||||
@Override
|
||||
public Object getIdentifier()
|
||||
{
|
||||
return getColumnNames();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
@@ -80,4 +81,34 @@ public class Index extends AbstractDbObject
|
||||
else if (!this.columnNames.equals(other.columnNames)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sameAs(DbObject o)
|
||||
{
|
||||
if (o != null && o instanceof Index)
|
||||
{
|
||||
Index other = (Index) o;
|
||||
|
||||
if (getName() != null)
|
||||
{
|
||||
if (getName().equals(other.getName()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return columnNames.equals(other.getColumnNames());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doDiff(DbObject right, Differences differences)
|
||||
{
|
||||
Index rightIndex = (Index) right;
|
||||
SchemaUtils.compareSimpleCollections(columnNames, rightIndex.columnNames, differences);
|
||||
}
|
||||
}
|
||||
|
@@ -20,8 +20,12 @@ package org.alfresco.util.schemacomp.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.util.schemacomp.Differences;
|
||||
import org.alfresco.util.schemacomp.SchemaUtils;
|
||||
|
||||
/**
|
||||
* TODO: comment me!
|
||||
* Primary key on a table.
|
||||
*
|
||||
* @author Matt Ward
|
||||
*/
|
||||
public class PrimaryKey extends AbstractDbObject
|
||||
@@ -68,4 +72,11 @@ public class PrimaryKey extends AbstractDbObject
|
||||
else if (!this.columnNames.equals(other.columnNames)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doDiff(DbObject right, Differences differences)
|
||||
{
|
||||
PrimaryKey rightPK = (PrimaryKey) right;
|
||||
SchemaUtils.compareSimpleCollections(columnNames, rightPK.columnNames, differences);
|
||||
}
|
||||
}
|
||||
|
@@ -18,50 +18,50 @@
|
||||
*/
|
||||
package org.alfresco.util.schemacomp.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.util.schemacomp.Differences;
|
||||
import org.alfresco.util.schemacomp.SchemaUtils;
|
||||
|
||||
/**
|
||||
* Instances of this class will represent a database schema.
|
||||
* Instances of this class represent a database schema.
|
||||
*
|
||||
* @author Matt Ward
|
||||
*/
|
||||
public class
|
||||
Schema extends AbstractDbObject implements Iterable<DbObject>
|
||||
public class Schema extends AbstractDbObject implements Iterable<DbObject>
|
||||
{
|
||||
private final Map<Object, DbObject> objects = new LinkedHashMap<Object, DbObject>();
|
||||
private final List<DbObject> objects = new ArrayList<DbObject>();
|
||||
|
||||
/**
|
||||
* @param key
|
||||
* @return
|
||||
* Construct a schema with the given name.
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
public DbObject get(Object key)
|
||||
public Schema(String name)
|
||||
{
|
||||
return this.objects.get(key);
|
||||
super(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param table
|
||||
*/
|
||||
public void put(DbObject dbObject)
|
||||
public void add(DbObject dbObject)
|
||||
{
|
||||
objects.put(dbObject.getIdentifier(), dbObject);
|
||||
objects.add(dbObject);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Iterator<DbObject> iterator()
|
||||
{
|
||||
return objects.values().iterator();
|
||||
return objects.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param identifier
|
||||
* @return
|
||||
*/
|
||||
public boolean contains(Object identifier)
|
||||
public boolean contains(DbObject object)
|
||||
{
|
||||
return objects.containsKey(identifier);
|
||||
return objects.contains(object);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -87,4 +87,12 @@ Schema extends AbstractDbObject implements Iterable<DbObject>
|
||||
else if (!this.objects.equals(other.objects)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void doDiff(DbObject right, Differences differences)
|
||||
{
|
||||
Schema rightSchema = (Schema) right;
|
||||
SchemaUtils.compareCollections(objects, rightSchema.objects, differences);
|
||||
}
|
||||
}
|
||||
|
@@ -18,10 +18,13 @@
|
||||
*/
|
||||
package org.alfresco.util.schemacomp.model;
|
||||
|
||||
|
||||
/**
|
||||
* TODO: comment me!
|
||||
* Represents a database sequence.
|
||||
*
|
||||
* @author Matt Ward
|
||||
*/
|
||||
public class Sequence extends AbstractDbObject
|
||||
{
|
||||
// No subclass specific data/behaviour at present.
|
||||
}
|
||||
|
@@ -22,8 +22,11 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.util.schemacomp.Differences;
|
||||
import org.alfresco.util.schemacomp.SchemaUtils;
|
||||
|
||||
/**
|
||||
* Instances of this class will represent a database table.
|
||||
* Instances of this class represent a database table.
|
||||
*
|
||||
* @author Matt Ward
|
||||
*/
|
||||
@@ -31,23 +34,26 @@ public class Table extends AbstractDbObject
|
||||
{
|
||||
private List<Column> columns = new ArrayList<Column>();
|
||||
private PrimaryKey primaryKey;
|
||||
private ForeignKey foreignKey;
|
||||
private List<ForeignKey> foreignKeys = new ArrayList<ForeignKey>();
|
||||
private List<Index> indexes = new ArrayList<Index>();
|
||||
|
||||
|
||||
public Table(String name, Collection<Column> columns, PrimaryKey primaryKey,
|
||||
ForeignKey foreignKey, Collection<Index> indexes)
|
||||
Collection<ForeignKey> foreignKeys, Collection<Index> indexes)
|
||||
{
|
||||
super(name);
|
||||
if (columns != null)
|
||||
{
|
||||
columns.addAll(columns);
|
||||
this.columns.addAll(columns);
|
||||
}
|
||||
this.primaryKey = primaryKey;
|
||||
this.foreignKey = foreignKey;
|
||||
if (foreignKeys != null)
|
||||
{
|
||||
this.foreignKeys.addAll(foreignKeys);
|
||||
}
|
||||
if (indexes != null)
|
||||
{
|
||||
indexes.addAll(indexes);
|
||||
this.indexes.addAll(indexes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,20 +95,20 @@ public class Table extends AbstractDbObject
|
||||
|
||||
|
||||
/**
|
||||
* @return the foreignKey
|
||||
* @return the foreignKeys
|
||||
*/
|
||||
public ForeignKey getForeignKey()
|
||||
public List<ForeignKey> getForeignKeys()
|
||||
{
|
||||
return this.foreignKey;
|
||||
return this.foreignKeys;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param foreignKey the foreignKey to set
|
||||
* @param foreignKeys the foreignKeys to set
|
||||
*/
|
||||
public void setForeignKey(ForeignKey foreignKey)
|
||||
public void setForeignKeys(List<ForeignKey> foreignKeys)
|
||||
{
|
||||
this.foreignKey = foreignKey;
|
||||
this.foreignKeys = foreignKeys;
|
||||
}
|
||||
|
||||
|
||||
@@ -130,7 +136,7 @@ public class Table extends AbstractDbObject
|
||||
final int prime = 31;
|
||||
int result = super.hashCode();
|
||||
result = prime * result + ((this.columns == null) ? 0 : this.columns.hashCode());
|
||||
result = prime * result + ((this.foreignKey == null) ? 0 : this.foreignKey.hashCode());
|
||||
result = prime * result + ((this.foreignKeys == null) ? 0 : this.foreignKeys.hashCode());
|
||||
result = prime * result + ((this.indexes == null) ? 0 : this.indexes.hashCode());
|
||||
result = prime * result + ((this.primaryKey == null) ? 0 : this.primaryKey.hashCode());
|
||||
return result;
|
||||
@@ -149,21 +155,34 @@ public class Table extends AbstractDbObject
|
||||
if (other.columns != null) return false;
|
||||
}
|
||||
else if (!this.columns.equals(other.columns)) return false;
|
||||
if (this.foreignKey == null)
|
||||
if (this.foreignKeys == null)
|
||||
{
|
||||
if (other.foreignKey != null) return false;
|
||||
if (other.foreignKeys != null) return false;
|
||||
}
|
||||
else if (!this.foreignKey.equals(other.foreignKey)) return false;
|
||||
else if (!this.foreignKeys.equals(other.foreignKeys)) return false;
|
||||
if (this.indexes == null)
|
||||
{
|
||||
if (other.indexes != null) return false;
|
||||
}
|
||||
else if (!this.indexes.equals(other.indexes)) return false;
|
||||
if (this.primaryKey == null)
|
||||
{
|
||||
if (other.primaryKey != null) return false;
|
||||
}
|
||||
else if (!this.primaryKey.equals(other.primaryKey)) return false;
|
||||
// TODO: this is difficult, equals probably should include this, but diffs shouldn't -
|
||||
// decide what to do about this.
|
||||
// if (this.primaryKey == null)
|
||||
// {
|
||||
// if (other.primaryKey != null) return false;
|
||||
// }
|
||||
// else if (!this.primaryKey.equals(other.primaryKey)) return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void doDiff(DbObject other, Differences differences)
|
||||
{
|
||||
Table rightTable = (Table) other;
|
||||
SchemaUtils.compareCollections(columns, rightTable.columns, differences);
|
||||
primaryKey.diff(rightTable.primaryKey, differences);
|
||||
SchemaUtils.compareCollections(foreignKeys, rightTable.foreignKeys, differences);
|
||||
SchemaUtils.compareCollections(indexes, rightTable.indexes, differences);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user