]> gerrit.simantics Code Review - simantics/interop.git/commitdiff
Subgraph difference tester
authorluukkainen <luukkainen@ac1ea38d-2e2b-0410-8846-a27921b304fc>
Fri, 21 May 2010 13:11:43 +0000 (13:11 +0000)
committerMarko Luukkainen <marko.luukkainen@vtt.fi>
Thu, 2 Feb 2017 09:22:10 +0000 (11:22 +0200)
git-svn-id: https://www.simantics.org/svn/simantics/interoperability/trunk@15820 ac1ea38d-2e2b-0410-8846-a27921b304fc

org.simantics.interop/plugin.xml
org.simantics.interop/src/org/simantics/interop/test/GraphComparator.java [new file with mode: 0644]
org.simantics.interop/src/org/simantics/interop/test/GraphComparatorViewer.java [new file with mode: 0644]

index a745fafac100067c169b7799c564989856e41342..250fcbc19307d4e1d650f6faf007f1173cd41cfb 100644 (file)
          </implementation>\r
       </binding>\r
    </extension>\r
+   <extension\r
+         point="org.eclipse.ui.views">\r
+      <view\r
+            category="org.simantics.debug.ui"\r
+            class="org.simantics.interop.test.GraphComparatorViewer"\r
+            id="org.simantics.interop.comparator"\r
+            name="Comparator"\r
+            restorable="true">\r
+      </view>\r
+   </extension>\r
 \r
 </plugin>\r
