1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
\r
3 * in Industry THTH ry.
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * Foster Wheeler Energia Oy - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.interop.test;
\r
14 import java.util.ArrayList;
\r
15 import java.util.Arrays;
\r
16 import java.util.Collection;
\r
17 import java.util.Collections;
\r
18 import java.util.Comparator;
\r
19 import java.util.HashMap;
\r
20 import java.util.HashSet;
\r
21 import java.util.List;
\r
22 import java.util.Map;
\r
23 import java.util.Set;
\r
24 import java.util.Stack;
\r
26 import org.simantics.db.ReadGraph;
\r
27 import org.simantics.db.Resource;
\r
28 import org.simantics.db.Session;
\r
29 import org.simantics.db.Statement;
\r
30 import org.simantics.db.common.request.ReadRequest;
\r
31 import org.simantics.db.common.utils.NameUtils;
\r
32 import org.simantics.db.exception.DatabaseException;
\r
33 import org.simantics.layer0.Layer0;
\r
34 import org.simantics.utils.datastructures.BijectionMap;
\r
35 import org.simantics.utils.datastructures.MapList;
\r
36 import org.simantics.utils.datastructures.Pair;
\r
39 * Compares two subgraphs and reports differences.
\r
41 * Assumes that subgraphs (defined using traverse relations) are not cyclic.
\r
43 * Assumes that properties can be used to identify objects, if relation type is not enough.
\r
47 * @author Marko Luukkainen <marko.luukkainen@vtt.fi>
\r
50 public class GraphComparator {
\r
52 private static final boolean DEBUG = false;
\r
54 private Resource r1;
\r
55 private Resource r2;
\r
56 private Set<Resource> strong = new HashSet<Resource>(); // List of relations that identify object, if subject is already identified.
\r
57 private List<Resource> traversed = new ArrayList<Resource>(); // list of relations that are traversed (and tested)
\r
58 private List<Resource> tested = new ArrayList<Resource>(); // list of relations that are tested, but not traversed
\r
59 private List<Resource> nonTraversed = new ArrayList<Resource>(); // list of relations that are not traversed
\r
60 private List<Resource> nonTested = new ArrayList<Resource>(); // list of relations that are not tested
\r
62 private List<Statement> changes1 = new ArrayList<Statement>();
\r
63 private List<Statement> changes2 = new ArrayList<Statement>();
\r
64 private List<Pair<Statement,Statement>> modifications = new ArrayList<Pair<Statement,Statement>>();
\r
65 private Set<Statement> changes1Set = new HashSet<Statement>();
\r
66 private Set<Statement> changes2Set = new HashSet<Statement>();
\r
67 private Set<Pair<Statement,Statement>> modificationsSet = new HashSet<Pair<Statement,Statement>>();
\r
69 private BijectionMap<Statement, Statement> comparableStatements = new BijectionMap<Statement, Statement>();
\r
70 private BijectionMap<Resource, Resource> comparableResources = new BijectionMap<Resource, Resource>();
\r
71 private Set<Resource> processedResources = new HashSet<Resource>();
\r
73 private ResourceComparator comparator;
\r
75 private Comparator<Statement> scomp = new PredicateComparator();
\r
76 private Comparator<Resource> rcomp = new ResComparator();
\r
78 // runtime attributes
\r
80 private ReadGraph g;
\r
83 public GraphComparator(Resource r1, Resource r2) {
\r
86 comparator = new TypeComparator();
\r
89 public GraphComparator(Resource r1, Resource r2, ResourceComparator comparator) {
\r
92 this.comparator = comparator;
\r
95 ArrayList<Statement> ss1 = new ArrayList<Statement>();
\r
96 ArrayList<Statement> ss2 = new ArrayList<Statement>();
\r
99 public Comparator<Resource> getResourceComparator() {
\r
103 public Comparator<Statement> getStatementComparator() {
\r
107 public Resource getR1() {
\r
111 public Resource getR2() {
\r
115 public void addTraversed(Resource rel) {
\r
116 traversed.add(rel);
\r
119 public void addTraversed(Collection<Resource> rels) {
\r
120 traversed.addAll(rels);
\r
123 public void addNonTraversed(Resource rel) {
\r
124 nonTraversed.add(rel);
\r
127 public void addNonTraversed(Collection<Resource> rels) {
\r
128 nonTraversed.addAll(rels);
\r
131 public void addTested(Resource rel) {
\r
135 public void addTested(Collection<Resource> rels) {
\r
136 tested.addAll(rels);
\r
139 public void addNonTested(Resource rel) {
\r
140 nonTested.add(rel);
\r
143 public void addNonTested(Collection<Resource> rels) {
\r
144 nonTested.addAll(rels);
\r
147 public void addComparableResources(Resource r1, Resource r2) {
\r
148 comparableResources.map(r1, r2);
\r
151 public void addComparableResources(BijectionMap<Resource, Resource> matching) {
\r
152 comparableResources.addAll(matching);
\r
155 public void addStrong(Resource r) {
\r
159 public void addStrong(Collection<Resource> rels) {
\r
160 strong.addAll(rels);
\r
164 public void test(ReadGraph g) throws DatabaseException {
\r
166 this.b = Layer0.getInstance(g);
\r
167 comparator.setComparator(this);
\r
169 Stack<Resource> objectsLeft = new Stack<Resource>();
\r
170 Stack<Resource> objectsRight = new Stack<Resource>();
\r
171 objectsLeft.push(r1);
\r
172 objectsRight.push(r2);
\r
174 Set<Statement> unreliableLeft = new HashSet<Statement>();
\r
175 Set<Statement> unreliableRight = new HashSet<Statement>();
\r
178 if (objectsLeft.isEmpty())
\r
182 // process compares objects that are identified and searches for more resources to process.
\r
183 process(objectsLeft, objectsRight, unreliableLeft, unreliableRight);
\r
184 // process unreliable handles cases where unidentified statements subject and object have been identified
\r
185 processUnreliable(unreliableLeft, unreliableRight);
\r
186 // process unreliable handles cases where unidentified resources have path of length one to identified resource
\r
187 processUnreliable(unreliableLeft, unreliableRight,objectsLeft,objectsRight);
\r
188 if (objectsLeft.isEmpty() && unreliableLeft.size() > 0 && unreliableRight.size() > 0) {
\r
189 // comparison is ending, but we have still unprocessed unidentified resources left.
\r
190 // These cases have longer path than one to identified objects.
\r
191 processUnreliableDeep(unreliableLeft, unreliableRight, objectsLeft, objectsRight);
\r
195 for (Statement s : unreliableLeft) {
\r
196 if (!comparableStatements.containsLeft(s))
\r
199 for (Statement s : unreliableRight) {
\r
200 if (!comparableStatements.containsRight(s))
\r
207 public void test(Session session) throws DatabaseException {
\r
208 test(session, r1, r2);
\r
211 public void test(Session session, Resource r1, Resource r2) throws DatabaseException {
\r
213 comparator.setComparator(this);
\r
215 addComparable(r1, r2, false);
\r
217 final Stack<Resource> objectsLeft = new Stack<Resource>();
\r
218 final Stack<Resource> objectsRight = new Stack<Resource>();
\r
219 objectsLeft.push(r1);
\r
220 objectsRight.push(r2);
\r
222 final Set<Statement> unreliableLeft = new HashSet<Statement>();
\r
223 final Set<Statement> unreliableRight = new HashSet<Statement>();
\r
226 if (objectsLeft.isEmpty())
\r
228 session.syncRequest(new ReadRequest() {
\r
231 public void run(ReadGraph graph) throws DatabaseException {
\r
233 b = Layer0.getInstance(graph);
\r
234 // process compares objects that are identified and searches for more resources to process.
\r
235 process(objectsLeft, objectsRight, unreliableLeft, unreliableRight);
\r
236 // process unreliable handles cases where unidentified statements subject and object have been identified
\r
237 processUnreliable(unreliableLeft, unreliableRight);
\r
238 // process unreliable handles cases where unidentified resources have path of length one to identified resource
\r
239 processUnreliable(unreliableLeft, unreliableRight,objectsLeft,objectsRight);
\r
240 if (objectsLeft.isEmpty() && unreliableLeft.size() > 0 && unreliableRight.size() > 0) {
\r
241 // comparison is ending, but we have still unprocessed unidentified resources left.
\r
242 // These cases have longer path than one to identified objects.
\r
243 processUnreliableDeep(unreliableLeft, unreliableRight, objectsLeft, objectsRight);
\r
251 for (Statement s : unreliableLeft) {
\r
252 if (!comparableStatements.containsLeft(s))
\r
255 for (Statement s : unreliableRight) {
\r
256 if (!comparableStatements.containsRight(s))
\r
263 private void process(Stack<Resource> objectsLeft, Stack<Resource> objectsRight, Set<Statement> unreliableLeft, Set<Statement> unreliableRight) throws DatabaseException {
\r
264 List<Statement> ss1 = new ArrayList<Statement>();
\r
265 List<Statement> ss2 = new ArrayList<Statement>();
\r
267 while (!objectsLeft.isEmpty()) {
\r
268 Resource r1 = objectsLeft.pop();
\r
269 Resource r2 = objectsRight.pop();
\r
274 if (processedResources.contains(r1))
\r
276 processedResources.add(r1);
\r
279 if((comparableResources.containsLeft(r1)||comparableResources.containsRight(r2)) && !comparableResources.contains(r1, r2)) {
\r
280 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.");
\r
282 addComparable(r1, r2, false);
\r
284 //System.out.println("test " + NameUtils.getSafeName(g, r1) + " " + NameUtils.getSafeName(g, r2));
\r
285 compareProps(r1, r2);
\r
287 for (Resource rel : tested) {
\r
288 ss1.addAll(g.getStatements(r1, rel));
\r
289 ss2.addAll(g.getStatements(r2, rel));
\r
290 ss1 = filterAsserted(r1, ss1);
\r
291 ss2 = filterAsserted(r2, ss2);
\r
292 ss1 = filterTraversed(ss1);
\r
293 ss2 = filterTraversed(ss2);
\r
294 ss1 = filterNonTested(ss1);
\r
295 ss2 = filterNonTested(ss2);
\r
298 compareStatements(ss1, ss2, null, null,null,null);
\r
303 for (Resource rel : traversed) {
\r
304 ss1.addAll(g.getStatements(r1, rel));
\r
305 ss2.addAll(g.getStatements(r2, rel));
\r
306 ss1 = filterAsserted(r1, ss1);
\r
307 ss2 = filterAsserted(r2, ss2);
\r
308 ss1 = filterNonTraversed(ss1);
\r
309 ss2 = filterNonTraversed(ss2);
\r
310 compareStatements(ss1, ss2, objectsLeft, objectsRight,unreliableLeft,unreliableRight);
\r
318 private void processUnreliable(Set<Statement> unreliableLeft, Set<Statement> unreliableRight) throws DatabaseException {
\r
319 MapList<Resource,Statement> subjectLeft = new MapList<Resource, Statement>();
\r
320 MapList<Resource,Statement> subjectRight = new MapList<Resource, Statement>();
\r
321 MapList<Resource,Statement> objectLeft = new MapList<Resource, Statement>();
\r
322 MapList<Resource,Statement> objectRight = new MapList<Resource, Statement>();
\r
324 for (Statement s : unreliableLeft) {
\r
325 subjectLeft.add(s.getSubject(),s);
\r
326 objectLeft.add(s.getObject(),s);
\r
328 for (Statement s : unreliableRight) {
\r
329 subjectRight.add(s.getSubject(),s);
\r
330 objectRight.add(s.getObject(),s);
\r
333 for (Resource left : subjectLeft.getKeys()) {
\r
334 if (!comparableResources.containsLeft(left))
\r
336 Resource right = comparableResources.getRight(left);
\r
337 for (Statement leftS : subjectLeft.getValues(left)) {
\r
338 Resource leftO = leftS.getObject();
\r
339 if (!comparableResources.containsLeft(leftO))
\r
341 if (!unreliableLeft.contains(leftS))
\r
343 Resource rightO = comparableResources.getRight(leftO);
\r
344 for (Statement rightS : subjectRight.getValues(right)) {
\r
345 if (!rightS.getObject().equals(rightO))
\r
347 if (!unreliableRight.contains(rightS))
\r
349 if (leftS.getPredicate().equals(rightS.getPredicate()) ||
\r
350 comparableResources.contains(leftS.getPredicate(), rightS.getPredicate())) {
\r
351 unreliableLeft.remove(leftS);
\r
352 unreliableRight.remove(rightS);
\r
353 addComparable(leftS, rightS, false);
\r
360 private void processUnreliable(Set<Statement> unreliableLeft, Set<Statement> unreliableRight, Stack<Resource> objectsLeft, Stack<Resource> objectsRight) throws DatabaseException {
\r
361 MapList<Resource,Statement> subjectLeft = new MapList<Resource, Statement>();
\r
362 MapList<Resource,Statement> subjectRight = new MapList<Resource, Statement>();
\r
363 MapList<Resource,Statement> objectLeft = new MapList<Resource, Statement>();
\r
364 MapList<Resource,Statement> objectRight = new MapList<Resource, Statement>();
\r
366 for (Statement s : unreliableLeft) {
\r
367 subjectLeft.add(s.getSubject(),s);
\r
368 objectLeft.add(s.getObject(),s);
\r
370 for (Statement s : unreliableRight) {
\r
371 subjectRight.add(s.getSubject(),s);
\r
372 objectRight.add(s.getObject(),s);
\r
375 for (Resource ol : objectLeft.getKeys()) {
\r
376 // all statements to the left side object
\r
377 List<Statement> left = objectLeft.getValues(ol);
\r
378 // all subjects that have statements to the left side object (ol)
\r
379 Set<Resource> sLeft = new HashSet<Resource>();
\r
380 // all matching subjects on the right side
\r
381 Set<Resource> sRight = new HashSet<Resource>();
\r
382 for (Statement s : left) {
\r
383 sLeft.add(s.getSubject());
\r
384 sRight.add(comparableResources.getRight(s.getSubject()));
\r
387 // check if object left can be reliably identified by available statements
\r
388 // if there are any objects on the left side with similar statements, object left cannot be mapped.
\r
389 boolean hasSimilar = false;
\r
390 MapList<Resource, Statement> comparableOLeft = new MapList<Resource, Statement>();
\r
391 for (Resource sl : sLeft) {
\r
392 for (Statement s : subjectLeft.getValues(sl)) {
\r
393 if (!s.getObject().equals(ol)) {
\r
394 comparableOLeft.add(s.getObject(),s);
\r
399 for (Resource similarOl : comparableOLeft.getKeys()) {
\r
400 List<Statement> similarLeft = comparableOLeft.getValues(similarOl);
\r
401 if (similarLeft.size() == left.size()) {
\r
402 boolean useL[] = new boolean[left.size()];
\r
403 boolean useSL[] = new boolean[left.size()];
\r
404 for (int i = 0; i < left.size(); i++) {
\r
408 for (int i = 0; i < left.size(); i++) {
\r
409 for (int j = 0; j < left.size(); j++) {
\r
412 Resource pl = left.get(i).getPredicate();
\r
413 Resource psl = similarLeft.get(j).getPredicate();
\r
414 if (pl.equals(psl)) {
\r
421 boolean diff = false;
\r
422 for (int i = 0; i < left.size(); i++) {
\r
423 if (!useL[i] || !useSL[i]) {
\r
438 // all objects that subjects on the right side point to. Object left has its matching resource among these, if it has matching resource
\r
439 MapList<Resource,Statement> possibleOR = new MapList<Resource, Statement>();
\r
440 for (Resource sr : sRight) {
\r
441 for (Statement s : subjectRight.getValues(sr))
\r
442 possibleOR.add(s.getObject(),s);
\r
445 // filter possible right side objects to those that have same amount of statements as the left side object
\r
446 for (Resource or : possibleOR.getKeys().toArray(new Resource[possibleOR.getKeys().size()])) {
\r
447 List<Statement> right = possibleOR.getValues(or);
\r
448 if (right.size() != left.size())
\r
449 possibleOR.remove(or);
\r
453 // check for matching statements (comparable subjects, matching predicates)
\r
454 MapList<Resource,Statement> matchingOR = new MapList<Resource, Statement>(); // list of objects that have matching statements
\r
455 Map<Resource,Pair<int[], int[]>> matchingStatements = new HashMap<Resource, Pair<int[], int[]>>(); // matching statements
\r
456 for (Resource or : possibleOR.getKeys()) {
\r
457 List<Statement> right = possibleOR.getValues(or);
\r
458 int iLeft[] = new int[left.size()];
\r
459 int iRight[] = new int[right.size()];
\r
461 for (int i = 0; i < left.size(); i++) {
\r
466 for (int l = 0; l < left.size(); l++) {
\r
467 Statement ls = left.get(l);
\r
468 for (int r = 0; r < right.size(); r++) {
\r
469 if (iRight[r] >= 0)
\r
471 Statement rs = right.get(r);
\r
472 if (!comparableResources.contains(ls.getSubject(), rs.getSubject()))
\r
474 if (rcomp.compare(ls.getPredicate(),rs.getPredicate()) == 0) {
\r
482 boolean success = true;
\r
483 for (int i = 0; i < left.size(); i++) {
\r
484 if (iLeft[i] < 0) {
\r
488 if (iRight[i] < 0) {
\r
495 for (Statement s : right)
\r
496 matchingOR.add(or,s);
\r
497 matchingStatements.put(or, new Pair<int[], int[]>(iLeft, iRight));
\r
500 // if there is only one matching right side object, we have found a match
\r
501 if (matchingOR.getKeySize() == 1) {
\r
502 Resource or = matchingOR.getKeys().iterator().next();
\r
503 List<Statement> right = matchingOR.getValues(or);
\r
504 Pair<int[], int[]> indices = matchingStatements.get(or);
\r
506 objectsLeft.add(ol);
\r
507 objectsRight.add(or);
\r
508 addComparable(ol, or, false);
\r
509 for (int l = 0; l < left.size(); l++) {
\r
510 int r = indices.first[l];
\r
511 Statement sl = left.get(l);
\r
512 Statement sr = right.get(r);
\r
513 addComparable(sl, sr, true);
\r
514 unreliableLeft.remove(sl);
\r
515 unreliableRight.remove(sr);
\r
525 private void processUnreliableDeep(Set<Statement> unreliableLeft, Set<Statement> unreliableRight, Stack<Resource> objectsLeft, Stack<Resource> objectsRight) throws DatabaseException {
\r
526 MapList<Resource,Statement> subjectLeft = new MapList<Resource, Statement>();
\r
527 MapList<Resource,Statement> subjectRight = new MapList<Resource, Statement>();
\r
528 MapList<Resource,Statement> objectLeft = new MapList<Resource, Statement>();
\r
529 MapList<Resource,Statement> objectRight = new MapList<Resource, Statement>();
\r
531 for (Statement s : unreliableLeft) {
\r
532 subjectLeft.add(s.getSubject(),s);
\r
533 objectLeft.add(s.getObject(),s);
\r
535 for (Statement s : unreliableRight) {
\r
536 subjectRight.add(s.getSubject(),s);
\r
537 objectRight.add(s.getObject(),s);
\r
539 for (Resource ol : objectLeft.getKeys()) {
\r
540 Set<Path> pathsLeft = new HashSet<Path>();
\r
541 for (Resource rel : traversed) {
\r
542 pathsLeft.addAll(Path.create(g.getStatements(ol, rel)));
\r
546 if (pathsLeft.size() == 0)
\r
548 Collection<Path> endPaths = new ArrayList<Path>(1);
\r
549 for (Path p : pathsLeft) {
\r
550 if (comparableResources.containsLeft(p.getEnd())) {
\r
554 if (endPaths.size() > 0) {
\r
556 pathsLeft.addAll(endPaths);
\r
560 if (pathsLeft.size() > 0) {
\r
561 Resource sl = objectLeft.getValues(ol).get(0).getSubject();
\r
562 Resource sr = comparableResources.getRight(sl);
\r
563 Collection<Resource> possibleOR = new ArrayList<Resource>();
\r
564 for (Statement s : subjectRight.getValues(sr)) {
\r
565 possibleOR.add(s.getObject());
\r
567 Map<Resource,Set<Path>> matchingPaths = new HashMap<Resource, Set<Path>>();
\r
568 for (Resource or : possibleOR) {
\r
569 Set<Path> possiblePathsRight = new HashSet<Path>();
\r
570 for (Path leftPath : pathsLeft) {
\r
571 possiblePathsRight.addAll(findComparableRight(leftPath, or));
\r
573 if (hasMatchingPaths(pathsLeft, possiblePathsRight)) {
\r
574 matchingPaths.put(or, possiblePathsRight);
\r
577 if (matchingPaths.size() > 0) {
\r
578 if (matchingPaths.size() == 1) {
\r
579 Resource or = matchingPaths.keySet().iterator().next();
\r
581 objectsLeft.add(ol);
\r
582 objectsRight.add(or);
\r
583 addComparable(ol, or, false);
\r
584 Collection<Statement> statementsLeft = objectLeft.getValues(ol);
\r
585 Collection<Statement> statementsRight = objectRight.getValues(or);
\r
586 unreliableLeft.removeAll(statementsLeft);
\r
587 unreliableRight.removeAll(statementsRight);
\r
588 BijectionMap<Path,Path> map = getMatchingPaths(pathsLeft, matchingPaths.get(or));
\r
589 for (Path left : map.getLeftSet()) {
\r
590 Path right = map.getRight(left);
\r
591 for (int i = 0; i < left.getLength(); i++) {
\r
592 addComparable(left.getStatements().get(i),right.getStatements().get(i),false);
\r
603 private boolean hasMatchingPaths(Set<Path> leftPaths, Set<Path> rightPaths) {
\r
604 if (leftPaths.size() != rightPaths.size())
\r
606 BijectionMap<Path,Path> map = getMatchingPaths(leftPaths, rightPaths);
\r
607 return map.size() == leftPaths.size();
\r
610 private BijectionMap<Path,Path> getMatchingPaths(Set<Path> leftPaths, Set<Path> rightPaths) {
\r
611 BijectionMap<Path,Path> map = new BijectionMap<Path, Path>();
\r
612 for (Path leftPath : leftPaths) {
\r
613 for (Path rightPath : rightPaths) {
\r
614 if (map.containsRight(rightPath))
\r
616 if (leftPath.getLength() != rightPath.getLength())
\r
618 if (comparableResources.contains(leftPath.getEnd(), rightPath.getEnd())) {
\r
619 map.map(leftPath, rightPath);
\r
627 private void expand(Set<Path> paths) throws DatabaseException {
\r
628 Set<Path> stepPathsLeft = new HashSet<Path>();
\r
629 if (paths.size() == 0)
\r
631 int length = paths.iterator().next().getLength() + 1;
\r
632 for (Path p : paths) {
\r
633 for (Resource rel : traversed) {
\r
634 stepPathsLeft.addAll(Path.expand(p,g.getStatements(p.getEnd(), rel)));
\r
638 for (Path p : stepPathsLeft) {
\r
639 if (p.getLength() == length)
\r
644 private Collection<Path> findComparableRight(Path leftPath, Resource beginRight) throws DatabaseException {
\r
645 Set<Path> rightPaths = new HashSet<Path>();
\r
646 rightPaths.addAll(Path.create(g.getStatements(beginRight, getRight(leftPath.getStatements().get(0).getPredicate()))));
\r
647 for (int i = 1; i < leftPath.getLength(); i++) {
\r
648 if (rightPaths.size() == 0)
\r
650 Set<Path> stepPaths = new HashSet<Path>();
\r
651 for (Path p : rightPaths) {
\r
652 stepPaths.addAll(Path.expand(p, g.getStatements(p.getEnd(), getRight(leftPath.getStatements().get(i).getPredicate()))));
\r
654 rightPaths.clear();
\r
655 for (Path p : stepPaths)
\r
656 if (p.getLength() == i+1)
\r
663 private Resource getRight(Resource r) {
\r
664 if (comparableResources.containsLeft(r))
\r
665 return comparableResources.getRight(r);
\r
671 public BijectionMap<Statement, Statement> getComparableStatements() {
\r
672 return comparableStatements;
\r
675 public BijectionMap<Resource, Resource> getComparableResources() {
\r
676 return comparableResources;
\r
679 public GraphChanges getChanges() {
\r
680 return new GraphChanges(r1,r2,changes1,changes2,modifications,comparableResources);
\r
683 private void addComparable(Statement left, Statement right, boolean process) throws DatabaseException {
\r
684 addComparable(left.getObject(), right.getObject(), process);
\r
685 comparableStatements.map(left, right);
\r
686 //comparableResources.map(left.getObject(), right.getObject());
\r
689 private void addComparable(Resource left, Resource right, boolean process) throws DatabaseException {
\r
690 if(!comparableResources.contains(left, right)) {
\r
691 if (comparableResources.containsLeft(left)||comparableResources.containsRight(right)) {
\r
692 throw new DatabaseException("Comparator error: Trying to map " + left + " to " + right + " while mappings " + left + " to " + comparableResources.getRight(left) + " and " + comparableResources.getLeft(right) + " to " + right + " exist.");
\r
694 if (DEBUG) System.out.println(left + " = " + right);
\r
695 comparableResources.map(left, right);
\r
701 public List<Statement> filterAsserted(Resource r, Collection<Statement> in) throws DatabaseException {
\r
702 List<Statement> out = new ArrayList<Statement>();
\r
703 for (Statement s : in) {
\r
704 if (!s.isAsserted(r))
\r
713 private String printStatement(ReadGraph graph, Statement s) throws DatabaseException {
\r
714 return NameUtils.getSafeName(graph, s.getSubject()) + " " + NameUtils.getSafeName(graph, s.getPredicate()) + " " + NameUtils.getSafeName(graph, s.getObject());
\r
717 private List<Statement> filterTraversed(List<Statement> in) throws DatabaseException {
\r
718 return filter(traversed, in);
\r
721 private List<Statement> filterNonTested(List<Statement> in) throws DatabaseException {
\r
722 return filter(nonTested, in);
\r
725 private List<Statement> filterNonTraversed(List<Statement> in) throws DatabaseException {
\r
726 return filter(nonTraversed, in);
\r
729 private List<Statement> filter(Collection<Resource> toFilter, List<Statement> in) throws DatabaseException {
\r
730 if (toFilter.size() == 0)
\r
732 List<Statement> out = new ArrayList<Statement>();
\r
733 for (Statement s : in) {
\r
734 boolean usable = true;
\r
735 for (Resource r : toFilter) {
\r
736 if (g.isSubrelationOf(s.getPredicate(),r)) {
\r
750 private void addDeletion(Statement s) {
\r
751 if (!changes1Set.contains(s)) {
\r
752 changes1Set.add(s);
\r
757 private void addAddition(Statement s) {
\r
758 if (!changes2Set.contains(s)) {
\r
759 changes2Set.add(s);
\r
764 private void addModification(Statement s1, Statement s2) {
\r
765 Pair<Statement, Statement> mod = new Pair<Statement, Statement>(s1,s2);
\r
766 if (!modificationsSet.contains(mod)) {
\r
767 modificationsSet.add(mod);
\r
768 modifications.add(mod);
\r
772 public void sortStatement(List<Statement> list1, List<Statement> list2) {
\r
773 sortStatement(list1, list2, scomp);
\r
776 public void sortStatement(List<Statement> list1, List<Statement> list2, Comparator<Statement> scomp) {
\r
777 Collections.sort(list1,scomp);
\r
778 Collections.sort(list2,scomp);
\r
780 List<Statement> sorted1 = new ArrayList<Statement>(list1.size());
\r
781 List<Statement> sorted2 = new ArrayList<Statement>(list2.size());
\r
782 sorted1.addAll(list1);
\r
783 sorted2.addAll(list2);
\r
787 for (int i = 0; i < list1.size(); ) {
\r
788 Statement s1 = list1.get(i);
\r
789 int same1 = sameRel(list1, i);
\r
790 for (int j = 0; j < list2.size(); j++) {
\r
791 Statement s2 = list2.get(j);
\r
792 if (scomp.compare(s1, s2) == 0) {
\r
793 int same2 = sameRel(list2, j);
\r
794 copy(sorted1,ss1,list1,i,same1);
\r
796 copy(sorted2,ss2,list2,j,same2);
\r
803 if (ss1 < sorted1.size()) {
\r
804 for (Statement s : list1) {
\r
805 if (!sorted1.contains(s)) {
\r
806 sorted1.set(ss1,s);
\r
811 if (ss2 < sorted2.size()) {
\r
812 for (Statement s : list2) {
\r
813 if (!sorted2.contains(s)) {
\r
814 sorted2.set(ss2,s);
\r
822 list1.addAll(sorted1);
\r
823 list2.addAll(sorted2);
\r
826 public <T> void copy(List<T> to, int toIndex, List<T> from, int fromIndex, int amount) {
\r
827 for (int i = 0; i < amount; i++) {
\r
828 to.set(toIndex + i, from.get(fromIndex+ i));
\r
832 public void sortResource(List<Resource> list1, List<Resource> list2) {
\r
833 Collections.sort(list1,rcomp);
\r
835 for (int i = 0; i < list1.size(); i++) {
\r
836 Resource s1 = list1.get(i);
\r
837 for (int j = js; j < list2.size(); j++) {
\r
838 Resource s2 = list2.get(j);
\r
839 if (rcomp.compare(s1, s2) == 0) {
\r
840 Resource t = list2.get(js);
\r
850 private void compareStatements(List<Statement> ss1, List<Statement> ss2, Stack<Resource> objectsLeft, Stack<Resource> objectsRight, Collection<Statement> unreliableLeft, Collection<Statement> unreliableRight) throws DatabaseException {
\r
851 sortStatement(ss1, ss2);
\r
857 if (i1 >= ss1.size()) {
\r
858 if (i2 >= ss2.size()) {
\r
861 while (i2 < ss2.size()) {
\r
862 if (DEBUG) System.out.println("Compare Statements addition " + printStatement(g,ss2.get(i2)));
\r
864 addAddition(ss2.get(i2));
\r
869 } else if (i2 >= ss2.size()) {
\r
870 while (i1 < ss1.size()) {
\r
871 if (DEBUG) System.out.println("Compare Statements deletion " + printStatement(g,ss1.get(i1)));
\r
872 addDeletion(ss1.get(i1));
\r
877 int same1 = sameRel(ss1, i1);
\r
878 int same2 = sameRel(ss2, i2);
\r
879 int c = rcomp.compare(ss1.get(i1).getPredicate(),ss2.get(i2).getPredicate());
\r
881 compareStatements(ss1, i1, same1, ss2, i2, same2,objectsLeft,objectsRight,unreliableLeft,unreliableRight);
\r
884 } else if (c < 0) {
\r
885 for (int i = 0; i < same1; i++) {
\r
886 if (DEBUG) System.out.println("Compare Statements deletion " + printStatement(g,ss1.get(i+i1)));
\r
887 addDeletion(ss1.get(i+i1));
\r
891 for (int i = 0; i < same2; i++) {
\r
892 if (DEBUG) System.out.println("Compare Statements addition " + printStatement(g,ss2.get(i+i2)));
\r
893 addAddition(ss2.get(i+i2));
\r
903 private int sameRel(List<Statement> statements, int off) {
\r
904 if (statements.size() <= off)
\r
907 long id = statements.get(off).getPredicate().getResourceId();
\r
908 for (int i = off+1; i <statements.size(); i++) {
\r
909 if (statements.get(i).getPredicate().getResourceId() == id)
\r
918 private int compareObject(Resource o1, Resource o2) throws DatabaseException {
\r
921 if (comparableResources.contains(o1, o2))
\r
923 if (comparableResources.containsLeft(o1))
\r
924 return Integer.MAX_VALUE;
\r
925 if (comparableResources.containsRight(o2))
\r
926 return Integer.MAX_VALUE;
\r
927 return comparator.compare(g, o1, o2);
\r
930 private void compareStatements(List<Statement> ss1, int off1, int len1, List<Statement> ss2, int off2, int len2, Collection<Resource> objectsLeft, Collection<Resource> objectsRight, Collection<Statement> unreliableLeft, Collection<Statement> unreliableRight) throws DatabaseException {
\r
931 boolean[] used1 = new boolean[len1];
\r
932 for (int i = 0; i < used1.length; i++) {
\r
936 boolean[] used2 = new boolean[len2];
\r
937 for (int i = 0; i < used2.length; i++) {
\r
941 // left, right, difference
\r
942 List<List<Integer>> differences = new ArrayList<List<Integer>>();
\r
943 for (int i1 = off1; i1 < off1 + len1; i1++) {
\r
944 Statement s1 = ss1.get(i1);
\r
945 List<Integer> diff = new ArrayList<Integer>();
\r
946 for (int i2 = off2; i2 < off2 + len2; i2++) {
\r
947 Statement s2 = ss2.get(i2);
\r
948 int d = compareObject(s1.getObject(), s2.getObject());
\r
950 for (Resource t : strong) {
\r
951 if (s1.getPredicate().equals(t) || g.isSubrelationOf(s1.getPredicate(), t)) {
\r
959 differences.add(diff);
\r
961 // difference, left
\r
962 MapList<Integer, Integer> priorities = new MapList<Integer, Integer>();
\r
963 for (int i = 0; i < differences.size(); i++) {
\r
964 List<Integer> list = differences.get(i);
\r
965 for (int j = 0; j < list.size(); j++) {
\r
966 priorities.add(list.get(j), i);
\r
970 Integer[] pris = priorities.getKeys(new Integer[]{});
\r
973 for (Integer pri : pris) {
\r
974 if (pri == Integer.MAX_VALUE) {
\r
976 } else if (pri == 0) {
\r
979 List<Integer> i1s = priorities.getValues(pri);
\r
980 for (Integer i1 : i1s) {
\r
983 List<Integer> i2diff = differences.get(i1);
\r
984 for (int i2 = 0; i2 < i2diff.size(); i2++) {
\r
985 if (i2diff.get(i2) == pri) {
\r
990 Statement s1 = ss1.get(i1+off1);
\r
991 Statement s2 = ss2.get(i2+off2);
\r
993 if (objectsLeft != null) {
\r
994 objectsLeft.add(s1.getObject());
\r
995 objectsRight.add(s2.getObject());
\r
997 addComparable(s1, s2, true);
\r
1005 for (Integer pri : pris) {
\r
1008 Set<Statement> s1s = new HashSet<Statement>();
\r
1009 Set<Statement> s2s = new HashSet<Statement>();
\r
1010 Set<Integer> s1i = new HashSet<Integer>();
\r
1011 Set<Integer> s2i = new HashSet<Integer>();
\r
1012 List<Integer> i1s = priorities.getValues(pri);
\r
1013 for (Integer i1 : i1s) {
\r
1016 List<Integer> i2diff = differences.get(i1);
\r
1017 for (int i2 = 0; i2 < i2diff.size(); i2++) {
\r
1018 if (i2diff.get(i2) == pri) {
\r
1021 Statement s1 = ss1.get(i1+off1);
\r
1022 Statement s2 = ss2.get(i2+off2);
\r
1030 if (unreliableLeft != null) {
\r
1031 unreliableLeft.addAll(s1s);
\r
1032 unreliableRight.addAll(s2s);
\r
1034 for (Integer i : s1i)
\r
1036 for (Integer i : s2i)
\r
1040 for (int i1 = off1; i1 < off1 + len1; i1++) {
\r
1041 if (!used1[i1-off1]) {
\r
1042 if (DEBUG) System.out.println("Compare Object deletion " + printStatement(g,ss1.get(i1)));
\r
1043 addDeletion(ss1.get(i1));
\r
1046 for (int i2 = off2; i2 < off2 + len2; i2++) {
\r
1047 if (!used2[i2-off2]) {
\r
1048 if (DEBUG) System.out.println("Compare Object addition " + printStatement(g,ss2.get(i2)));
\r
1049 addAddition(ss2.get(i2));
\r
1057 * compares properties, assumes functional relations
\r
1060 * @throws ServiceException
\r
1061 * @throws DoesNotContainValueException
\r
1062 * @throws ValidationException
\r
1064 private void compareProps(Resource r1, Resource r2) throws DatabaseException {
\r
1065 if (DEBUG) System.out.println("compareProps " + r1 + " " + NameUtils.getSafeName(g, r1) + " " + r2 + " " + NameUtils.getSafeName(g, r2));
\r
1066 List<Statement> ss1 = new ArrayList<Statement>();
\r
1067 List<Statement> ss2 = new ArrayList<Statement>();
\r
1068 ss1.addAll(g.getStatements(r1, b.HasProperty));
\r
1069 ss2.addAll(g.getStatements(r2, b.HasProperty));
\r
1070 ss1 = filterNonTested(ss1);
\r
1071 ss2 = filterNonTested(ss2);
\r
1072 sortStatement(ss1, ss2);
\r
1078 if (i1 >= ss1.size()) {
\r
1079 if (i2 >= ss2.size())
\r
1082 while (i2 < ss2.size()) {
\r
1083 if (DEBUG) System.out.println("Compare Prop diff2 " + printStatement(g,ss2.get(i2)));
\r
1084 addAddition(ss2.get(i2));
\r
1089 } else if (i2 >= ss2.size()) {
\r
1090 while (i1 < ss1.size()) {
\r
1091 if (DEBUG) System.out.println("Compare Prop diff1 " + printStatement(g,ss1.get(i1)));
\r
1092 addDeletion(ss1.get(i1));
\r
1097 Statement s1 = ss1.get(i1);
\r
1098 Statement s2 = ss2.get(i2);
\r
1099 if (s1.isAsserted(r1) && s2.isAsserted(r2)) {
\r
1104 int c = scomp.compare(s1, s2);
\r
1107 boolean b1 = g.hasValue(s1.getObject());
\r
1108 boolean b2 = g.hasValue(s2.getObject());
\r
1111 Object v1 = g.getValue(s1.getObject());
\r
1112 Object v2 = g.getValue(s2.getObject());
\r
1113 boolean eq = compareValue(v1, v2);
\r
1115 addModification(s1, s2);
\r
1116 addComparable(s1, s2, false);
\r
1119 if (!s1.getObject().equals(s1.getSubject()) && !s2.getObject().equals(s2.getSubject()))
\r
1120 compareProps(s1.getObject(), s2.getObject());
\r
1123 addModification(s1, s2);
\r
1124 addComparable(s1, s2, false);
\r
1131 if (DEBUG) System.out.println("Compare Prop diff1s " + printStatement(g,s1));
\r
1138 if (DEBUG) System.out.println("Compare Prop diff2s " + printStatement(g,s2));
\r
1152 public static boolean compareValue(Object v1, Object v2) {
\r
1153 if (v1 instanceof Object[] && v2 instanceof Object[])
\r
1154 return Arrays.deepEquals((Object[])v1, (Object[])v2);
\r
1155 else if (v1 instanceof int[] && v2 instanceof int[])
\r
1156 return Arrays.equals((int[])v1, (int[])v2);
\r
1157 else if (v1 instanceof float[] && v2 instanceof float[])
\r
1158 return Arrays.equals((float[])v1, (float[])v2);
\r
1159 else if (v1 instanceof double[] && v2 instanceof double[])
\r
1160 return Arrays.equals((double[])v1, (double[])v2);
\r
1161 else if (v1 instanceof long[] && v2 instanceof long[])
\r
1162 return Arrays.equals((long[])v1, (long[])v2);
\r
1163 else if (v1 instanceof byte[] && v2 instanceof byte[])
\r
1164 return Arrays.equals((byte[])v1, (byte[])v2);
\r
1165 else if (v1 instanceof boolean[] && v2 instanceof boolean[])
\r
1166 return Arrays.equals((boolean[])v1, (boolean[])v2);
\r
1168 return v1.equals(v2);
\r
1172 public class PredicateComparator implements Comparator<Statement> {
\r
1174 public int compare(Statement o1, Statement o2) {
\r
1175 if (comparableResources.contains(o1.getPredicate(), o2.getPredicate()))
\r
1177 if (o1.getPredicate().getResourceId() < o2.getPredicate().getResourceId())
\r
1179 if (o1.getPredicate().getResourceId() > o2.getPredicate().getResourceId())
\r
1185 public class SubjectComparator implements Comparator<Statement> {
\r
1187 public int compare(Statement o1, Statement o2) {
\r
1188 if (comparableResources.contains(o1.getSubject(), o2.getSubject()))
\r
1190 if (o1.getSubject().getResourceId() < o2.getSubject().getResourceId())
\r
1192 if (o1.getSubject().getResourceId() > o2.getSubject().getResourceId())
\r
1198 public class ObjectComparator implements Comparator<Statement> {
\r
1200 public int compare(Statement o1, Statement o2) {
\r
1201 if (comparableResources.contains(o1.getObject(), o2.getObject()))
\r
1203 if (o1.getObject().getResourceId() < o2.getObject().getResourceId())
\r
1205 if (o1.getObject().getResourceId() > o2.getObject().getResourceId())
\r
1211 public static class FullStatementComparator implements Comparator<Statement> {
\r
1213 public int compare(Statement o1, Statement o2) {
\r
1214 if (o1.getSubject().getResourceId() < o2.getSubject().getResourceId())
\r
1216 if (o1.getSubject().getResourceId() > o2.getSubject().getResourceId())
\r
1218 if (o1.getPredicate().getResourceId() < o2.getPredicate().getResourceId())
\r
1220 if (o1.getPredicate().getResourceId() > o2.getPredicate().getResourceId())
\r
1222 if (o1.getObject().getResourceId() < o2.getObject().getResourceId())
\r
1224 if (o1.getObject().getResourceId() > o2.getObject().getResourceId())
\r
1230 public class ResComparator implements Comparator<Resource> {
\r
1232 public int compare(Resource o1, Resource o2) {
\r
1233 if (comparableResources.contains(o1, o2))
\r
1235 if (o1.getResourceId() < o2.getResourceId())
\r
1237 if (o1.getResourceId() > o2.getResourceId())
\r