*
* Contributors:
* Foster Wheeler Energia Oy - initial API and implementation
+ * VTT Technical Research Centre of Finland - Improvements to comparison.
+ * Semantum Oy - Improvements to comparison, various bug fixes.
*******************************************************************************/
package org.simantics.interop.test;
import org.simantics.db.common.request.ReadRequest;
import org.simantics.db.common.utils.NameUtils;
import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.request.Read;
import org.simantics.interop.test.GraphChanges.Modification;
import org.simantics.layer0.Layer0;
import org.simantics.utils.datastructures.BijectionMap;
Set<Statement> unreliableLeft = new HashSet<Statement>();
Set<Statement> unreliableRight = new HashSet<Statement>();
+ boolean changed = false;
while (true) {
- if (objectsLeft.isEmpty())
+ if (objectsLeft.isEmpty() && !changed)
break;
-
+ changed = false;
// process compares objects that are identified and searches for more resources to process.
- process(objectsLeft, objectsRight, unreliableLeft, unreliableRight);
+ changed |= process(objectsLeft, objectsRight, unreliableLeft, unreliableRight);
// process unreliable handles cases where unidentified statements subject and object have been identified
- processUnreliable(unreliableLeft, unreliableRight);
+ changed |= processUnreliable(unreliableLeft, unreliableRight);
// process unreliable handles cases where unidentified resources have path of length one to identified resource
- processUnreliable(unreliableLeft, unreliableRight,objectsLeft,objectsRight);
+ changed |= processUnreliable(unreliableLeft, unreliableRight,objectsLeft,objectsRight);
if (objectsLeft.isEmpty() && unreliableLeft.size() > 0 && unreliableRight.size() > 0) {
- processUnreliable2(unreliableLeft, unreliableRight,objectsLeft,objectsRight);
+ changed |= processUnreliable2(unreliableLeft, unreliableRight,objectsLeft,objectsRight);
}
if (objectsLeft.isEmpty() && unreliableLeft.size() > 0 && unreliableRight.size() > 0) {
// comparison is ending, but we have still unprocessed unidentified resources left.
// These cases have longer path than one to identified objects.
- processUnreliableDeep(unreliableLeft, unreliableRight, objectsLeft, objectsRight);
+ changed |= processUnreliableDeep(unreliableLeft, unreliableRight, objectsLeft, objectsRight);
}
}
for (Statement s : unreliableLeft) {
- if (!comparableStatements.containsLeft(s))
+ if (!comparableStatements.containsLeft(s)) {
+ if (DEBUG) System.out.println("Unreliable Object deletion " + printStatement(g,s));
addDeletion(s);
+ }
}
for (Statement s : unreliableRight) {
- if (!comparableStatements.containsRight(s))
+ if (!comparableStatements.containsRight(s)) {
+ if (DEBUG) System.out.println("Unreliable Object addition " + printStatement(g,s));
addAddition(s);
+ }
}
}
final Set<Statement> unreliableLeft = new HashSet<Statement>();
final Set<Statement> unreliableRight = new HashSet<Statement>();
+ boolean changed = false;
while (true) {
- if (objectsLeft.isEmpty())
+ if (objectsLeft.isEmpty() && !changed)
break;
- session.syncRequest(new ReadRequest() {
+ changed = session.syncRequest(new Read<Boolean>() {
@Override
- public void run(ReadGraph graph) throws DatabaseException {
+ public Boolean perform(ReadGraph graph) throws DatabaseException {
g = graph;
b = Layer0.getInstance(graph);
// process compares objects that are identified and searches for more resources to process.
- process(objectsLeft, objectsRight, unreliableLeft, unreliableRight);
+ boolean c = process(objectsLeft, objectsRight, unreliableLeft, unreliableRight);
// process unreliable handles cases where unidentified statements subject and object have been identified
- processUnreliable(unreliableLeft, unreliableRight);
+ c |= processUnreliable(unreliableLeft, unreliableRight);
// process unreliable handles cases where unidentified resources have path of length one to identified resource
- processUnreliable(unreliableLeft, unreliableRight,objectsLeft,objectsRight);
+ c |= processUnreliable(unreliableLeft, unreliableRight,objectsLeft,objectsRight);
if (objectsLeft.isEmpty() && unreliableLeft.size() > 0 && unreliableRight.size() > 0) {
- processUnreliable2(unreliableLeft, unreliableRight,objectsLeft,objectsRight);
+ c |= processUnreliable2(unreliableLeft, unreliableRight,objectsLeft,objectsRight);
}
if (objectsLeft.isEmpty() && unreliableLeft.size() > 0 && unreliableRight.size() > 0) {
// comparison is ending, but we have still unprocessed unidentified resources left.
// These cases have longer path than one to identified objects.
- processUnreliableDeep(unreliableLeft, unreliableRight, objectsLeft, objectsRight);
+ c |= processUnreliableDeep(unreliableLeft, unreliableRight, objectsLeft, objectsRight);
}
if (objectsLeft.isEmpty() && unreliableLeft.size() > 0 && unreliableRight.size() > 0) {
// comparison is ending, but we have still unprocessed unidentified resources left.
// These cases have longer path than one to identified objects.
- processUnreliableDeep(unreliableLeft, unreliableRight, objectsLeft, objectsRight);
+ c |= processUnreliableDeep(unreliableLeft, unreliableRight, objectsLeft, objectsRight);
}
+ return c;
}
});
}
- private void process(Stack<Resource> objectsLeft, Stack<Resource> objectsRight, Set<Statement> unreliableLeft, Set<Statement> unreliableRight) throws DatabaseException {
+ private boolean process(Stack<Resource> objectsLeft, Stack<Resource> objectsRight, Set<Statement> unreliableLeft, Set<Statement> unreliableRight) throws DatabaseException {
List<Statement> ss1 = new ArrayList<Statement>();
List<Statement> ss2 = new ArrayList<Statement>();
-
+ boolean didSomething = false;
while (!objectsLeft.isEmpty()) {
Resource r1 = objectsLeft.pop();
Resource r2 = objectsRight.pop();
throw new DatabaseException("Comparator error: Trying to map " + r1 + " to " + r2 + " while mappings " + r1 + " to " + comparableResources.getRight(r1) + " and " + comparableResources.getLeft(r2) + " to " + r2 + " exist.");
}
addComparable(r1, r2);
-
+ didSomething = true;
//System.out.println("test " + NameUtils.getSafeName(g, r1) + " " + NameUtils.getSafeName(g, r2));
compareProps(r1, r2);
ss2 = filterTraversed(ss2);
ss1 = filterNonTested(ss1);
ss2 = filterNonTested(ss2);
-
+ ss1 = filter(Collections.singletonList(b.HasProperty), ss1);
+ ss2 = filter(Collections.singletonList(b.HasProperty), ss2);
compareStatements(ss1, ss2, null, null,null,null);
ss1.clear();
}
}
+ return didSomething;
}
- private void processUnreliable(Set<Statement> unreliableLeft, Set<Statement> unreliableRight) throws DatabaseException {
+ private boolean processUnreliable(Set<Statement> unreliableLeft, Set<Statement> unreliableRight) throws DatabaseException {
MapList<Resource,Statement> subjectLeft = new MapList<Resource, Statement>();
MapList<Resource,Statement> subjectRight = new MapList<Resource, Statement>();
MapList<Resource,Statement> objectLeft = new MapList<Resource, Statement>();
MapList<Resource,Statement> objectRight = new MapList<Resource, Statement>();
-
+ boolean didSomething = false;
for (Statement s : unreliableLeft) {
subjectLeft.add(s.getSubject(),s);
objectLeft.add(s.getObject(),s);
unreliableLeft.remove(leftS);
unreliableRight.remove(rightS);
addComparable(leftS, rightS);
+ didSomething = true;
}
}
}
}
+ return didSomething;
}
- private void processUnreliable(Set<Statement> unreliableLeft, Set<Statement> unreliableRight, Stack<Resource> objectsLeft, Stack<Resource> objectsRight) throws DatabaseException {
+ private boolean processUnreliable(Set<Statement> unreliableLeft, Set<Statement> unreliableRight, Stack<Resource> objectsLeft, Stack<Resource> objectsRight) throws DatabaseException {
MapList<Resource,Statement> subjectLeft = new MapList<Resource, Statement>();
MapList<Resource,Statement> subjectRight = new MapList<Resource, Statement>();
MapList<Resource,Statement> objectLeft = new MapList<Resource, Statement>();
MapList<Resource,Statement> objectRight = new MapList<Resource, Statement>();
-
+ boolean didSomething = false;
for (Statement s : unreliableLeft) {
subjectLeft.add(s.getSubject(),s);
objectLeft.add(s.getObject(),s);
objectsLeft.add(ol);
objectsRight.add(or);
addComparable(ol, or);
+ didSomething = true;
for (int l = 0; l < left.size(); l++) {
int r = indices.first[l];
Statement sl = left.get(l);
}
}
+ return didSomething;
}
- private void processUnreliable2(Set<Statement> unreliableLeft, Set<Statement> unreliableRight, Stack<Resource> objectsLeft, Stack<Resource> objectsRight) throws DatabaseException {
+ private boolean processUnreliable2(Set<Statement> unreliableLeft, Set<Statement> unreliableRight, Stack<Resource> objectsLeft, Stack<Resource> objectsRight) throws DatabaseException {
MapList<Resource,Statement> subjectLeft = new MapList<Resource, Statement>();
MapList<Resource,Statement> subjectRight = new MapList<Resource, Statement>();
MapList<Resource,Statement> objectLeft = new MapList<Resource, Statement>();
MapList<Resource,Statement> objectRight = new MapList<Resource, Statement>();
-
+ boolean didSomething = false;
for (Statement s : unreliableLeft) {
subjectLeft.add(s.getSubject(),s);
objectLeft.add(s.getObject(),s);
int count = comparableStatements.size();
compareStatements(ss1, ss2, objectsLeft, objectsRight,unreliableLeft,unreliableRight);
if (comparableStatements.size() > count) {
+ didSomething = true;
for (Entry<Statement, Statement> entry : comparableStatements.getEntries()) {
unreliableLeft.remove(entry.getKey());
unreliableRight.remove(entry.getValue());
}
}
}
+ return didSomething;
}
- private void processUnreliableDeep(Set<Statement> unreliableLeft, Set<Statement> unreliableRight, Stack<Resource> objectsLeft, Stack<Resource> objectsRight) throws DatabaseException {
+ private boolean processUnreliableDeep(Set<Statement> unreliableLeft, Set<Statement> unreliableRight, Stack<Resource> objectsLeft, Stack<Resource> objectsRight) throws DatabaseException {
MapList<Resource,Statement> subjectLeft = new MapList<Resource, Statement>();
MapList<Resource,Statement> subjectRight = new MapList<Resource, Statement>();
MapList<Resource,Statement> objectLeft = new MapList<Resource, Statement>();
MapList<Resource,Statement> objectRight = new MapList<Resource, Statement>();
-
+ boolean didSomething = false;
for (Statement s : unreliableLeft) {
subjectLeft.add(s.getSubject(),s);
objectLeft.add(s.getObject(),s);
}
if (matchingPaths.size() > 0) {
if (matchingPaths.size() == 1) {
+ didSomething = true;
Resource or = matchingPaths.keySet().iterator().next();
objectsLeft.add(ol);
}
}
+ return didSomething;
}
private void addComparable(Statement left, Statement right) throws DatabaseException {
addComparable(left.getObject(), right.getObject());
comparableStatements.map(left, right);
- //comparableResources.map(left.getObject(), right.getObject());
}
private void addComparable(Resource left, Resource right) throws DatabaseException {
private void addDeletion(Statement s) {
if (!changes1Set.contains(s)) {
+ if (DEBUG) System.out.println("- " +s.getSubject() + " " + s.getPredicate() + " " + s.getObject()) ;
changes1Set.add(s);
changes1.add(s);
}
private void addAddition(Statement s) {
if (!changes2Set.contains(s)) {
changes2Set.add(s);
+ if (DEBUG) System.out.println("+ " +s.getSubject() + " " + s.getPredicate() + " " + s.getObject()) ;
changes2.add(s);
}
}
boolean matchFail = priorityMatching(ss1, off1, len1, ss2, off2, len2, pris, differences, priorities, used1, used2, objectsLeft, objectsRight, false);
if (matchFail)
matchFail = priorityMatching(ss1, off1, len1, ss2, off2, len2, pris, differences, priorities, used1, used2, objectsLeft, objectsRight, objectsLeft == null);
-
- for (Integer pri : pris) {
- if (pri != 0 && !matchFail && unreliableLeft == null)
- continue;
- Set<Statement> s1s = new HashSet<Statement>();
- Set<Statement> s2s = new HashSet<Statement>();
- Set<Integer> s1i = new HashSet<Integer>();
- Set<Integer> s2i = new HashSet<Integer>();
- List<Integer> i1s = priorities.getValues(pri);
- for (Integer i1 : i1s) {
- if (used1[i1])
- continue;
- List<Integer> i2diff = differences.get(i1);
- for (int i2 = 0; i2 < i2diff.size(); i2++) {
- if (i2diff.get(i2) == pri) {
- if (used2[i2])
- continue;
- Statement s1 = ss1.get(i1+off1);
- Statement s2 = ss2.get(i2+off2);
- s1s.add(s1);
- s2s.add(s2);
- s1i.add(i1);
- s2i.add(i2);
- }
+ if (unreliableLeft != null) {
+ if (matchFail) {
+ // With match failure, statement matching was aborted. We must move all unmatched statements to unreliable.
+ for (Integer pri : pris) {
+ if (pri == 0 || pri == Integer.MAX_VALUE)
+ continue;
+ priorityProcessUnmatched(ss1, off1, len1, ss2, off2, len2, differences, priorities, used1, used2, unreliableLeft, unreliableRight, pri);
}
}
- if (unreliableLeft != null) {
- unreliableLeft.addAll(s1s);
- unreliableRight.addAll(s2s);
+ // Zero means unreliable comparison result, move all unmatched to unreliable.
+ if (org.simantics.utils.datastructures.Arrays.contains(pris, 0)) {
+ priorityProcessUnmatched(ss1, off1, len1, ss2, off2, len2, differences, priorities, used1, used2, unreliableLeft, unreliableRight, 0);
}
- for (Integer i : s1i)
- used1[i] = true;
- for (Integer i : s2i)
- used2[i] = true;
-
- }
+ }
+// Previous version processed 0 priority statements, even when unreliableLeft collection was null.
+// The problem was that property relations were not filtered in process() from "tested" statements.
+// else {
+// if (org.simantics.utils.datastructures.Arrays.contains(pris, 0)) {
+// priorityProcessUnmatched(ss1, off1, len1, ss2, off2, len2, differences, priorities, used1, used2, unreliableLeft, unreliableRight, 0);
+// }
+// }
+ // Report unmatched statements as changes.
for (int i1 = off1; i1 < off1 + len1; i1++) {
if (!used1[i1-off1]) {
if (DEBUG) System.out.println("Compare Object deletion " + printStatement(g,ss1.get(i1)));
}
}
+ /**
+ * Moves unmatched statements to unreliable collections.
+ * @param ss1
+ * @param off1
+ * @param len1
+ * @param ss2
+ * @param off2
+ * @param len2
+ * @param differences
+ * @param priorities
+ * @param used1
+ * @param used2
+ * @param unreliableLeft
+ * @param unreliableRight
+ * @param pri
+ */
+ private void priorityProcessUnmatched(List<Statement> ss1, int off1, int len1, List<Statement> ss2, int off2, int len2,List<List<Integer>> differences,MapList<Integer, Integer> priorities,boolean used1[],boolean used2[], Collection<Statement> unreliableLeft, Collection<Statement> unreliableRight, int pri) {
+ Set<Statement> s1s = new HashSet<Statement>();
+ Set<Statement> s2s = new HashSet<Statement>();
+ Set<Integer> s1i = new HashSet<Integer>();
+ Set<Integer> s2i = new HashSet<Integer>();
+ List<Integer> i1s = priorities.getValues(pri);
+ for (Integer i1 : i1s) {
+ if (used1[i1])
+ continue;
+ List<Integer> i2diff = differences.get(i1);
+ for (int i2 = 0; i2 < i2diff.size(); i2++) {
+ if (i2diff.get(i2) == pri) {
+ if (used2[i2])
+ continue;
+ Statement s1 = ss1.get(i1+off1);
+ Statement s2 = ss2.get(i2+off2);
+ s1s.add(s1);
+ s2s.add(s2);
+ s1i.add(i1);
+ s2i.add(i2);
+ }
+ }
+ }
+ if (unreliableLeft != null) {
+ unreliableLeft.addAll(s1s);
+ unreliableRight.addAll(s2s);
+ }
+ for (Integer i : s1i)
+ used1[i] = true;
+ for (Integer i : s2i)
+ used2[i] = true;
+ }
+ /**
+ * Matches left and right side statements.
+ *
+ * When there are two or more equally good matching objects, the behaviour depends on force flag.
+ * False: Matching is aborted and matchFail is returned (method return true).
+ * True: equally good matches will be paired randomly. Method always returns false.
+ * @param ss1
+ * @param off1
+ * @param len1
+ * @param ss2
+ * @param off2
+ * @param len2
+ * @param pris
+ * @param differences
+ * @param priorities
+ * @param used1
+ * @param used2
+ * @param objectsLeft
+ * @param objectsRight
+ * @param force
+ * @return
+ * @throws DatabaseException
+ */
private boolean priorityMatching(List<Statement> ss1, int off1, int len1, List<Statement> ss2, int off2, int len2, Integer[] pris, List<List<Integer>> differences, MapList<Integer, Integer> priorities, boolean used1[],boolean used2[], Collection<Resource> objectsLeft, Collection<Resource> objectsRight, boolean force) throws DatabaseException {
boolean matchFail = false;
for (Integer pri : pris) {
* compares properties, assumes functional relations
* @param r1
* @param r2
- * @throws ServiceException
- * @throws DoesNotContainValueException
- * @throws ValidationException
+ * @throws DatabaseException
*/
private void compareProps(Resource r1, Resource r2) throws DatabaseException {
if (DEBUG) System.out.println("compareProps " + r1 + " " + NameUtils.getSafeName(g, r1) + " " + r2 + " " + NameUtils.getSafeName(g, r2));
}
} else {
// Exact match, nothing to do.
+ if (!a1 && !a2)
+ addComparable(s1, s2);
}
}
} else {