diff --git a/org.simantics.interop/src/org/simantics/interop/test/GraphComparator.java b/org.simantics.interop/src/org/simantics/interop/test/GraphComparator.java
new file mode 100644 (file)
index 0000000..10f1265
--- /dev/null
@@ -0,0 +1,531 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     Foster Wheeler Energia Oy - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.interop.test;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Arrays;\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+import java.util.Comparator;\r
+import java.util.List;\r
+import java.util.Stack;\r
+\r
+import org.simantics.db.Builtins;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.Statement;\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.utils.direct.GraphUtils;\r
+import org.simantics.utils.datastructures.BijectionMap;\r
+import org.simantics.utils.datastructures.MapList;\r
+\r
+/**\r
+ * Compares two subgraphs and reports differences.\r
+ * \r
+ * Assumes that subgraphs (defined using traverse relations) are not cyclic.\r
+ * \r
+ * Assumes that properties can be used to identify objects, if relation type is not enough.\r
+ * \r
+ * \r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public class GraphComparator {\r
+\r
+       \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
+       \r
+       \r
+       private List<Statement> changes1 = new ArrayList<Statement>();\r
+       private List<Statement> changes2 = new ArrayList<Statement>();\r
+       private BijectionMap<Statement, Statement> comparable = new BijectionMap<Statement, Statement>();\r
+       \r
+       \r
+       // runtime attributes\r
+       \r
+       private ReadGraph g;\r
+       private Builtins b;\r
+       \r
+       ArrayList<Resource> rs1 = new ArrayList<Resource>();\r
+       ArrayList<Resource> rs2 = new ArrayList<Resource>();\r
+       ArrayList<Statement> ss1 = new ArrayList<Statement>();\r
+       ArrayList<Statement> ss2 = new ArrayList<Statement>();\r
+       Comparator<Statement> scomp = new StatementComparator();\r
+       Comparator<Resource> rcomp = new ResourceComparator();\r
+\r
+       \r
+       public void addTraversed(Resource rel) {\r
+               traversed.add(rel);\r
+       }\r
+       \r
+       public void addTraversed(Collection<Resource> rels) {\r
+               traversed.addAll(rels);\r
+       }\r
+       \r
+       public void addTested(Resource rel) {\r
+               tested.add(rel);\r
+       }\r
+       \r
+       public void addTested(Collection<Resource> rels) {\r
+               tested.addAll(rels);\r
+       }\r
+       \r
+       public void clearRels() {\r
+               traversed.clear();\r
+               tested.clear();\r
+       }\r
+       \r
+       public void test(ReadGraph g, Resource r1, Resource r2) throws ServiceException, DoesNotContainValueException, ValidationException {\r
+               this.g = g;\r
+               this.b = g.getBuiltins();\r
+               \r
+               changes1.clear();\r
+               changes2.clear();\r
+               \r
+               Stack<Resource> stack1 = new Stack<Resource>();\r
+               Stack<Resource> stack2 = new Stack<Resource>();\r
+               stack1.push(r1);\r
+               stack2.push(r2);\r
+               \r
+               ArrayList<Statement> ss1 = new ArrayList<Statement>();\r
+               ArrayList<Statement> ss2 = new ArrayList<Statement>();\r
+               \r
+               while (!stack1.isEmpty()) {\r
+                       r1 = stack1.pop();\r
+                       r2 = stack2.pop();\r
+                       \r
+                       System.out.println("test " + GraphUtils.getReadableName(g, r1) + " " + GraphUtils.getReadableName(g, r2));\r
+                       compareProps(r1, r2);\r
+                       \r
+                       for (Resource rel : tested) {\r
+                               filterTraversed(g.getStatements(r1, rel), ss1);\r
+                               filterTraversed(g.getStatements(r2, rel), ss2);\r
+                               \r
+                               compareStatement(ss1, ss2, null, null);\r
+                               ss1.clear();\r
+                               ss2.clear();\r
+                       }\r
+                       \r
+                       for (Resource rel : traversed) {\r
+                               ss1.addAll(g.getStatements(r1, rel));\r
+                               ss2.addAll(g.getStatements(r2, rel));\r
+                               compareStatement(ss1, ss2, stack1, stack2);\r
+                               ss1.clear();\r
+                               ss2.clear();\r
+                       }\r
+               }\r
+       }\r
+       \r
+       public Collection<Statement> getChanges1() {\r
+               return changes1;\r
+       }\r
+       \r
+       public Collection<Statement> getChanges2() {\r
+               return changes2;\r
+       }\r
+       \r
+       public BijectionMap<Statement, Statement> getComparable() {\r
+               return comparable;\r
+       }\r
+       \r
+       private void filterTraversed(Collection<Statement> in, Collection<Statement> out) throws ServiceException {\r
+               for (Statement s : in) {\r
+                       boolean usable = true;\r
+                       for (Resource r : traversed) {\r
+                               if (g.isSubrelationOf(s.getPredicate(),r)) {\r
+                                       usable = false;\r
+                                       break;\r
+                               }\r
+                       }\r
+                       if (usable) {\r
+                               out.add(s);\r
+                       }\r
+                       \r
+               }\r
+       }\r
+       \r
+       private void compareStatement(List<Statement> ss1, List<Statement> ss2, Stack<Resource> stack1, Stack<Resource> stack2) throws ServiceException, DoesNotContainValueException, ValidationException {\r
+               Collections.sort(ss1, scomp);\r
+               Collections.sort(ss2, scomp);\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
+                                               changes2.add(ss2.get(i2));\r
+                                               i2++;\r
+                                       }\r
+                                       break;\r
+                               }\r
+                       } else if (i2 >= ss2.size()) {\r
+                               while (i1 < ss1.size()) {\r
+                                       changes1.add(ss1.get(i1));\r
+                                       i1++;\r
+                               }\r
+                               break;\r
+                       }\r
+                       int same1 = sameRel(ss1, i1);\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
+                               i1+=same1;\r
+                               i2+=same2;\r
+                       } else if (c < 0) {\r
+                               for (int i = 0; i < same1; i++) {\r
+                                       changes1.add(ss1.get(i+i1));\r
+                               }\r
+                               i1 += same1;\r
+                               } else {\r
+                                       for (int i = 0; i < same2; i++) {\r
+                                       changes2.add(ss2.get(i+i2));\r
+                               }\r
+                               i2 += same2;\r
+                       }\r
+                       \r
+               }\r
+       }\r
+       \r
+       private int sameRel(List<Statement> statements, int off) {\r
+               if (statements.size() <= off)\r
+                       return 0;\r
+               int same = 1;\r
+               long id = statements.get(off).getPredicate().getResourceId();\r
+               for (int i = off+1; i <statements.size(); i++) {\r
+                       if (statements.get(i).getPredicate().getResourceId() == id)\r
+                               same++;\r
+                       else \r
+                               break;\r
+               }\r
+               return same;\r
+               \r
+       }\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
+               boolean[] used1 = new boolean[len1];\r
+               for (int i = 0; i < used1.length; i++) {\r
+                       used1[i] = false;\r
+               }\r
+               \r
+               boolean[] used2 = new boolean[len2];\r
+               for (int i = 0; i < used2.length; i++) {\r
+                       used2[i] = false;\r
+               }\r
+               \r
+               // left, right, difference\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
+                               diff.add(propsDiffCount(s1.getObject(), s2.getObject()));\r
+                       }\r
+                       differences.add(diff);\r
+               }\r
+               // difference, left\r
+               MapList<Integer, Integer> priorities = new MapList<Integer, Integer>();\r
+               for (int i = 0; i < differences.size(); i++) {\r
+                       List<Integer> list = differences.get(i);\r
+                       for (int j = 0; j < list.size(); j++) {\r
+                               priorities.add(list.get(j), i);\r
+                       }\r
+               }\r
+               \r
+               Integer[] pris = priorities.getKeys(new Integer[]{});\r
+               Arrays.sort(pris);\r
+               \r
+               for (Integer pri : pris) {\r
+                       if (pri == Integer.MAX_VALUE)\r
+                               continue;\r
+                       List<Integer> i1s = priorities.getValues(pri);\r
+                       for (Integer i1 : i1s) {\r
+                               if (used1[i1])\r
+                                       continue;\r
+                               List<Integer> i2diff = differences.get(i1);\r
+                               for (int i2 = 0; i2 < i2diff.size(); i2++) {\r
+                                       if (i2diff.get(i2) == pri) {\r
+                                               if (used2[i2])\r
+                                                       break;\r
+                                               used1[i1] = true;\r
+                                               used2[i2] = true;\r
+                                               if (stack1 != null) {\r
+                                                       stack1.add(ss1.get(i1+off1).getObject());\r
+                                                       stack2.add(ss2.get(i2+off2).getObject());\r
+                                               } else {\r
+                                                       // TODO : how should we report non traversed differences\r
+                                                       // using compareProps assumes that referenced objects are the same (references are not different)\r
+                                                       // using propsDiffCount assumes that objects are different, and cannot report changes in referred object.\r
+                                                       \r
+                                                       //compareProps(ss1.get(i1+off1).getObject(), ss2.get(i2+off2).getObject());\r
+                                                       int diff = propsDiffCount(ss1.get(i1+off1).getObject(), ss2.get(i2+off2).getObject());\r
+                                                       if (diff != 0) {\r
+                                                               changes1.add(ss1.get(i1+off1));\r
+                                                               changes2.add(ss2.get(i2+off2));\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+               for (int i1 = off1; i1 < off1 + len1; i1++) {\r
+                       if (!used1[i1-off1])\r
+                               changes1.add(ss1.get(i1));\r
+               }\r
+               for (int i2 = off2; i2 < off2 + len2; i2++) {\r
+                       if (!used2[i2-off2])\r
+                               changes2.add(ss2.get(i2));\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
+        * compares properties, assumes functional relations\r
+        * @param r1\r
+        * @param r2\r
+        * @throws ManyObjectsForFunctionalRelationException\r
+        * @throws ServiceException\r
+        * @throws DoesNotContainValueException\r
+        */\r
+       private void compareProps(Resource r1, Resource r2) throws ManyObjectsForFunctionalRelationException, ServiceException, DoesNotContainValueException {\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
+               Collections.sort(ss1, scomp);\r
+               Collections.sort(ss2, scomp);\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
+                                               changes2.add(ss2.get(i2));\r
+                                               i2++;\r
+                                       }\r
+                                       break;\r
+                               }\r
+                       } else if (i2 >= ss2.size()) {\r
+                               while (i1 < ss1.size()) {\r
+                                       changes1.add(ss1.get(i1));\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\r
+                                                       eq = v1.equals(v2);\r
+                                               if (!eq) {\r
+                                                       changes1.add(s1);\r
+                                                       changes2.add(s2);\r
+                                                       comparable.map(s1, s2);\r
+                                               }\r
+                                       } else {\r
+                                               compareProps(s1.getObject(), s2.getObject());\r
+                                       }\r
+                               } else {\r
+                                       changes1.add(s1);\r
+                                       changes2.add(s2);\r
+                                       comparable.map(s1, s2);\r
+                               }\r
+                               i1++;\r
+                               i2++;\r
+                               break;\r
+                       }\r
+                       case -1:{\r
+                               changes1.add(s1);\r
+                               i1++;\r
+                               break;\r
+                       }\r
+                               \r
+                       case 1:{\r
+                               changes2.add(s2);\r
+                               i2++;\r
+                               break;\r
+                       }\r
+                       }\r
+                       \r
+                       \r
+               }\r
+               \r
+               ss1.clear();\r
+               ss2.clear();\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\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
+               \r
+               ss1.clear();\r
+               ss2.clear();\r
+               return count;\r
+       }\r
+\r
+       \r
+       \r
+       public class StatementComparator implements Comparator<Statement> {\r
+               @Override\r
+               public int compare(Statement o1, Statement o2) {\r
+                       if (o1.getPredicate().getResourceId() < o2.getPredicate().getResourceId())\r
+                               return -1;\r
+                       if (o1.getPredicate().getResourceId() > o2.getPredicate().getResourceId())\r
+                               return 1;\r
+                       return 0;\r
+               }\r
+       }\r
+       \r
+\r
+       \r
+       public class ResourceComparator implements Comparator<Resource> {\r
+               @Override\r
+               public int compare(Resource o1, Resource o2) {\r
+                       if (o1.getResourceId() < o2.getResourceId())\r
+                               return -1;\r
+                       if (o2.getResourceId() > o2.getResourceId())\r
+                               return 1;\r
+                       return 0;\r
+               }\r
+       }\r
+}\r
diff --git a/org.simantics.interop/src/org/simantics/interop/test/GraphComparatorViewer.java b/org.simantics.interop/src/org/simantics/interop/test/GraphComparatorViewer.java
new file mode 100644 (file)
index 0000000..0f8dce0
--- /dev/null
@@ -0,0 +1,275 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     Foster Wheeler Energia Oy - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.interop.test;\r
+\r
+import java.io.IOException;\r
+import java.util.HashMap;\r
+import java.util.Map;\r
+\r
+import org.eclipse.jface.layout.GridDataFactory;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.dnd.DND;\r
+import org.eclipse.swt.dnd.DropTarget;\r
+import org.eclipse.swt.dnd.DropTargetAdapter;\r
+import org.eclipse.swt.dnd.DropTargetEvent;\r
+import org.eclipse.swt.dnd.TextTransfer;\r
+import org.eclipse.swt.dnd.Transfer;\r
+import org.eclipse.swt.events.SelectionAdapter;\r
+import org.eclipse.swt.events.SelectionEvent;\r
+import org.eclipse.swt.layout.GridData;\r
+import org.eclipse.swt.layout.GridLayout;\r
+import org.eclipse.swt.widgets.Button;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Display;\r
+import org.eclipse.swt.widgets.Label;\r
+import org.eclipse.swt.widgets.Text;\r
+import org.eclipse.ui.part.ViewPart;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.Session;\r
+import org.simantics.db.Statement;\r
+import org.simantics.db.common.ResourceArray;\r
+import org.simantics.db.common.request.ReadRequest;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.exception.InvalidResourceReferenceException;\r
+import org.simantics.db.exception.ServiceException;\r
+import org.simantics.db.exception.ValidationException;\r
+import org.simantics.db.request.Read;\r
+import org.simantics.db.service.SerialisationSupport;\r
+import org.simantics.layer0.utils.direct.GraphUtils;\r
+import org.simantics.ui.SimanticsUI;\r
+import org.simantics.ui.dnd.LocalObjectTransfer;\r
+import org.simantics.ui.dnd.ResourceReferenceTransfer;\r
+import org.simantics.ui.dnd.ResourceTransferUtils;\r
+import org.simantics.ui.utils.ResourceAdaptionUtils;\r
+import org.simantics.utils.datastructures.BijectionMap;\r
+\r
+/**\r
+ * Simple multi line text viewer for seeing differences in two subgraphs. \r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public class GraphComparatorViewer extends ViewPart{\r
+       \r
+       private Session session;\r
+\r
+       private Composite composite;\r
+       \r
+       private Label resourceText1;\r
+       private Label resourceText2;\r
+       \r
+       private Text text1;\r
+       private Text text2;\r
+       \r
+       private GraphComparator comparator = new GraphComparator();\r
+       \r
+       @Override\r
+       public void createPartControl(Composite parent) {\r
+               composite = new Composite(parent, SWT.NONE);\r
+               composite.setLayout(new GridLayout(2, false));\r
+               \r
+               session = SimanticsUI.getSession();\r
+               \r
+               Composite topComposite = new Composite(composite, SWT.BORDER);\r
+               topComposite.setLayout(new GridLayout(3, false));\r
+               text1 = new Text(composite, SWT.MULTI|SWT.V_SCROLL);\r
+               text2 = new Text(composite, SWT.MULTI|SWT.V_SCROLL);\r
+               \r
+               GridDataFactory.fillDefaults().align(SWT.FILL, SWT.TOP).grab(true, false).span(2, 1).applyTo(topComposite);\r
+               GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(text1);\r
+               GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(text2);\r
+               \r
+               resourceText1 = createDropLabel(topComposite);\r
+               resourceText2 = createDropLabel(topComposite);\r
+               \r
+               Button button = new Button(topComposite, SWT.PUSH);\r
+               button.setText("Compare");\r
+               button.addSelectionListener(new SelectionAdapter() {\r
+                       @Override\r
+                       public void widgetSelected(SelectionEvent e) {\r
+                               compare();\r
+                       }\r
+               });\r
+               \r
+       }\r
+       \r
+       \r
+       \r
+       private void compare() {\r
+               text1.setText("");\r
+               text2.setText("");\r
+               final Resource r1 = (Resource)resourceText1.getData();\r
+               final Resource r2 = (Resource)resourceText2.getData();\r
+               if (r1 == null || r2 == null) {\r
+                       if (r1 == null)\r
+                               text1.setText("Missing input!");\r
+                       if (r2 == null)\r
+                               text2.setText("Missing input!");\r
+                       return; \r
+               }\r
+               \r
+               session.asyncRequest(new ReadRequest() {\r
+                       \r
+                       @Override\r
+                       public void run(final ReadGraph graph) throws DatabaseException {\r
+                               comparator.clearRels();\r
+                               comparator.addTraversed(graph.getBuiltins().ConsistsOf);\r
+//                             comparator.addTested(graph.getBuiltins().IsWeaklyRelatedTo);\r
+                               comparator.test(graph, r1, r2);\r
+                               BijectionMap<Statement, Statement> map = comparator.getComparable();\r
+                               Map<Statement, Integer> indices = new HashMap<Statement, Integer>();\r
+                               final StringBuilder sb1 = new StringBuilder();\r
+                               int index = 0;\r
+                               for (Statement s : comparator.getChanges1()) {\r
+                                       String sub;\r
+                                       try {\r
+                                               \r
+                                               sub = GraphUtils.getReadableName(graph, s.getSubject());\r
+                                               String pre = GraphUtils.getReadableName(graph, s.getPredicate());\r
+                                               String obj = GraphUtils.getReadableName(graph, s.getObject());\r
+                                               if (map.containsLeft(s)) {\r
+                                                       index++;\r
+                                                       indices.put(s, index);\r
+                                                       sb1.append("["+index + "] ");\r
+                                               }\r
+                                               sb1.append(sub + " - " + pre + " - " + obj + "\n");\r
+                                       } catch (ValidationException e) {\r
+                                               e.printStackTrace();\r
+                                       } catch (ServiceException e) {\r
+                                               e.printStackTrace();\r
+                                       }\r
+                                       \r
+                               }\r
+                               final StringBuilder sb2 = new StringBuilder();\r
+                               for (Statement s : comparator.getChanges2()) {\r
+                                       String sub;\r
+                                       try {\r
+                                               sub = GraphUtils.getReadableName(graph, s.getSubject());\r
+                                               String pre = GraphUtils.getReadableName(graph, s.getPredicate());\r
+                                               String obj = GraphUtils.getReadableName(graph, s.getObject());\r
+                                               if (map.containsRight(s)) {\r
+                                                       index = indices.get(map.getLeft(s));\r
+                                                       sb2.append("["+index + "] ");\r
+                                               }\r
+                                               sb2.append(sub + " - " + pre + " - " + obj + "\n");\r
+                                       } catch (ValidationException e) {\r
+                                               e.printStackTrace();\r
+                                       } catch (ServiceException e) {\r
+                                               e.printStackTrace();\r
+                                       }\r
+                                       \r
+                               }\r
+                               Display.getDefault().asyncExec(new Runnable() {                 \r
+                                       @Override\r
+                                       public void run() {\r
+                                               text1.setText(sb1.toString());\r
+                                               text2.setText(sb2.toString());\r
+                                               \r
+                                       }\r
+                               });\r
+                       }\r
+               });\r
+       }\r
+       \r
+       @Override\r
+       public void setFocus() {\r
+               composite.setFocus();\r
+       }\r
+       \r
+       @Override\r
+       public void dispose() {\r
+               super.dispose();\r
+               \r
+       }\r
+       \r
+       \r
+       // copy-paste from GraphDebugger\r
+        public Label createDropLabel(Composite parent) {\r
+               final Label label = new Label(parent, SWT.BORDER);\r
+               label.setAlignment(SWT.CENTER);\r
+               label.setText("Drag a resource here to examine it in this debugger!");\r
+               label.setForeground(parent.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY));\r
+               GridData data = new GridData(SWT.FILL, SWT.TOP, true, false);\r
+               data.heightHint = 16;\r
+               label.setLayoutData(data);\r
+\r
+               // Add resource id drop support to the drop-area.\r
+               DropTarget dropTarget = new DropTarget(label, DND.DROP_LINK | DND.DROP_COPY);\r
+               dropTarget.setTransfer(new Transfer[] { TextTransfer.getInstance(), ResourceReferenceTransfer.getInstance(), LocalObjectTransfer.getTransfer() });\r
+               dropTarget.addDropListener(new DropTargetAdapter() {\r
+                   @Override\r
+                   public void dragEnter(DropTargetEvent event) {\r
+                       event.detail = DND.DROP_LINK;\r
+                       //label.setBackground(green);\r
+                       return;\r
+                   }\r
+                   @Override\r
+                   public void dragLeave(DropTargetEvent event) {\r
+                       label.setBackground(null);\r
+                   }\r
+\r
+                   @Override\r
+                   public void drop(DropTargetEvent event) {\r
+                       label.setBackground(null);\r
+                       ResourceArray[] data = parseEventData(event);\r
+                       if (data == null || data.length != 1) {\r
+                           event.detail = DND.DROP_NONE;\r
+                           return;\r
+                       }\r
+                       final ResourceArray array = data[0];\r
+                       final Resource r = array.resources[array.resources.length - 1];\r
+\r
+                       label.setData(r);\r
+                       try {\r
+                                               label.setText(session.syncRequest(new Read<String>() {\r
+                                                       @Override\r
+                                                       public String perform(ReadGraph graph)\r
+                                                               throws DatabaseException {\r
+                                                               return GraphUtils.getReadableName(graph, r);\r
+                                                       }\r
+                                               }));\r
+                                       } catch (DatabaseException e) {\r
+                                               e.printStackTrace();\r
+                                       }\r
+                   }\r
+\r
+                   private ResourceArray[] parseEventData(DropTargetEvent event) {\r
+                       //System.out.println("DATA: " + event.data);\r
+                       if (event.data instanceof String) {\r
+                           try {\r
+                               SerialisationSupport support = session.getService(SerialisationSupport.class);\r
+                               return ResourceTransferUtils.readStringTransferable(support.getResourceSerializer(), (String) event.data).toResourceArrayArray();\r
+                           } catch (IllegalArgumentException e) {\r
+                               e.printStackTrace();\r
+                           } catch (IOException e) {\r
+                               e.printStackTrace();\r
+                           } catch (InvalidResourceReferenceException e) {\r
+                               e.printStackTrace();\r
+                           }\r
+                       }\r
+                       ResourceArray[] ret = ResourceAdaptionUtils.toResourceArrays(event.data);\r
+                       if (ret.length > 0)\r
+                           return ret;\r
+                       return null;\r
+                   }\r
+               });\r
+\r
+               return label;\r
+           }\r
+       \r
+       \r
+       \r
+       \r
+       \r
+       \r
+}\r