-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 (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);
+ }
+
+}