]> gerrit.simantics Code Review - simantics/interop.git/blobdiff - org.simantics.interop/src/org/simantics/interop/test/GraphChanges.java
Graph comparison and change management fixes.
[simantics/interop.git] / org.simantics.interop / src / org / simantics / interop / test / GraphChanges.java
index b25eea87d49795573a2f26e2f33566d66fdd3f53..304c156f3ec166a85440569087aa0e5c74221fdb 100644 (file)
@@ -1,15 +1,18 @@
 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;
-import org.simantics.utils.datastructures.Pair;
 
 public class GraphChanges {
        
@@ -17,12 +20,109 @@ public class GraphChanges {
        private Resource r2;
        private List<Statement> deletions;
        private List<Statement> additions;
-       private List<Pair<Statement,Statement>> modifications;
+       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<Pair<Statement, Statement>> modifications, BijectionMap<Resource, Resource> comparable) {
+                       List<Modification> modifications, BijectionMap<Resource, Resource> comparable) {
                super();
                this.r1 = r1;
                this.r2 = r2;
@@ -48,7 +148,7 @@ public class GraphChanges {
                return deletions;
        }
        
-       public List<Pair<Statement, Statement>> getModifications() {
+       public List<Modification> getModifications() {
                return modifications;
        }
        
@@ -60,38 +160,63 @@ public class GraphChanges {
                StringBuilder sb = new StringBuilder();
                sb.append("Del:\n");
                for (Statement stm : deletions) {
-                       sb.append(NameUtils.getSafeName(graph, stm.getSubject()) + " "+
-                                                  NameUtils.getSafeName(graph, stm.getPredicate()) + " " +
-                                                  NameUtils.getSafeName(graph, stm.getObject()) + " (" +
-                                                  stm.getSubject() + " " +stm.getPredicate() + " " + stm.getObject() + ")\n");
+                       sb.append(toString(graph, stm));
+                       sb.append("\n");
        }
                sb.append("Add:\n");
                for (Statement stm : additions) {
-                       sb.append(NameUtils.getSafeName(graph, stm.getSubject()) + " "+
-                                          NameUtils.getSafeName(graph, stm.getPredicate()) + " " +
-                                  NameUtils.getSafeName(graph, stm.getObject()) + " (" +
-                                  stm.getSubject() + " " +stm.getPredicate() + " " + stm.getObject() + ")\n");
+                       sb.append(toString(graph, stm));
+                       sb.append("\n");
        }
                sb.append("Mod:\n");
-               for (Pair<Statement, Statement> mod :modifications) {
-                       {
-                               Statement stm = mod.first;
-                               sb.append(NameUtils.getSafeName(graph, stm.getSubject()) + " "+
+               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()) + " " +
-                                          NameUtils.getSafeName(graph, stm.getObject()) + " (" +
-                                          stm.getSubject() + " " +stm.getPredicate() + " " + stm.getObject() + ")\n");
+                                                  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.second;
-                               sb.append(NameUtils.getSafeName(graph, stm.getSubject()) + " "+
+               }
+               {
+                       Statement stm = mod.getRightStm();
+                       if (stm != null) {
+                               sb.append(NameUtils.getSafeName(graph, mod.getRightSub()) + " "+
                                                   NameUtils.getSafeName(graph, stm.getPredicate()) + " " +
-                                          NameUtils.getSafeName(graph, stm.getObject()) + " (" +
-                                          stm.getSubject() + " " +stm.getPredicate() + " " + stm.getObject() + ")\n");
+                                                  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");
@@ -103,5 +228,135 @@ public class GraphChanges {
                }
                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 (o2 == null)
+                                               o2 = graph.getPossibleObject(s2, p2);
+                                       
+                                       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);
+       }
 
 }