]> gerrit.simantics Code Review - simantics/interop.git/blobdiff - org.simantics.interop/src/org/simantics/interop/test/GraphChanges.java
Graph Comparison / Change management fixes.
[simantics/interop.git] / org.simantics.interop / src / org / simantics / interop / test / GraphChanges.java
index facb75abce9ac752eea6f1229a5f656d685b64fd..f9065070fe095f8e3c247c12bf03011f8db811cd 100644 (file)
-package org.simantics.interop.test;\r
-\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.BijectionMap;\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
-       private BijectionMap<Resource, Resource> comparable;\r
-       \r
-       public GraphChanges(Resource r1, Resource r2, List<Statement> deletions, List<Statement> additions,\r
-                       List<Pair<Statement, Statement>> modifications, BijectionMap<Resource, Resource> comparable) {\r
-               super();\r
-               this.r1 = r1;\r
-               this.r2 = r2;\r
-               this.deletions = deletions;\r
-               this.additions = additions;\r
-               this.modifications = modifications;\r
-               this.comparable = comparable;\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
-       \r
-       public List<Statement> getDeletions() {\r
-               return deletions;\r
-       }\r
-       \r
-       public List<Pair<Statement, Statement>> getModifications() {\r
-               return modifications;\r
-       }\r
-       \r
-       public BijectionMap<Resource, Resource> getComparable() {\r
-               return comparable;\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
+package org.simantics.interop.test;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map.Entry;
+
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.Session;
+import org.simantics.db.Statement;
+import org.simantics.db.common.request.ReadRequest;
+import org.simantics.db.common.utils.NameUtils;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.utils.datastructures.BijectionMap;
+
+public class GraphChanges {
+       
+       private Resource r1;
+       private Resource r2;
+       private List<Statement> deletions;
+       private List<Statement> additions;
+       private List<Modification> modifications;
+       
+       private BijectionMap<Resource, Resource> comparable;
+       
+       public static class Modification {
+               Resource leftSub;
+               Resource rightSub;
+               Statement leftStm;
+               Statement rightStm;
+
+               
+               int hashCode;
+               
+               public Modification(Resource leftSub, Resource rightSub, Statement leftStm, Statement rightStm) {
+                       this.leftSub = leftSub;
+                       this.rightSub = rightSub;
+                       this.leftStm = leftStm;
+                       this.rightStm = rightStm;
+                       
+                       hashCode = leftSub.hashCode() + rightSub.hashCode();
+                       if (leftStm != null)
+                               hashCode += leftStm.hashCode();
+                       if (rightStm != null)
+                               hashCode += rightStm.hashCode();
+               }
+
+               public boolean isLeftAsserted() {
+                       return leftStm != null && !leftSub.equals(leftStm.getSubject());
+               }
+               
+               public boolean isRightAsserted() {
+                       return rightStm != null && !rightSub.equals(rightStm.getSubject());
+               }
+
+               public Resource getLeftSub() {
+                       return leftSub;
+               }
+
+               public void setLeftSub(Resource leftSub) {
+                       this.leftSub = leftSub;
+               }
+
+               public Resource getRightSub() {
+                       return rightSub;
+               }
+
+               public void setRightSub(Resource rightSub) {
+                       this.rightSub = rightSub;
+               }
+
+               public Statement getLeftStm() {
+                       return leftStm;
+               }
+
+               public void setLeftStm(Statement leftStm) {
+                       this.leftStm = leftStm;
+               }
+
+               public Statement getRightStm() {
+                       return rightStm;
+               }
+
+               public void setRightStm(Statement rightStm) {
+                       this.rightStm = rightStm;
+               }
+               
+               public Resource getPredicate() {
+                   if (leftStm != null)
+                       return leftStm.getPredicate();
+                   return rightStm.getPredicate();
+               }
+               
+               @Override
+               public boolean equals(Object obj) {
+                       if (obj.getClass() != this.getClass())
+                               return false;
+                       Modification other = (Modification)obj;
+                       if (!leftSub.equals(other.leftSub))
+                               return false;
+                       if (!rightSub.equals(other.rightSub))
+                               return false;
+                       if (leftStm != null) {
+                               if (!leftStm.equals(other.leftStm))
+                                       return false;
+                       } else if (other.leftStm != null)
+                               return false;
+                       if (rightStm != null) {
+                               if (!rightStm.equals(other.rightStm))
+                                       return false;
+                       } else if (other.rightStm != null)
+                               return false;
+                       return true;
+               }
+               
+               @Override
+               public int hashCode() {
+                       return hashCode;
+               }
+
+       }
+       
+       public GraphChanges(Resource r1, Resource r2, List<Statement> deletions, List<Statement> additions,
+                       List<Modification> modifications, BijectionMap<Resource, Resource> comparable) {
+               super();
+               this.r1 = r1;
+               this.r2 = r2;
+               this.deletions = deletions;
+               this.additions = additions;
+               this.modifications = modifications;
+               this.comparable = comparable;
+       }
+       
+       public Resource getResource1() {
+               return r1;
+       }
+       
+       public Resource getResource2() {
+               return r2;
+       }
+       
+       public List<Statement> getAdditions() {
+               return additions;
+       }
+       
+       public List<Statement> getDeletions() {
+               return deletions;
+       }
+       
+       public List<Modification> getModifications() {
+               return modifications;
+       }
+       
+       public BijectionMap<Resource, Resource> getComparable() {
+               return comparable;
+       }
+       
+       public String toString(ReadGraph graph) throws DatabaseException {
+               StringBuilder sb = new StringBuilder();
+               sb.append("Del:\n");
+               for (Statement stm : deletions) {
+                       sb.append(toString(graph, stm));
+                       sb.append("\n");
+       }
+               sb.append("Add:\n");
+               for (Statement stm : additions) {
+                       sb.append(toString(graph, stm));
+                       sb.append("\n");
+       }
+               sb.append("Mod:\n");
+               for (Modification mod :modifications) {
+                       sb.append(toString(graph, mod));
+                       sb.append("\n");
+       }
+               return sb.toString();
+       }
+       
+       public static String toString(ReadGraph graph, Statement stm) throws DatabaseException{
+               return NameUtils.getSafeName(graph, stm.getSubject()) + " "+
+                                  NameUtils.getSafeName(graph, stm.getPredicate()) + " " +
+                          NameUtils.getSafeName(graph, stm.getObject()) + " (" +
+                          stm.getSubject() + " " +stm.getPredicate() + " " + stm.getObject();
+       }
+       
+       public static String toString(ReadGraph graph, Modification mod) throws DatabaseException{
+               StringBuilder sb = new StringBuilder();
+               {
+                       Statement stm = mod.getLeftStm();
+                       if (stm != null) {
+                               sb.append(NameUtils.getSafeName(graph, mod.getLeftSub()) + " "+
+                                                  NameUtils.getSafeName(graph, stm.getPredicate()) + " " +
+                                                  truncate(NameUtils.getSafeName(graph, stm.getObject())) + " (" +
+                                                  mod.getLeftSub() + " " + stm.getSubject() + " " +stm.getPredicate() + " " + stm.getObject() + ")\n");
+                       } else {
+                               sb.append(NameUtils.getSafeName(graph, mod.getLeftSub()) + " "+  mod.getLeftSub() + " N/A\n");
+                       }
+               }
+               {
+                       Statement stm = mod.getRightStm();
+                       if (stm != null) {
+                               sb.append(NameUtils.getSafeName(graph, mod.getRightSub()) + " "+
+                                                  NameUtils.getSafeName(graph, stm.getPredicate()) + " " +
+                                                  truncate(NameUtils.getSafeName(graph, stm.getObject())) + " (" +
+                                                  mod.getRightSub() + " " + stm.getSubject() + " " +stm.getPredicate() + " " + stm.getObject() + ")");
+                       } else {
+                               sb.append(NameUtils.getSafeName(graph, mod.getRightSub()) + " "+  mod.getRightSub() + " N/A");
+                       }
+                       
+               }
+               return sb.toString();
+       }
+       
+       public static String truncate(String s) {
+               if (s.length() < 100)
+                       return s;
+               return s.substring(0, 100)+"...";
+       }
+       
+       public String comparableToString(ReadGraph graph) throws DatabaseException {
+               StringBuilder sb = new StringBuilder();
+               sb.append("Comparable:\n");
+               for (Entry<Resource, Resource> entry : comparable.getEntries()) {
+                       sb.append(NameUtils.getSafeName(graph, entry.getKey()) + " "+
+                                          NameUtils.getSafeName(graph, entry.getValue()) + " (" +
+                                          entry.getKey() + " " +entry.getValue() + ")\n");
+                       
+               }
+               return sb.toString();
+       }
+       
+       /**
+        * Adapts GraphChanges between A1 and B to A2 and B, when A2 is copy of A1.
+        * @param changes changes between A1 and B
+        * @param bijection changes between A1 and A2. Expected to be a bijection, so no additions or removals.
+        * @return
+        * @throws DatabaseException
+        */
+       public static GraphChanges adapt(Session session, GraphChanges changes, GraphChanges bijection) throws DatabaseException{
+               if (!changes.getResource1().equals(bijection.getResource1()))
+                       throw new DatabaseException("Left side model must be the same");
+               //if (bijection.getDeletions().size() > 0 || bijection.getAdditions().size() > 0)
+               //      throw new DatabaseException("Bijection change is not a bijection, it contains additions and/or removals");
+               BijectionMap<Resource, Resource> comparable = new BijectionMap<Resource, Resource>();
+               for (Entry<Resource, Resource> entry : changes.comparable.getEntries()) {
+                       if (entry.getKey().equals(entry.getValue())) {
+                               comparable.map(entry.getKey(), entry.getValue());
+                       } else {
+                               Resource nl = bijection.getComparable().getRight(entry.getKey());
+                               if (nl == null) {
+                                       // Matching literal resources are not included in bijection map.
+                                       // TODO : should we check that the resource is literal?
+                                       // throw new DatabaseException("Did not find matching resource from bijection for " + entry.getKey());
+                                       continue;
+                               }
+                               comparable.map(nl, entry.getValue());
+                       }
+               }
+               List<Statement> deletions = new ArrayList<Statement>(changes.getDeletions().size()); // Removals must be adapted from A1 to A2.
+               List<Statement> additions = new ArrayList<Statement>(changes.getAdditions()); // Additions can be copied, since they are statements in B.
+               session.syncRequest(new ReadRequest() {
+                       
+                       @Override
+                       public void run(ReadGraph graph) throws DatabaseException {
+                               for (Statement del : changes.getDeletions()) {
+                                       Resource s1 = del.getSubject();
+                                       Resource s2 = bijection.getComparable().getRight(s1);
+                                       Resource p1 = del.getPredicate();
+                                       Resource p2 = bijection.getComparable().getRight(p1);
+                                       if (p2 == null)
+                                               p2 = p1;
+                                       Resource o1 = del.getObject();
+                                       Resource o2 = bijection.getComparable().getRight(o1);
+                                       
+                                       if (s2 == null || p2 == null || o2 == null) {
+                                               throw new DatabaseException("Did not find matching statement from bijection for (" + s1 +","+p1+","+o1+"), got (" + s2 +","+p2+","+o2+")");
+                                       }
+                                       Statement stm2 = null;
+                                       for (Statement s : graph.getStatements(s2, p2)) {
+                                               if (s.getObject().equals(o2)) {
+                                                       stm2 = s;
+                                                       break;
+                                               }
+                                       }
+                                       if (stm2 == null) {
+                                               throw new DatabaseException("Did not find matching statement from bijection for (" + s1 +","+p1+","+o1+"), got (" + s2 +","+p2+","+o2+"), but it is not in DB!");
+                                       }
+                                       deletions.add(stm2);
+                               }
+                               
+                       }
+               });
+               
+               List<Modification> modifications = new ArrayList<GraphChanges.Modification>(changes.getModifications().size());
+               
+               session.syncRequest(new ReadRequest() {
+                       
+                       @Override
+                       public void run(ReadGraph graph) throws DatabaseException {
+                               for (Modification mod : changes.getModifications()) {
+                                       Statement del = mod.leftStm;
+                                       Resource sub1 = mod.getLeftSub();
+                                       Resource sub2 = bijection.getComparable().getRight(sub1);
+                                       Resource p1 = del != null ? del.getPredicate() : mod.getPredicate();
+                                       Resource p2 = bijection.getComparable().getRight(p1);
+                                       if (p2 == null)
+                                               p2 = p1;
+                                       Resource o1 = del != null ? del.getObject() : null;
+                                       Resource o2 = bijection.getComparable().getRight(o1);
+                                       
+                                       if (mod.isLeftAsserted()) {
+                                               if (sub2 == null)
+                                                       sub2 = sub1;
+                                               
+                                       }
+                                       if (o2 == null && p2 != null)
+                                               o2 = graph.getPossibleObject(sub2, p2);
+                                       if (mod.isLeftAsserted()) {
+                                               if (o2 == null)
+                                                       o2 = o1;
+                                       }
+                                       if (sub2 == null || p2 == null) {
+                                               throw new DatabaseException("Did not find matching statement from bijection for (" + sub1 +","+p1+","+o1+"), got (" + sub2 +","+p2+","+o2+")");
+                                       }
+                                       if (del == null) {
+                                               Modification mod2 = new Modification(sub2, mod.rightSub, null, mod.rightStm);
+                                               modifications.add(mod2);
+                                       } else {
+                                               Collection<Statement> stms = graph.getStatements(sub2, p2);
+                                               Statement stm2 = null;
+                                               if (o2 == null) {
+                                                       // Matching literal resources are not included in bijection map.
+                                                       if (stms.size() == 1) {
+                                                               stm2 = stms.iterator().next();
+                                                       } else {
+                                                               throw new DatabaseException("Did not find matching statement from bijection for (" + sub1 +","+p1+","+o1+"), got (" + sub2 +","+p2+","+o2+")");
+                                                       }
+                                               } else {
+                                                       for (Statement s : stms) {
+                                                               if (s.getObject().equals(o2)) {
+                                                                       stm2 = s;
+                                                                       break;
+                                                               }
+                                                       }
+                                               }
+                                               if (stm2 == null) {
+                                                       throw new DatabaseException("Did not find matching statement from bijection for (" + sub1 +","+p1+","+o1+"), got (" + sub2 +","+p2+","+o2+"), but it is not in DB!");
+                                               }
+                                               Modification mod2 = new Modification(sub2, mod.rightSub, stm2, mod.rightStm);
+                                               modifications.add(mod2);
+                                       }
+                               }
+                               
+                       }
+               });
+               
+               return new GraphChanges(bijection.r2, changes.r2, deletions, additions, modifications, comparable);
+       }
+
+}