/**
*
*/
package ecologylab.bigsemantics.metadata;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import ecologylab.bigsemantics.metametadata.MetaMetadata;
import ecologylab.bigsemantics.metametadata.MetaMetadataCollectionField;
import ecologylab.bigsemantics.metametadata.MetaMetadataCompositeField;
import ecologylab.bigsemantics.metametadata.MetaMetadataField;
import ecologylab.bigsemantics.metametadata.MetaMetadataNestedField;
import ecologylab.bigsemantics.metametadata.MetaMetadataScalarField;
import ecologylab.generic.Debug;
import ecologylab.generic.HashMapArrayList;
import ecologylab.generic.ReflectionTools;
/**
* MetadataComparator implements the java.util.Comparator for Metadata
*
* @author ajit
*
*/
public class MetadataComparator extends Debug implements Comparator<Metadata>
{
@Override
public int compare(Metadata m1, Metadata m2)
{
if (m1 == null || m2 == null)
return compareNull(m1, m2);
if (m1.getClass() != m2.getClass())
return -1;
MetaMetadata mmd1 = (MetaMetadata) m1.getMetaMetadata();
MetaMetadata mmd2 = (MetaMetadata) m2.getMetaMetadata();
// all values are looked up from hashmaps, so expected to be same
// change to name?
if (mmd1 != mmd2)
{
error("metametadata of the metadata objects is not same");
return -1;
}
return recursiveComparison(m1, m2, mmd1);
}
private int recursiveComparison(Metadata m1, Metadata m2, MetaMetadataNestedField mmd)
{
HashMapArrayList<String, MetaMetadataField> fieldSet = mmd.getChildrenMap();
if (fieldSet == null || fieldSet.isEmpty())
return -1;
MetaMetadataNestedField targetParent = mmd.isUsedToDefineInlineMmd() ? mmd.getTypeMmd() : mmd;
for (MetaMetadataField field : fieldSet)
{
if (!field.isAuthoredChildOf(targetParent))
{
// if 'field' is purely inherited, we ignore it to prevent infinite loops.
// infinite loops can happen when 'field' uses the same mmd type as where it is defined,
// e.g. google_patent.references are google_patent too.
// this behavior is not necessarily required to prevent infinite loops, but it works
// for our use cases now.
// -- yin qu, 2/21/2012
continue;
}
try
{
int suc = 0;
if (field instanceof MetaMetadataCompositeField)
{
MetaMetadataCompositeField mmcf = (MetaMetadataCompositeField) field;
suc = compareCompositeField(m1, m2, mmcf);
}
else if (field instanceof MetaMetadataCollectionField)
{
MetaMetadataCollectionField mmcf = (MetaMetadataCollectionField) field;
if (mmcf != null)
suc = compareCollectionField(m1, m2, mmcf);
}
else
{
// scalar
MetaMetadataScalarField mmsf = (MetaMetadataScalarField) field;
suc = compareScalarField(m1, m2, mmsf);
}
if (suc != 0)
{
error("in metadata " + mmd.getMetadataClassDescriptor());
return -1;
}
}
catch (Exception e)
{
error(String.format("EXCEPTION when comparing %s: %s", field, e.getMessage()));
e.printStackTrace();
}
}
return 0;
}
private int compareScalar(Object c1, Object c2)
{
if (c1 == null || c2 == null)
return compareNull(c1, c2);
if (c1.equals(c2))
return 0;
else
error("scalar not equal");
return -1;
}
private int compareScalarField(Metadata m1, Metadata m2, MetaMetadataScalarField mmsf)
{
Field javaField = mmsf.getMetadataFieldDescriptor().getField();
Object o1 = ReflectionTools.getFieldValue(m1, javaField);
Object o2 = ReflectionTools.getFieldValue(m2, javaField);
int suc = compareScalar(o1, o2);
if (suc != 0)
error("scalar field " + javaField + " not equal");
return suc;
}
private int compareCollectionField(Metadata m1, Metadata m2, MetaMetadataCollectionField mmcf)
{
Field javaField = mmcf.getMetadataFieldDescriptor().getField();
javaField.setAccessible(true);
Collection cf1 = (Collection) ReflectionTools.getFieldValue(m1, javaField);
Object fieldValue2 = ReflectionTools.getFieldValue(m2, javaField);
Collection cf2 = (Collection) fieldValue2;
if (cf1 == null || cf2 == null)
{
return compareNull(cf1, cf2);
}
if (cf1.size() != cf2.size())
{
error("collection field " + javaField + " not having same size in metadata");
return -1;
}
else
{
int suc = 0;
Iterator iter1 = cf1.iterator();
Iterator iter2 = cf2.iterator();
while (iter1.hasNext() && iter2.hasNext())
{
Object c1 = iter1.next();
Object c2 = iter2.next();
if (mmcf.isCollectionOfScalars())
{
if ((suc = compareScalar(c1, c2)) != 0)
break;
}
else
{
if ((suc = compare((Metadata)c1, (Metadata)c2)) != 0)
break;
}
}
if (suc != 0)
error("in collection field " + javaField);
return suc;
}
}
private int compareCompositeField(Metadata m1, Metadata m2, MetaMetadataCompositeField mmcf)
{
Field javaField = mmcf.getMetadataFieldDescriptor().getField();
Metadata mf1 = (Metadata) ReflectionTools.getFieldValue(m1, javaField);
Metadata mf2 = (Metadata) ReflectionTools.getFieldValue(m2, javaField);
if (mf1 == null || mf2 == null)
return compareNull(mf1, mf2);
int suc = recursiveComparison(mf1, mf2, mmcf);
if (suc != 0)
error("in composite field " + javaField);
return suc;
}
private int compareNull(Object o1, Object o2)
{
int suc = 0;
if ((o1 != null) && (o2 == null))
{
error("object1 is null");
suc = -1;
}
else if ((o1 == null) && (o2 != null))
{
error("object2 is null");
suc = 1;
}
else if ((o1 == null) && (o2 == null))
{
suc = 0;
}
return suc;
}
}