\r
import java.util.List;\r
\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
import org.simantics.db.Statement;\r
+import org.simantics.db.common.utils.NameUtils;\r
+import org.simantics.db.exception.ServiceException;\r
+import org.simantics.db.exception.ValidationException;\r
import org.simantics.utils.datastructures.Pair;\r
\r
public class GraphChanges {\r
\r
+ private Resource r1;\r
+ private Resource r2;\r
private List<Statement> deletions;\r
private List<Statement> additions;\r
private List<Pair<Statement,Statement>> modifications;\r
\r
- public GraphChanges(List<Statement> deletions, List<Statement> additions,\r
+ public GraphChanges(Resource r1, Resource r2, List<Statement> deletions, List<Statement> additions,\r
List<Pair<Statement, Statement>> modifications) {\r
super();\r
+ this.r1 = r1;\r
+ this.r2 = r2;\r
this.deletions = deletions;\r
this.additions = additions;\r
this.modifications = modifications;\r
}\r
\r
+ public Resource getResource1() {\r
+ return r1;\r
+ }\r
+ \r
+ public Resource getResource2() {\r
+ return r2;\r
+ }\r
+ \r
public List<Statement> getAdditions() {\r
return additions;\r
}\r
public List<Pair<Statement, Statement>> getModifications() {\r
return modifications;\r
}\r
+ \r
+ public String toString(ReadGraph graph) throws ValidationException, ServiceException {\r
+ StringBuilder sb = new StringBuilder();\r
+ sb.append("Del:\n");\r
+ for (Statement stm : deletions) {\r
+ sb.append(NameUtils.getSafeName(graph, stm.getSubject()) + " "+\r
+ NameUtils.getSafeName(graph, stm.getPredicate()) + " " +\r
+ NameUtils.getSafeName(graph, stm.getObject()) + " (" +\r
+ stm.getSubject() + " " +stm.getPredicate() + " " + stm.getObject() + ")\n");\r
+ }\r
+ sb.append("Add:\n");\r
+ for (Statement stm : additions) {\r
+ sb.append(NameUtils.getSafeName(graph, stm.getSubject()) + " "+\r
+ NameUtils.getSafeName(graph, stm.getPredicate()) + " " +\r
+ NameUtils.getSafeName(graph, stm.getObject()) + " (" +\r
+ stm.getSubject() + " " +stm.getPredicate() + " " + stm.getObject() + ")\n");\r
+ }\r
+ sb.append("Mod:\n");\r
+ for (Pair<Statement, Statement> mod :modifications) {\r
+ {\r
+ Statement stm = mod.first;\r
+ sb.append(NameUtils.getSafeName(graph, stm.getSubject()) + " "+\r
+ NameUtils.getSafeName(graph, stm.getPredicate()) + " " +\r
+ NameUtils.getSafeName(graph, stm.getObject()) + " (" +\r
+ stm.getSubject() + " " +stm.getPredicate() + " " + stm.getObject() + ")\n");\r
+ }\r
+ {\r
+ Statement stm = mod.second;\r
+ sb.append(NameUtils.getSafeName(graph, stm.getSubject()) + " "+\r
+ NameUtils.getSafeName(graph, stm.getPredicate()) + " " +\r
+ NameUtils.getSafeName(graph, stm.getObject()) + " (" +\r
+ stm.getSubject() + " " +stm.getPredicate() + " " + stm.getObject() + ")\n");\r
+ }\r
+ }\r
+ return sb.toString();\r
+ }\r
\r
}\r
import org.simantics.db.Resource;\r
import org.simantics.db.Statement;\r
import org.simantics.db.common.utils.NameUtils;\r
+import org.simantics.db.exception.DatabaseException;\r
import org.simantics.db.exception.DoesNotContainValueException;\r
-import org.simantics.db.exception.ManyObjectsForFunctionalRelationException;\r
import org.simantics.db.exception.ServiceException;\r
import org.simantics.db.exception.ValidationException;\r
import org.simantics.layer0.Layer0;\r
*/\r
public class GraphComparator {\r
\r
- \r
+ private Resource r1;\r
+ private Resource r2;\r
private List<Resource> traversed = new ArrayList<Resource>(); // list of relations that are traversed (and tested)\r
private List<Resource> tested = new ArrayList<Resource>(); // list of relations that are tested, but not traversed\r
private List<Resource> nonTraversed = new ArrayList<Resource>(); // list of relations that are not traversed\r
private BijectionMap<Resource, Resource> comparableResources = new BijectionMap<Resource, Resource>();\r
\r
\r
+ private ObjectComparator comparator;\r
+ \r
// runtime attributes\r
\r
private ReadGraph g;\r
private Layer0 b;\r
\r
- ArrayList<Resource> rs1 = new ArrayList<Resource>();\r
- ArrayList<Resource> rs2 = new ArrayList<Resource>();\r
+ public GraphComparator() {\r
+ comparator = new TypeComparator();\r
+ }\r
+ \r
+ public GraphComparator(ObjectComparator comparator) {\r
+ this.comparator = comparator;\r
+ }\r
+ \r
ArrayList<Statement> ss1 = new ArrayList<Statement>();\r
ArrayList<Statement> ss2 = new ArrayList<Statement>();\r
+ \r
Comparator<Statement> scomp = new PredicateComparator();\r
Comparator<Resource> rcomp = new ResourceComparator();\r
\r
tested.clear();\r
}\r
\r
- public void test(ReadGraph g, Resource r1, Resource r2) throws ServiceException, DoesNotContainValueException, ValidationException {\r
+ public void test(ReadGraph g, Resource r1, Resource r2) throws DatabaseException {\r
this.g = g;\r
this.b = Layer0.getInstance(g);\r
\r
+ this.r1 = r1;\r
+ this.r2 = r2;\r
changes1Set.clear();\r
changes2Set.clear();\r
modificationsSet.clear();\r
ss1 = filterNonTested(ss1);\r
ss2 = filterNonTested(ss2);\r
\r
- compareStatement(ss1, ss2, null, null);\r
+ compareStatements(ss1, ss2, null, null);\r
ss1.clear();\r
ss2.clear();\r
}\r
ss2.addAll(g.getStatements(r2, rel));\r
ss1 = filterAsserted(r1, ss1);\r
ss2 = filterAsserted(r2, ss2);\r
- compareStatement(ss1, ss2, stack1, stack2);\r
+ compareStatements(ss1, ss2, stack1, stack2);\r
ss1.clear();\r
ss2.clear();\r
}\r
}\r
\r
public GraphChanges getChanges() {\r
-// List<Statement> deletions = new ArrayList<Statement>();\r
-// List<Statement> additions = new ArrayList<Statement>();\r
-// deletions.addAll(changes1);\r
-// additions.addAll(changes2);\r
-// Collections.sort(deletions, new FullStatementComparator());\r
-// Collections.sort(additions, new FullStatementComparator());\r
-// return new GraphChanges(deletions, additions, modifications);\r
- return new GraphChanges(changes1,changes2,modifications);\r
+ return new GraphChanges(r1,r2,changes1,changes2,modifications);\r
}\r
\r
private List<Statement> filterAsserted(Resource r, Collection<Statement> in) throws ServiceException {\r
}\r
}\r
\r
- private void compareStatement(List<Statement> ss1, List<Statement> ss2, Stack<Resource> stack1, Stack<Resource> stack2) throws ServiceException, DoesNotContainValueException, ValidationException {\r
+ private void compareStatements(List<Statement> ss1, List<Statement> ss2, Stack<Resource> stack1, Stack<Resource> stack2) throws DatabaseException {\r
Collections.sort(ss1, scomp);\r
Collections.sort(ss2, scomp);\r
\r
int same2 = sameRel(ss2, i2);\r
int c = rcomp.compare(ss1.get(i1).getPredicate(),ss2.get(i2).getPredicate());\r
if (c == 0) {\r
- compareObject(ss1, i1, same1, ss2, i2, same2,stack1,stack2);\r
+ compareStatements(ss1, i1, same1, ss2, i2, same2,stack1,stack2);\r
i1+=same1;\r
i2+=same2;\r
} else if (c < 0) {\r
\r
}\r
\r
+ private int compareObject(Resource o1, Resource o2) throws DatabaseException {\r
+ if (comparableResources.contains(o1, o2))\r
+ return (-1);\r
+ return comparator.compare(g, o1, o2);\r
+ }\r
\r
- private void compareObject(List<Statement> ss1, int off1, int len1, List<Statement> ss2, int off2, int len2, Stack<Resource> stack1, Stack<Resource> stack2) throws ServiceException, DoesNotContainValueException, ValidationException {\r
+ private void compareStatements(List<Statement> ss1, int off1, int len1, List<Statement> ss2, int off2, int len2, Stack<Resource> stack1, Stack<Resource> stack2) throws DatabaseException {\r
boolean[] used1 = new boolean[len1];\r
for (int i = 0; i < used1.length; i++) {\r
used1[i] = false;\r
List<List<Integer>> differences = new ArrayList<List<Integer>>();\r
for (int i1 = off1; i1 < off1 + len1; i1++) {\r
Statement s1 = ss1.get(i1);\r
- //Map<Integer,Integer> differences = new HashMap<Integer, Integer>();\r
List<Integer> diff = new ArrayList<Integer>();\r
for (int i2 = off2; i2 < off2 + len2; i2++) {\r
Statement s2 = ss2.get(i2);\r
- if (!compareType(s1.getObject(), s2.getObject())) {\r
- diff.add(Integer.MAX_VALUE);\r
- continue;\r
- }\r
- if (comparableResources.contains(s1.getObject(), s2.getObject()))\r
- diff.add(-1);\r
- else\r
- diff.add(propsDiffCount(s1.getObject(), s2.getObject()));\r
+ diff.add(compareObject(s1.getObject(), s2.getObject()));\r
}\r
differences.add(diff);\r
}\r
}\r
}\r
\r
- private boolean compareType(Resource r1, Resource r2) throws ServiceException, ManyObjectsForFunctionalRelationException {\r
- rs1.addAll(g.getObjects(r1, b.InstanceOf));\r
- rs2.addAll(g.getObjects(r2, b.InstanceOf));\r
- if (rs1.size() != rs2.size()) {\r
- rs1.clear();\r
- rs2.clear();\r
- return false;\r
- }\r
- Collections.sort(rs1, rcomp);\r
- Collections.sort(rs2, rcomp);\r
- for (int i = 0; i < rs1.size(); i++) {\r
- int c = rcomp.compare(rs1.get(i), rs2.get(i));\r
- if (c != 0) {\r
- rs1.clear();\r
- rs2.clear();\r
- return false;\r
- }\r
- }\r
- \r
- rs1.clear();\r
- rs2.clear();\r
- \r
- return true;\r
- }\r
+ \r
\r
/**\r
* compares properties, assumes functional relations\r
if (b1) {\r
Object v1 = g.getValue(s1.getObject());\r
Object v2 = g.getValue(s2.getObject());\r
- boolean eq = false;\r
- if (v1 instanceof Object[] && v2 instanceof Object[])\r
- eq = Arrays.deepEquals((Object[])v1, (Object[])v2);\r
- else if (v1 instanceof int[] && v2 instanceof int[]) \r
- eq = Arrays.equals((int[])v1, (int[])v2);\r
- else if (v1 instanceof float[] && v2 instanceof float[]) \r
- eq = Arrays.equals((float[])v1, (float[])v2);\r
- else if (v1 instanceof double[] && v2 instanceof double[]) \r
- eq = Arrays.equals((double[])v1, (double[])v2);\r
- else if (v1 instanceof long[] && v2 instanceof long[]) \r
- eq = Arrays.equals((long[])v1, (long[])v2);\r
- else if (v1 instanceof byte[] && v2 instanceof byte[]) \r
- eq = Arrays.equals((byte[])v1, (byte[])v2);\r
- else if (v1 instanceof boolean[] && v2 instanceof boolean[]) \r
- eq = Arrays.equals((boolean[])v1, (boolean[])v2);\r
- else\r
- eq = v1.equals(v2);\r
+ boolean eq = compareValue(v1, v2);\r
if (!eq) {\r
- //changes1.add(s1);\r
- //changes2.add(s2);\r
addModification(s1, s2);\r
comparableStatements.map(s1, s2);\r
comparableResources.map(s1.getObject(),s2.getObject());\r
compareProps(s1.getObject(), s2.getObject());\r
}\r
} else {\r
- //changes1.add(s1);\r
- //changes2.add(s2);\r
addModification(s1, s2);\r
comparableStatements.map(s1, s2);\r
comparableResources.map(s1.getObject(),s2.getObject());\r
\r
}\r
\r
- private int propsDiffCount(Resource r1, Resource r2) throws ServiceException, DoesNotContainValueException, ValidationException {\r
- ArrayList<Statement> ss1 = new ArrayList<Statement>();\r
- ArrayList<Statement> ss2 = new ArrayList<Statement>();\r
- ss1.addAll(g.getStatements(r1, b.HasProperty));\r
- ss2.addAll(g.getStatements(r2, b.HasProperty));\r
- //System.out.println("Props count " + GraphUtils.getReadableName(g, r1) + " " + GraphUtils.getReadableName(g, r2));\r
- Collections.sort(ss1, scomp);\r
- Collections.sort(ss2, scomp);\r
- \r
- int count = 0;\r
- \r
- int i1 = 0; \r
- int i2 = 0;\r
- \r
- while (true) {\r
- if (i1 >= ss1.size()) {\r
- if (i2 >= ss2.size())\r
- break;\r
- else {\r
- while (i2 < ss2.size()) {\r
- count++;\r
- i2++;\r
- }\r
- break;\r
- }\r
- } else if (i2 >= ss2.size()) {\r
- while (i1 < ss1.size()) {\r
- count++;\r
- i1++;\r
- }\r
- break;\r
- }\r
- Statement s1 = ss1.get(i1);\r
- Statement s2 = ss2.get(i2);\r
- int c = scomp.compare(s1, s2);\r
- switch (c) {\r
- case 0:{\r
- boolean b1 = g.hasValue(s1.getObject());\r
- boolean b2 = g.hasValue(s2.getObject());\r
- if (b1 == b2) {\r
- if (b1) {\r
- Object v1 = g.getValue(s1.getObject());\r
- Object v2 = g.getValue(s2.getObject());\r
- boolean eq = false;\r
- if (v1 instanceof Object[] && v2 instanceof Object[])\r
- eq = Arrays.deepEquals((Object[])v1, (Object[])v2);\r
- else if (v1 instanceof int[] && v2 instanceof int[]) \r
- eq = Arrays.equals((int[])v1, (int[])v2);\r
- else if (v1 instanceof float[] && v2 instanceof float[]) \r
- eq = Arrays.equals((float[])v1, (float[])v2);\r
- else if (v1 instanceof double[] && v2 instanceof double[]) \r
- eq = Arrays.equals((double[])v1, (double[])v2);\r
- else if (v1 instanceof long[] && v2 instanceof long[]) \r
- eq = Arrays.equals((long[])v1, (long[])v2);\r
- else if (v1 instanceof byte[] && v2 instanceof byte[]) \r
- eq = Arrays.equals((byte[])v1, (byte[])v2);\r
- else if (v1 instanceof boolean[] && v2 instanceof boolean[]) \r
- eq = Arrays.equals((boolean[])v1, (boolean[])v2);\r
- else\r
- eq = v1.equals(v2);\r
- if (!eq) {\r
- count++;\r
- }\r
- //System.out.println("Prop count values " + v1 + " " + v2);\r
- } else {\r
- count += propsDiffCount(s1.getObject(), s2.getObject());\r
- }\r
- } else {\r
- //System.out.println("Props count structural vs literal");\r
- count++;\r
- }\r
- i1++;\r
- i2++;\r
- break;\r
- }\r
- case -1:{\r
- count++;\r
- i1++;\r
- break;\r
- }\r
- \r
- case 1:{\r
- count++;\r
- i2++;\r
- break;\r
- }\r
- }\r
-\r
- }\r
- \r
- ss1.clear();\r
- ss2.clear();\r
- return count;\r
+ \r
+ public static boolean compareValue(Object v1, Object v2) {\r
+ if (v1 instanceof Object[] && v2 instanceof Object[])\r
+ return Arrays.deepEquals((Object[])v1, (Object[])v2);\r
+ else if (v1 instanceof int[] && v2 instanceof int[]) \r
+ return Arrays.equals((int[])v1, (int[])v2);\r
+ else if (v1 instanceof float[] && v2 instanceof float[]) \r
+ return Arrays.equals((float[])v1, (float[])v2);\r
+ else if (v1 instanceof double[] && v2 instanceof double[]) \r
+ return Arrays.equals((double[])v1, (double[])v2);\r
+ else if (v1 instanceof long[] && v2 instanceof long[]) \r
+ return Arrays.equals((long[])v1, (long[])v2);\r
+ else if (v1 instanceof byte[] && v2 instanceof byte[]) \r
+ return Arrays.equals((byte[])v1, (byte[])v2);\r
+ else if (v1 instanceof boolean[] && v2 instanceof boolean[]) \r
+ return Arrays.equals((boolean[])v1, (boolean[])v2);\r
+ else\r
+ return v1.equals(v2);\r
}\r
\r
\r
\r
- public class PredicateComparator implements Comparator<Statement> {\r
+ public static class PredicateComparator implements Comparator<Statement> {\r
@Override\r
public int compare(Statement o1, Statement o2) {\r
if (o1.getPredicate().getResourceId() < o2.getPredicate().getResourceId())\r
}\r
}\r
\r
- public class FullStatementComparator implements Comparator<Statement> {\r
+ public static class FullStatementComparator implements Comparator<Statement> {\r
@Override\r
public int compare(Statement o1, Statement o2) {\r
if (o1.getSubject().getResourceId() < o2.getSubject().getResourceId())\r
\r
\r
\r
- public class ResourceComparator implements Comparator<Resource> {\r
+ public static class ResourceComparator implements Comparator<Resource> {\r
@Override\r
public int compare(Resource o1, Resource o2) {\r
if (o1.getResourceId() < o2.getResourceId())\r
return 0;\r
}\r
}\r
+ \r
+ \r
}\r
--- /dev/null
+package org.simantics.interop.test;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collections;\r
+import java.util.Comparator;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.Statement;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.exception.DoesNotContainValueException;\r
+import org.simantics.db.exception.ManyObjectsForFunctionalRelationException;\r
+import org.simantics.db.exception.ServiceException;\r
+import org.simantics.db.exception.ValidationException;\r
+import org.simantics.interop.test.GraphComparator.PredicateComparator;\r
+import org.simantics.interop.test.GraphComparator.ResourceComparator;\r
+import org.simantics.layer0.Layer0;\r
+\r
+/**\r
+ * Object comparator that uses type of objects to check if objects are comparable. \r
+ * \r
+ * Difference value is amount of properties that have different values.\r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public class TypeComparator implements ObjectComparator {\r
+\r
+ Comparator<Statement> scomp = new PredicateComparator();\r
+ Comparator<Resource> rcomp = new ResourceComparator();\r
+ \r
+ ArrayList<Resource> rs1 = new ArrayList<Resource>();\r
+ ArrayList<Resource> rs2 = new ArrayList<Resource>();\r
+ \r
+ @Override\r
+ public int compare(ReadGraph g, Resource o1, Resource o2) throws DatabaseException{\r
+ if (!compareType(g,o1, o2)) {\r
+ return (Integer.MAX_VALUE);\r
+ }\r
+ return propsDiffCount(g,o1, o2);\r
+ }\r
+ \r
+ protected boolean compareType(ReadGraph g,Resource r1, Resource r2) throws ServiceException, ManyObjectsForFunctionalRelationException {\r
+ Layer0 l0 = Layer0.getInstance(g);\r
+ rs1.addAll(g.getObjects(r1, l0.InstanceOf));\r
+ rs2.addAll(g.getObjects(r2, l0.InstanceOf));\r
+ if (rs1.size() != rs2.size()) {\r
+ rs1.clear();\r
+ rs2.clear();\r
+ return false;\r
+ }\r
+ Collections.sort(rs1, rcomp);\r
+ Collections.sort(rs2, rcomp);\r
+ for (int i = 0; i < rs1.size(); i++) {\r
+ int c = rcomp.compare(rs1.get(i), rs2.get(i));\r
+ if (c != 0) {\r
+ rs1.clear();\r
+ rs2.clear();\r
+ return false;\r
+ }\r
+ }\r
+ \r
+ rs1.clear();\r
+ rs2.clear();\r
+ \r
+ return true;\r
+ }\r
+ \r
+ protected int propsDiffCount(ReadGraph g, Resource r1, Resource r2) throws ServiceException, DoesNotContainValueException, ValidationException {\r
+ Layer0 l0 = Layer0.getInstance(g);\r
+ ArrayList<Statement> ss1 = new ArrayList<Statement>();\r
+ ArrayList<Statement> ss2 = new ArrayList<Statement>();\r
+ ss1.addAll(g.getStatements(r1, l0.HasProperty));\r
+ ss2.addAll(g.getStatements(r2, l0.HasProperty));\r
+ Collections.sort(ss1, scomp);\r
+ Collections.sort(ss2, scomp);\r
+ \r
+ int count = 0;\r
+ \r
+ int i1 = 0; \r
+ int i2 = 0;\r
+ \r
+ while (true) {\r
+ if (i1 >= ss1.size()) {\r
+ if (i2 >= ss2.size())\r
+ break;\r
+ else {\r
+ while (i2 < ss2.size()) {\r
+ count++;\r
+ i2++;\r
+ }\r
+ break;\r
+ }\r
+ } else if (i2 >= ss2.size()) {\r
+ while (i1 < ss1.size()) {\r
+ count++;\r
+ i1++;\r
+ }\r
+ break;\r
+ }\r
+ Statement s1 = ss1.get(i1);\r
+ Statement s2 = ss2.get(i2);\r
+ int c = scomp.compare(s1, s2);\r
+ switch (c) {\r
+ case 0:{\r
+ boolean b1 = g.hasValue(s1.getObject());\r
+ boolean b2 = g.hasValue(s2.getObject());\r
+ if (b1 == b2) {\r
+ if (b1) {\r
+ Object v1 = g.getValue(s1.getObject());\r
+ Object v2 = g.getValue(s2.getObject());\r
+ boolean eq = GraphComparator.compareValue(v1, v2);\r
+ \r
+ if (!eq) {\r
+ count++;\r
+ }\r
+ //System.out.println("Prop count values " + v1 + " " + v2);\r
+ } else {\r
+ count += propsDiffCount(g,s1.getObject(), s2.getObject());\r
+ }\r
+ } else {\r
+ //System.out.println("Props count structural vs literal");\r
+ count++;\r
+ }\r
+ i1++;\r
+ i2++;\r
+ break;\r
+ }\r
+ case -1:{\r
+ count++;\r
+ i1++;\r
+ break;\r
+ }\r
+ \r
+ case 1:{\r
+ count++;\r
+ i2++;\r
+ break;\r
+ }\r
+ }\r
+\r
+ }\r
+ \r
+ ss1.clear();\r
+ ss2.clear();\r
+ return count;\r
+ }\r
+\r
+}\r