]> gerrit.simantics Code Review - simantics/interop.git/blob - org.simantics.interop/src/org/simantics/interop/test/GraphComparator.java
Statement processing could match objects that were already matched.
[simantics/interop.git] / org.simantics.interop / src / org / simantics / interop / test / GraphComparator.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management
3  * in Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     Foster Wheeler Energia Oy - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.interop.test;
13
14 import java.util.ArrayList;
15 import java.util.Arrays;
16 import java.util.Collection;
17 import java.util.Collections;
18 import java.util.Comparator;
19 import java.util.HashMap;
20 import java.util.HashSet;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Map.Entry;
24 import java.util.Set;
25 import java.util.Stack;
26
27 import org.simantics.databoard.Bindings;
28 import org.simantics.db.ReadGraph;
29 import org.simantics.db.Resource;
30 import org.simantics.db.Session;
31 import org.simantics.db.Statement;
32 import org.simantics.db.common.request.ReadRequest;
33 import org.simantics.db.common.utils.NameUtils;
34 import org.simantics.db.exception.DatabaseException;
35 import org.simantics.interop.test.GraphChanges.Modification;
36 import org.simantics.layer0.Layer0;
37 import org.simantics.utils.datastructures.BijectionMap;
38 import org.simantics.utils.datastructures.MapList;
39 import org.simantics.utils.datastructures.Pair;
40
41 /**
42  * Compares two subgraphs and reports differences.
43  * 
44  * Assumes that subgraphs (defined using traverse relations) are not cyclic.
45  * 
46  * Assumes that properties can be used to identify objects, if relation type is not enough.
47  * 
48  * 
49  * 
50  * @author Marko Luukkainen <marko.luukkainen@vtt.fi>
51  *
52  */
53 public class GraphComparator {
54         
55         private static final boolean DEBUG = false;
56
57         private Resource r1;
58         private Resource r2;
59         private Set<Resource> strong = new HashSet<>();       // List of relations that identify object, if subject is already identified. 
60         private List<Resource> traversed = new ArrayList<>(); // list of relations that are traversed (and tested)
61         private List<Resource> tested = new ArrayList<>();    // list of relations that are tested, but not traversed
62         private List<Resource> nonTraversed = new ArrayList<>(); // list of relations that are not traversed
63         private List<Resource> nonTested = new ArrayList<>(); // list of relations that are not tested
64         
65         private List<Statement> changes1 = new ArrayList<>();
66         private List<Statement> changes2 = new ArrayList<>();
67         private List<Modification> modifications = new ArrayList<>();
68         private Set<Statement> changes1Set = new HashSet<>();
69         private Set<Statement> changes2Set = new HashSet<>();
70         private Set<Modification> modificationsSet = new HashSet<>();
71
72         private BijectionMap<Statement, Statement> comparableStatements = new BijectionMap<>();
73         private BijectionMap<Resource, Resource> comparableResources = new BijectionMap<>();
74         
75         private Set<Resource> processedResources = new HashSet<Resource>();
76         
77         private ResourceComparator comparator;
78         
79         private Comparator<Statement> scomp = new PredicateComparator();
80         private Comparator<Resource> rcomp = new ResComparator();
81         
82         private Set<Resource> nonMatchedLeft = new HashSet<Resource>();
83         private Set<Resource> nonMatchedRight = new HashSet<Resource>();
84         
85         // runtime attributes
86         
87         private ReadGraph g;
88         private Layer0 b;
89         
90         public GraphComparator(Resource r1, Resource r2) {
91                 this.r1 = r1;
92                 this.r2 = r2;
93                 comparator = new TypeComparator();
94         }
95         
96         public GraphComparator(Resource r1, Resource r2, ResourceComparator comparator) {
97                 this.r1 = r1;
98                 this.r2 = r2;
99                 this.comparator = comparator;
100         }
101         
102         ArrayList<Statement> ss1 = new ArrayList<Statement>();
103         ArrayList<Statement> ss2 = new ArrayList<Statement>();
104         
105         
106         public Comparator<Resource> getResourceComparator() {
107                 return rcomp;
108         }
109         
110         public Comparator<Statement> getStatementComparator() {
111                 return scomp;
112         }
113         
114         public Resource getR1() {
115                 return r1;
116         }
117         
118         public Resource getR2() {
119                 return r2;
120         }
121         
122         public void addTraversed(Resource rel) {
123                 traversed.add(rel);
124         }
125         
126         public void addTraversed(Collection<Resource> rels) {
127                 traversed.addAll(rels);
128         }
129         
130         public void addNonTraversed(Resource rel) {
131                 nonTraversed.add(rel);
132         }
133         
134         public void addNonTraversed(Collection<Resource> rels) {
135                 nonTraversed.addAll(rels);
136         }
137         
138         public void addTested(Resource rel) {
139                 tested.add(rel);
140         }
141         
142         public void addTested(Collection<Resource> rels) {
143                 tested.addAll(rels);
144         }
145         
146         public void addNonTested(Resource rel) {
147                 nonTested.add(rel);
148         }
149         
150         public void addNonTested(Collection<Resource> rels) {
151                 nonTested.addAll(rels);
152         }
153         
154         public void addComparableResources(Resource r1, Resource r2) {
155                 if (DEBUG)
156                         System.out.println("Preset " + r1 + " = " + r2);
157                 comparableResources.map(r1, r2);
158         }
159         
160         public void addComparableResources(BijectionMap<Resource, Resource> matching) {
161                 if (DEBUG) {
162                         for (Entry<Resource, Resource> entry : matching.getEntries())
163                                 System.out.println("Preset " + entry.getKey() + " = " + entry.getValue());
164                 }
165                 comparableResources.addAll(matching);
166         }
167         
168         public void addStrong(Resource r) {
169                 strong.add(r);
170         }
171         
172         public void addStrong(Collection<Resource> rels) {
173                 strong.addAll(rels);
174         }
175         
176         public void addNonMatchedLeft(Resource r) {
177                 nonMatchedLeft.add(r);
178         }
179         
180         public void addNonMatchedRight(Resource r) {
181                 nonMatchedRight.add(r);
182         }
183         
184         public void test(ReadGraph g) throws DatabaseException {
185                 this.g = g;
186                 this.b = Layer0.getInstance(g);
187                 comparator.setComparator(this);
188                 comparator.initialize(g, r1, r2);
189                 
190                 Stack<Resource> objectsLeft = new Stack<Resource>();
191                 Stack<Resource> objectsRight = new Stack<Resource>();
192                 objectsLeft.push(r1);
193                 objectsRight.push(r2);
194                 
195                 Set<Statement> unreliableLeft = new HashSet<Statement>();
196                 Set<Statement> unreliableRight = new HashSet<Statement>();
197                 
198                 while (true) {
199                         if (objectsLeft.isEmpty())
200                                 break;
201                         
202                         
203                         // process compares objects that are identified and searches for more resources to process. 
204                         process(objectsLeft, objectsRight, unreliableLeft, unreliableRight);
205                         // process unreliable handles cases where unidentified statements subject and object have been identified 
206                         processUnreliable(unreliableLeft, unreliableRight);
207                         // process unreliable handles cases where unidentified resources have path of length one to identified resource
208                         processUnreliable(unreliableLeft, unreliableRight,objectsLeft,objectsRight);
209                         if (objectsLeft.isEmpty() && unreliableLeft.size() > 0 && unreliableRight.size() > 0) {
210                                 processUnreliable2(unreliableLeft, unreliableRight,objectsLeft,objectsRight);
211                         }
212                         if (objectsLeft.isEmpty() && unreliableLeft.size() > 0 && unreliableRight.size() > 0) {
213                                 // comparison is ending, but we have still unprocessed unidentified resources left.
214                                 // These cases have longer path than one to identified objects.
215                                 processUnreliableDeep(unreliableLeft, unreliableRight, objectsLeft, objectsRight);
216                         }
217                         
218                 }
219                 for (Statement s : unreliableLeft) {
220                         if (!comparableStatements.containsLeft(s))
221                                 addDeletion(s);
222                 }
223                 for (Statement s : unreliableRight) {
224                         if (!comparableStatements.containsRight(s))
225                                 addAddition(s);
226                 }
227         }
228         
229         public void test(Session session) throws DatabaseException {
230                 test(session, r1, r2);
231         }
232         
233         public void test(Session session, Resource r1, Resource r2) throws DatabaseException {
234                 
235                 comparator.setComparator(this);
236                 
237                 session.syncRequest(new ReadRequest() {
238             
239             @Override
240             public void run(ReadGraph graph) throws DatabaseException {
241                 comparator.initialize(graph, r1, r2);
242             }
243         });
244                 
245                 addComparable(r1, r2);
246                 
247                 final Stack<Resource> objectsLeft = new Stack<Resource>();
248                 final Stack<Resource> objectsRight = new Stack<Resource>();
249                 objectsLeft.push(r1);
250                 objectsRight.push(r2);
251                 
252                 final Set<Statement> unreliableLeft = new HashSet<Statement>();
253                 final Set<Statement> unreliableRight = new HashSet<Statement>();
254                 
255                 while (true) {
256                         if (objectsLeft.isEmpty())
257                                 break;
258                         session.syncRequest(new ReadRequest() {
259                                 
260                                 @Override
261                                 public void run(ReadGraph graph) throws DatabaseException {
262                                         g = graph;
263                                         b = Layer0.getInstance(graph);
264                                         // process compares objects that are identified and searches for more resources to process. 
265                                         process(objectsLeft, objectsRight, unreliableLeft, unreliableRight);
266                                         // process unreliable handles cases where unidentified statements subject and object have been identified 
267                                         processUnreliable(unreliableLeft, unreliableRight);
268                                         // process unreliable handles cases where unidentified resources have path of length one to identified resource
269                                         processUnreliable(unreliableLeft, unreliableRight,objectsLeft,objectsRight);
270                                         if (objectsLeft.isEmpty() && unreliableLeft.size() > 0 && unreliableRight.size() > 0) {
271                                                 processUnreliable2(unreliableLeft, unreliableRight,objectsLeft,objectsRight);
272                                         }
273                                         if (objectsLeft.isEmpty() && unreliableLeft.size() > 0 && unreliableRight.size() > 0) {
274                                                 // comparison is ending, but we have still unprocessed unidentified resources left.
275                                                 // These cases have longer path than one to identified objects.
276                                                 processUnreliableDeep(unreliableLeft, unreliableRight, objectsLeft, objectsRight);
277                                         }
278                                         if (objectsLeft.isEmpty() && unreliableLeft.size() > 0 && unreliableRight.size() > 0) {
279                                                 // comparison is ending, but we have still unprocessed unidentified resources left.
280                                                 // These cases have longer path than one to identified objects.
281                                                 processUnreliableDeep(unreliableLeft, unreliableRight, objectsLeft, objectsRight);
282                                         }
283                                 }
284                         });
285                         
286                         
287                         
288                 }
289                 for (Statement s : unreliableLeft) {
290                         if (!comparableStatements.containsLeft(s))
291                                 addDeletion(s);
292                 }
293                 for (Statement s : unreliableRight) {
294                         if (!comparableStatements.containsRight(s))
295                                 addAddition(s);
296                 }
297                 
298                 
299         }
300         
301         private void process(Stack<Resource> objectsLeft, Stack<Resource> objectsRight, Set<Statement> unreliableLeft, Set<Statement> unreliableRight) throws DatabaseException {
302                 List<Statement> ss1 = new ArrayList<Statement>();
303                 List<Statement> ss2 = new ArrayList<Statement>();
304                 
305                 while (!objectsLeft.isEmpty()) {
306                         Resource r1 = objectsLeft.pop();
307                         Resource r2 = objectsRight.pop();
308                         
309                         if (r1.equals(r2))
310                                 continue;
311                         if (processedResources.contains(r1))
312                                 continue;
313                         processedResources.add(r1);
314                         
315                 
316                         if((comparableResources.containsLeft(r1)||comparableResources.containsRight(r2)) && !comparableResources.contains(r1, r2)) {
317                                 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.");
318                         }
319                         addComparable(r1, r2);
320                         
321                         //System.out.println("test " + NameUtils.getSafeName(g, r1) + " " + NameUtils.getSafeName(g, r2));
322                         compareProps(r1, r2);
323                         
324                         for (Resource rel : tested) {
325                                 ss1.addAll(g.getStatements(r1, rel));
326                                 ss2.addAll(g.getStatements(r2, rel));
327                                 ss1 = filterAsserted(r1, ss1);
328                                 ss2 = filterAsserted(r2, ss2);
329                                 ss1 = filterTraversed(ss1);
330                                 ss2 = filterTraversed(ss2);
331                                 ss1 = filterNonTested(ss1);
332                                 ss2 = filterNonTested(ss2);
333                                 
334                                 
335                                 compareStatements(ss1, ss2, null, null,null,null);
336                                 ss1.clear();
337                                 ss2.clear();
338                         }
339                         
340                         for (Resource rel : traversed) {
341                                 ss1.addAll(g.getStatements(r1, rel));
342                                 ss2.addAll(g.getStatements(r2, rel));
343                                 ss1 = filterAsserted(r1, ss1);
344                                 ss2 = filterAsserted(r2, ss2);
345                                 ss1 = filterNonTraversed(ss1);
346                                 ss2 = filterNonTraversed(ss2);
347                                 compareStatements(ss1, ss2, objectsLeft, objectsRight,unreliableLeft,unreliableRight);
348                                 ss1.clear();
349                                 ss2.clear();
350                                 
351                         }
352                 }
353         }
354         
355         private void processUnreliable(Set<Statement> unreliableLeft, Set<Statement> unreliableRight) throws DatabaseException {
356                 MapList<Resource,Statement> subjectLeft = new MapList<Resource, Statement>();
357                 MapList<Resource,Statement> subjectRight = new MapList<Resource, Statement>();
358                 MapList<Resource,Statement> objectLeft = new MapList<Resource, Statement>();
359                 MapList<Resource,Statement> objectRight = new MapList<Resource, Statement>();
360                 
361                 for (Statement s : unreliableLeft) {
362                         subjectLeft.add(s.getSubject(),s);
363                         objectLeft.add(s.getObject(),s);
364                 }
365                 for (Statement s : unreliableRight) {
366                         subjectRight.add(s.getSubject(),s);
367                         objectRight.add(s.getObject(),s);
368                 }
369                 
370                 for (Resource left : subjectLeft.getKeys()) {
371                         Resource right = comparableResources.getRight(left);
372                         if (right == null)
373                                 continue;
374                         for (Statement leftS : subjectLeft.getValues(left)) {
375                                 Resource leftO = leftS.getObject();
376                                 if (!unreliableLeft.contains(leftS))
377                                         continue;
378                                 Resource rightO = comparableResources.getRight(leftO);
379                                 if (rightO == null)
380                                         continue;
381                                 for (Statement rightS : subjectRight.getValues(right)) {
382                                         if (!rightS.getObject().equals(rightO))
383                                                 continue;
384                                         if (!unreliableRight.contains(rightS))
385                                                 continue;
386                                         if (leftS.getPredicate().equals(rightS.getPredicate()) ||
387                                                 comparableResources.contains(leftS.getPredicate(), rightS.getPredicate())) {
388                                                 unreliableLeft.remove(leftS);
389                                                 unreliableRight.remove(rightS);
390                                                 addComparable(leftS, rightS);
391                                         }
392                                 }
393                         }               
394                 }
395         }
396         
397         private void processUnreliable(Set<Statement> unreliableLeft, Set<Statement> unreliableRight, Stack<Resource> objectsLeft, Stack<Resource> objectsRight) throws DatabaseException {
398                 MapList<Resource,Statement> subjectLeft = new MapList<Resource, Statement>();
399                 MapList<Resource,Statement> subjectRight = new MapList<Resource, Statement>();
400                 MapList<Resource,Statement> objectLeft = new MapList<Resource, Statement>();
401                 MapList<Resource,Statement> objectRight = new MapList<Resource, Statement>();
402                 
403                 for (Statement s : unreliableLeft) {
404                         subjectLeft.add(s.getSubject(),s);
405                         objectLeft.add(s.getObject(),s);
406                 }
407                 for (Statement s : unreliableRight) {
408                         subjectRight.add(s.getSubject(),s);
409                         objectRight.add(s.getObject(),s);
410                 }
411                 
412                 for (Resource ol : objectLeft.getKeys()) {
413                         // all statements to the left side object
414                         List<Statement> left = objectLeft.getValues(ol);
415                         // all subjects that have statements to the left side object (ol)
416                         Set<Resource> sLeft = new HashSet<Resource>();
417                         // all matching subjects on the right side
418                         Set<Resource> sRight = new HashSet<Resource>();
419                         for (Statement s : left) {
420                                 sLeft.add(s.getSubject());
421                                 sRight.add(comparableResources.getRight(s.getSubject()));
422                         }
423                         
424                         // check if object left can be reliably identified by available statements
425                         // if there are any objects on the left side with similar statements, object left cannot be mapped.
426                         boolean hasSimilar = false;
427                         MapList<Resource, Statement> comparableOLeft = new MapList<Resource, Statement>();
428                         for (Resource sl : sLeft) {
429                                 for (Statement s : subjectLeft.getValues(sl)) {
430                                         if (!s.getObject().equals(ol)) {
431                                                 comparableOLeft.add(s.getObject(),s);
432                                         }
433                                 }
434                         }
435                         
436                         compareStatements(ss1, ss2, objectsLeft, objectsRight,unreliableLeft,unreliableRight);
437                         
438                         for (Resource similarOl : comparableOLeft.getKeys()) {
439                                 List<Statement> similarLeft = comparableOLeft.getValues(similarOl);
440                                 if (similarLeft.size() == left.size()) {
441                                         boolean useL[] = new boolean[left.size()];
442                                         boolean useSL[] = new boolean[left.size()];
443                                         for (int i = 0; i < left.size(); i++) {
444                                                 useL[i] = false;
445                                                 useSL[i] = false;
446                                         }
447                                         for (int i = 0; i < left.size(); i++) {
448                                                 for (int j = 0; j < left.size(); j++) {
449                                                         if (useSL[j])
450                                                                 continue;
451                                                         // compare predicates
452                                                         Resource pl = left.get(i).getPredicate();
453                                                         Resource psl = similarLeft.get(j).getPredicate();
454                                                         if (pl.equals(psl)) {
455                                                                 // compare objects (unreliable result is interpreted as positive match)
456
457                                                                 int comp = comparator.compare(g, left.get(i).getObject(), similarLeft.get(j).getObject(), true);
458                                                                 if (comp >= 0 && comp < ResourceComparator.NO_MATCH) {
459                                                                         useL[i] = true;
460                                                                         useSL[j] = true;
461                                                                         break;
462                                                                 }
463                                                         }
464                                                 }
465                                         }
466                                         boolean diff = false;
467                                         for (int i = 0; i < left.size(); i++) {
468                                                 if (!useL[i] || !useSL[i]) {
469                                                         diff = true;
470                                                 }
471                                         }
472                                         if (!diff) {
473                                                 hasSimilar = true;
474                                                 break;
475                                         }
476                                 }
477                         }
478                         
479                         if (hasSimilar)
480                                 continue;
481                                 
482                         
483                         // all objects that subjects on the right side point to. Object left has its matching resource among these, if it has matching resource
484                         MapList<Resource,Statement> possibleOR = new MapList<Resource, Statement>();
485                         for (Resource sr : sRight) {
486                                 for (Statement s : subjectRight.getValues(sr))
487                                         possibleOR.add(s.getObject(),s);
488                         }
489                         
490                         // filter possible right side objects to those that have same amount of statements as the left side object
491                         for (Resource or : possibleOR.getKeys().toArray(new Resource[possibleOR.getKeys().size()])) {
492                                 List<Statement> right = possibleOR.getValues(or);
493                                 if (right.size() != left.size())
494                                         possibleOR.remove(or);
495                                         
496                         }
497                         
498                         // check for matching statements (comparable subjects, matching predicates)
499                         MapList<Resource,Statement> matchingOR = new MapList<Resource, Statement>(); // list of objects that have matching statements
500                         Map<Resource,Pair<int[], int[]>> matchingStatements = new HashMap<Resource, Pair<int[], int[]>>(); // matching statements
501                         for (Resource or : possibleOR.getKeys()) {
502                                 List<Statement> right = possibleOR.getValues(or);
503                                 int iLeft[] = new int[left.size()];
504                                 int iRight[] = new int[right.size()];
505                                 
506                                 for (int i = 0; i < left.size(); i++) {
507                                         iLeft[i] = -1;
508                                         iRight[i] = -1;
509                                 }
510                                 
511                                 for (int l = 0; l < left.size(); l++) {
512                                         Statement ls = left.get(l);
513                                         for (int r = 0; r < right.size(); r++) {
514                                                 if (iRight[r] >= 0)
515                                                         continue;
516                                                 Statement rs = right.get(r);
517                                                 if (!comparableResources.contains(ls.getSubject(), rs.getSubject()))
518                                                         continue;
519                                                 if ((comparableResources.containsLeft(ls.getObject()) || comparableResources.containsRight(rs.getObject())) && !comparableResources.contains(ls.getObject(), rs.getObject()))
520                                                         continue;
521                                                 if (rcomp.compare(ls.getPredicate(),rs.getPredicate()) == 0) {
522                                                         // compare objects (unreliable result is not accepted)
523                                                         int comp = comparator.compare(g, ls.getObject(), rs.getObject());
524                                                         if (comp > 0 && comp < Integer.MAX_VALUE) {
525                                                                 iLeft[l] = r;
526                                                                 iRight[r] = l;
527                                                                 break;
528                                                         }
529                                                         break;
530                                                 }
531                                         }
532                                         
533                                 }
534                                 boolean success = true;
535                                 for (int i = 0; i < left.size(); i++) {
536                                         if (iLeft[i] < 0) {
537                                                 success = false;
538                                                 break;
539                                         }
540                                         if (iRight[i] < 0) {
541                                                 success = false;
542                                                 break;
543                                         }
544                                                 
545                                 }
546                                 if (success) {
547                                         for (Statement s : right) 
548                                                 matchingOR.add(or,s);
549                                         matchingStatements.put(or, new Pair<int[], int[]>(iLeft, iRight));
550                                 }
551                         }
552                         // if there is only one matching right side object, we have found a match 
553                         if (matchingOR.getKeySize() == 1) {
554                                 Resource or = matchingOR.getKeys().iterator().next();
555                                 List<Statement> right = matchingOR.getValues(or);
556                                 Pair<int[], int[]> indices = matchingStatements.get(or);
557                                 
558                                 objectsLeft.add(ol);
559                                 objectsRight.add(or);
560                                 addComparable(ol, or);
561                                 for (int l = 0; l < left.size(); l++) {
562                                         int r = indices.first[l];
563                                         Statement sl = left.get(l);
564                                         Statement sr = right.get(r);
565                                         addComparable(sl, sr);
566                                         unreliableLeft.remove(sl);
567                                         unreliableRight.remove(sr);
568                                 }
569                                 
570                         } else {
571                                 
572                         }
573
574                 }
575                 
576                 
577         }
578         
579         private void processUnreliable2(Set<Statement> unreliableLeft, Set<Statement> unreliableRight, Stack<Resource> objectsLeft, Stack<Resource> objectsRight) throws DatabaseException {
580                 MapList<Resource,Statement> subjectLeft = new MapList<Resource, Statement>();
581                 MapList<Resource,Statement> subjectRight = new MapList<Resource, Statement>();
582                 MapList<Resource,Statement> objectLeft = new MapList<Resource, Statement>();
583                 MapList<Resource,Statement> objectRight = new MapList<Resource, Statement>();
584                 
585                 for (Statement s : unreliableLeft) {
586                         subjectLeft.add(s.getSubject(),s);
587                         objectLeft.add(s.getObject(),s);
588                 }
589                 for (Statement s : unreliableRight) {
590                         subjectRight.add(s.getSubject(),s);
591                         objectRight.add(s.getObject(),s);
592                 }
593                 
594                 for (Resource ol : objectLeft.getKeys()) {
595                         // all statements to the left side object
596                         List<Statement> left = objectLeft.getValues(ol);
597                         // all subjects that have statements to the left side object (ol)
598                         Set<Resource> sLeft = new HashSet<Resource>();
599                         // all matching subjects on the right side
600                         Set<Resource> sRight = new HashSet<Resource>();
601                         for (Statement s : left) {
602                                 sLeft.add(s.getSubject());
603                                 sRight.add(comparableResources.getRight(s.getSubject()));
604                         }
605                         
606                         if (sLeft.size() == 1 && sRight.size() == 1) {
607                                 List<Statement> ss1 = new ArrayList<Statement>(subjectLeft.getValues(sLeft.iterator().next()));
608                                 List<Statement> ss2 = new ArrayList<Statement>(subjectRight.getValues(sRight.iterator().next()));
609                                 
610                                 int count = comparableStatements.size();
611                                 compareStatements(ss1, ss2, objectsLeft, objectsRight,unreliableLeft,unreliableRight);
612                                 if (comparableStatements.size() > count) {
613                                         for (Entry<Statement, Statement> entry : comparableStatements.getEntries()) {
614                                                 unreliableLeft.remove(entry.getKey());
615                                                 unreliableRight.remove(entry.getValue());
616                                         }
617                                 }
618                         }
619                 }
620         }
621         
622         private void processUnreliableDeep(Set<Statement> unreliableLeft, Set<Statement> unreliableRight, Stack<Resource> objectsLeft, Stack<Resource> objectsRight) throws DatabaseException {
623                 MapList<Resource,Statement> subjectLeft = new MapList<Resource, Statement>();
624                 MapList<Resource,Statement> subjectRight = new MapList<Resource, Statement>();
625                 MapList<Resource,Statement> objectLeft = new MapList<Resource, Statement>();
626                 MapList<Resource,Statement> objectRight = new MapList<Resource, Statement>();
627                 
628                 for (Statement s : unreliableLeft) {
629                         subjectLeft.add(s.getSubject(),s);
630                         objectLeft.add(s.getObject(),s);
631                 }
632                 for (Statement s : unreliableRight) {
633                         subjectRight.add(s.getSubject(),s);
634                         objectRight.add(s.getObject(),s);
635                 }
636                 for (Resource ol : objectLeft.getKeys()) {
637                         Set<Path> pathsLeft = new HashSet<Path>();
638                         for (Resource rel : traversed) {
639                                 pathsLeft.addAll(Path.create(g.getStatements(ol, rel)));
640                         }
641                         while (true) {
642                                 expand(pathsLeft);
643                                 if (pathsLeft.size() == 0)
644                                         break;
645                                 Collection<Path> endPaths = new ArrayList<Path>(1);
646                                 for (Path p : pathsLeft) {
647                                         if (comparableResources.containsLeft(p.getEnd())) {
648                                                 endPaths.add(p);
649                                         }
650                                 }
651                                 if (endPaths.size() > 0) {
652                                         pathsLeft.clear();
653                                         pathsLeft.addAll(endPaths);
654                                         break;
655                                 }       
656                         }
657                         if (pathsLeft.size() > 0) {
658                                 Resource sl = objectLeft.getValues(ol).get(0).getSubject();
659                                 Resource sr = comparableResources.getRight(sl);
660                                 Collection<Resource> possibleOR = new ArrayList<Resource>();
661                                 for (Statement s : subjectRight.getValues(sr)) {
662                                         possibleOR.add(s.getObject());
663                                 }
664                                 Map<Resource,Set<Path>> matchingPaths = new HashMap<Resource, Set<Path>>();
665                                 for (Resource or : possibleOR) {
666                                         Set<Path> possiblePathsRight = new HashSet<Path>();
667                                         for (Path leftPath : pathsLeft) {
668                                                 possiblePathsRight.addAll(findComparableRight(leftPath, or));
669                                         }
670                                         if (hasMatchingPaths(pathsLeft, possiblePathsRight)) {
671                                                 matchingPaths.put(or, possiblePathsRight);
672                                         }
673                                 }
674                                 if (matchingPaths.size() > 0) {
675                                         if (matchingPaths.size() == 1) {
676                                                 Resource or = matchingPaths.keySet().iterator().next();
677                                                 
678                                                 objectsLeft.add(ol);
679                                                 objectsRight.add(or);
680                                                 addComparable(ol, or);
681                                                 Collection<Statement> statementsLeft = objectLeft.getValues(ol);
682                                                 Collection<Statement> statementsRight = objectRight.getValues(or);
683                                                 unreliableLeft.removeAll(statementsLeft);
684                                                 unreliableRight.removeAll(statementsRight);
685                                                 BijectionMap<Path,Path> map = getMatchingPaths(pathsLeft, matchingPaths.get(or));
686                                                 for (Path left : map.getLeftSet()) {
687                                                         Path right = map.getRight(left);
688                                                         for (int i = 0; i < left.getLength(); i++) {
689                                                                 addComparable(left.getStatements().get(i),right.getStatements().get(i));
690                                                         }
691                                                 }
692                                         } 
693                                 }
694                         }
695                         
696                 }
697                 
698         }
699         
700         private boolean hasMatchingPaths(Set<Path> leftPaths, Set<Path> rightPaths) throws DatabaseException {
701                 if (leftPaths.size() != rightPaths.size())
702                         return false;
703                 BijectionMap<Path,Path> map = getMatchingPaths(leftPaths, rightPaths);
704                 return map.size() == leftPaths.size();
705         }
706         
707         private BijectionMap<Path,Path> getMatchingPaths(Set<Path> leftPaths, Set<Path> rightPaths) throws DatabaseException {
708                 BijectionMap<Path,Path> map = new BijectionMap<Path, Path>();
709                 for (Path leftPath : leftPaths) {
710                         for (Path rightPath : rightPaths) {
711                                 if (map.containsRight(rightPath))
712                                         continue;
713                                 if (leftPath.getLength() != rightPath.getLength())
714                                         continue;
715                                 if (comparableResources.contains(leftPath.getEnd(), rightPath.getEnd())) {
716                                         boolean match = true;
717                                         for (int i = 0; i < leftPath.getLength(); i++) {
718                                                 Statement sl = leftPath.getStatements().get(i);
719                                                 Statement sr = rightPath.getStatements().get(i);
720                                                 if (!sl.getPredicate().equals(sr.getPredicate()) && !comparableResources.contains(sl.getPredicate(), sr.getPredicate())) {
721                                                         match = false;
722                                                         break;
723                                                 }
724                                                 if ((getComparableResources().containsLeft(sl.getObject()) || getComparableResources().containsRight(sr.getObject())) && !getComparableResources().contains(sl.getObject(), sr.getObject())) {
725                                                         match = false;
726                                                         break;
727                                                 }
728                                                 if (comparator.compare(g, sl.getObject(), sr.getObject()) == ResourceComparator.NO_MATCH) {
729                                                         match = false;
730                                                         break;
731                                                 }
732                                         }
733                                         if (match) {
734                                                 map.map(leftPath, rightPath);
735                                                 break;
736                                         }
737                                 }
738                         }
739                 }
740                 return map;
741         }
742         
743         private void expand(Set<Path> paths) throws DatabaseException {
744                 Set<Path> stepPathsLeft = new HashSet<Path>();
745                 if (paths.size() == 0)
746                         return;
747                 int length = paths.iterator().next().getLength() + 1;
748                 for (Path p : paths) {
749                         for (Resource rel : traversed) {
750                                 stepPathsLeft.addAll(Path.expand(p,g.getStatements(p.getEnd(), rel)));
751                         }
752                 }
753                 paths.clear();
754                 for (Path p : stepPathsLeft) {
755                         if (p.getLength() == length)
756                                 paths.add(p);
757                 }
758         }
759         
760         private Collection<Path> findComparableRight(Path leftPath, Resource beginRight) throws DatabaseException {
761                 Set<Path> rightPaths = new HashSet<Path>();
762                 rightPaths.addAll(Path.create(g.getStatements(beginRight, getRight(leftPath.getStatements().get(0).getPredicate()))));
763                 for (int i = 1; i < leftPath.getLength(); i++) {
764                         if (rightPaths.size() == 0)
765                                 return rightPaths;
766                         Set<Path> stepPaths = new HashSet<Path>();
767                         for (Path p : rightPaths) {
768                                 stepPaths.addAll(Path.expand(p, g.getStatements(p.getEnd(), getRight(leftPath.getStatements().get(i).getPredicate()))));
769                         }
770                         rightPaths.clear();
771                         for (Path p : stepPaths)
772                                 if (p.getLength() == i+1) 
773                                         rightPaths.add(p);
774                 }
775                 return rightPaths;
776                 
777         }
778         
779         private Resource getRight(Resource r) {
780                 if (comparableResources.containsLeft(r))
781                         return comparableResources.getRight(r);
782                 return r;
783         }
784         
785
786         
787         public BijectionMap<Statement, Statement> getComparableStatements() {
788                 return comparableStatements;
789         }
790         
791         public BijectionMap<Resource, Resource> getComparableResources() {
792                 return comparableResources;
793         }
794         
795         public GraphChanges getChanges() {
796                 return new GraphChanges(r1,r2,changes1,changes2,modifications,comparableResources);
797         }
798         
799         public List<Statement> getChanges1() {
800                 return changes1;
801         }
802         
803         public List<Statement> getChanges2() {
804                 return changes2;
805         }
806         
807         private void addComparable(Statement left, Statement right) throws DatabaseException {
808                 addComparable(left.getObject(), right.getObject());
809                 comparableStatements.map(left, right);
810                 //comparableResources.map(left.getObject(), right.getObject());
811         }
812         
813         private void addComparable(Resource left, Resource right) throws DatabaseException {
814                 if(!comparableResources.contains(left, right)) {
815                         if (comparableResources.containsLeft(left)||comparableResources.containsRight(right)) {
816                                 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.");
817                         } else {
818                                 if (DEBUG) System.out.println(left + " = " + right);
819                                 comparableResources.map(left, right);
820                         }
821                 }
822                 
823         }
824         
825         public List<Statement> filterAsserted(Resource r, Collection<Statement> in) throws DatabaseException {
826                 List<Statement> out = new ArrayList<Statement>();
827                 for (Statement s : in) {
828                         if (!s.isAsserted(r))
829                                 out.add(s);
830                         
831                 }
832                 return out;
833         }
834         
835         public List<Statement> filterAssertedDuplicates(Resource r, List<Statement> in) throws DatabaseException {
836                 List<Statement> out = new ArrayList<Statement>();
837                 for (int i = 0; i < in.size(); i++) {
838                         Statement s = in.get(i);
839                         if (!s.isAsserted(r))
840                                 out.add(s);
841                         else {
842                                 boolean has = false;
843                                 if (i > 0 && in.get(i-1).getPredicate().equals(s.getPredicate()))
844                                         has = true;
845                                 else if (i < in.size()-1 && in.get(i+1).getPredicate().equals(s.getPredicate()))
846                                         has = true;
847                                 if (!has)
848                                         out.add(s);
849                         }
850                         
851                 }
852                 return out;
853         }
854         
855         
856
857         private String printStatement(ReadGraph graph, Statement s) throws DatabaseException {
858                 return NameUtils.getSafeName(graph, s.getSubject()) + " " + NameUtils.getSafeName(graph, s.getPredicate()) + " " + NameUtils.getSafeName(graph, s.getObject());
859         }
860         
861         private List<Statement> filterTraversed(List<Statement> in) throws DatabaseException {
862                 return filter(traversed, in);
863         }
864         
865         private List<Statement> filterNonTested(List<Statement> in) throws DatabaseException {
866                 return filter(nonTested, in);
867         }
868         
869         private List<Statement> filterNonTraversed(List<Statement> in) throws DatabaseException {
870                 return filter(nonTraversed, in);
871         }
872         
873         private List<Statement> filter(Collection<Resource> toFilter, List<Statement> in) throws DatabaseException {
874                 if (toFilter.size() == 0)
875                         return in;
876                 List<Statement> out = new ArrayList<Statement>();
877                 for (Statement s : in) {
878                         boolean usable = true;
879                         for (Resource r : toFilter) {
880                                 if (g.isSubrelationOf(s.getPredicate(),r)) {
881                                         usable = false;
882                                         break;
883                                 }
884                         }
885                         if (usable) {
886                                 out.add(s);
887                         }
888                         
889                 }
890                 return out;
891         }
892         
893         
894         private void addDeletion(Statement s) {
895                 if (!changes1Set.contains(s)) {
896                         changes1Set.add(s);
897                         changes1.add(s);
898                 }
899         }
900         
901         private void addAddition(Statement s) {
902                 if (!changes2Set.contains(s)) {
903                         changes2Set.add(s);
904                         changes2.add(s);
905                 }
906         }
907         
908         private void addModification(Resource left, Statement leftstm, Resource right, Statement rightstm) {
909                 Modification mod = new Modification(left, right, leftstm, rightstm);
910                 if (!modificationsSet.contains(mod)) {
911                         modificationsSet.add(mod);
912                         modifications.add(mod);
913                 }
914         }
915         
916         public void sortStatement(List<Statement> list1, List<Statement> list2) {
917                 sortStatement(list1, list2, scomp);
918         }
919         
920         public void sortStatement(List<Statement> list1, List<Statement> list2, Comparator<Statement> scomp) {
921                 Collections.sort(list1,scomp);
922                 Collections.sort(list2,scomp);
923                 
924                 List<Statement> sorted1 = new ArrayList<Statement>(list1.size());
925                 List<Statement> sorted2 = new ArrayList<Statement>(list2.size());
926                 sorted1.addAll(list1);
927                 sorted2.addAll(list2);
928                 
929                 int ss1 = 0;
930                 int ss2 = 0;
931                 for (int i = 0; i < list1.size(); ) {
932                         Statement s1 = list1.get(i);
933                         int same1 = sameRel(list1, i);  
934                         for (int j = 0; j < list2.size(); j++) {
935                                 Statement s2 = list2.get(j);
936                                 if (scomp.compare(s1, s2) == 0) {
937                                         int same2 = sameRel(list2, j);
938                                         copy(sorted1,ss1,list1,i,same1);
939                                         ss1 += same1;
940                                         copy(sorted2,ss2,list2,j,same2);
941                                         ss2 += same2;
942                                         break;
943                                 }
944                         }
945                         i+= same1;
946                 }
947                 if (ss1 < sorted1.size()) {
948                         for (Statement s : list1) {
949                                 if (!sorted1.contains(s)) {
950                                         sorted1.set(ss1,s);
951                                         ss1++;
952                                 }
953                         }
954                 }
955                 if (ss2 < sorted2.size()) {
956                         for (Statement s : list2) {
957                                 if (!sorted2.contains(s)) {
958                                         sorted2.set(ss2,s);
959                                         ss2++;
960                                 }
961                         }
962                 }
963                 
964                 list1.clear();
965                 list2.clear();
966                 list1.addAll(sorted1);
967                 list2.addAll(sorted2);
968         }
969         
970         public <T> void copy(List<T> to, int toIndex, List<T> from, int fromIndex, int amount) {
971                 for (int i = 0; i <  amount; i++) {
972                         to.set(toIndex + i, from.get(fromIndex+ i));
973                 }
974         }
975         
976         public void sortResource(List<Resource> list1, List<Resource> list2) {
977                 Collections.sort(list1,rcomp);
978                 int js = 0;
979                 for (int i = 0; i < list1.size(); i++) {
980                         Resource s1 = list1.get(i);
981                         for (int j = js; j < list2.size(); j++) {
982                                 Resource s2 = list2.get(j);
983                                 if (rcomp.compare(s1, s2) == 0) {
984                                         Resource t = list2.get(js);
985                                         list2.set(js, s2);
986                                         list2.set(j, t);
987                                         break;
988                                 }
989                         }
990                         js++;
991                 }
992         }
993         
994         private void compareStatements(List<Statement> ss1, List<Statement> ss2, Stack<Resource> objectsLeft, Stack<Resource> objectsRight, Collection<Statement> unreliableLeft, Collection<Statement> unreliableRight) throws DatabaseException {
995                 sortStatement(ss1, ss2);
996                 
997                 int i1 = 0;
998                 int i2 = 0;
999                 
1000                 while (true) {
1001                         if (i1 >= ss1.size()) {
1002                                 if (i2 >= ss2.size()) {
1003                                         break;
1004                                 } else {
1005                                         while (i2 < ss2.size()) {
1006                                                 if (DEBUG) System.out.println("Compare Statements addition " + printStatement(g,ss2.get(i2)));
1007                                                 
1008                                                 addAddition(ss2.get(i2));
1009                                                 i2++;
1010                                         }
1011                                         break;
1012                                 }
1013                         } else if (i2 >= ss2.size()) {
1014                                 while (i1 < ss1.size()) {
1015                                         if (DEBUG) System.out.println("Compare Statements deletion " + printStatement(g,ss1.get(i1)));
1016                                         addDeletion(ss1.get(i1));
1017                                         i1++;
1018                                 }
1019                                 break;
1020                         }
1021                         int same1 = sameRel(ss1, i1);
1022                         int same2 = sameRel(ss2, i2);
1023                         int c = rcomp.compare(ss1.get(i1).getPredicate(),ss2.get(i2).getPredicate());
1024                         if (c == 0) {
1025                                 compareStatements(ss1, i1, same1, ss2, i2, same2,objectsLeft,objectsRight,unreliableLeft,unreliableRight);
1026                                 i1+=same1;
1027                                 i2+=same2;
1028                         } else if (c < 0) {
1029                                 for (int i = 0; i < same1; i++) {
1030                                         if (DEBUG) System.out.println("Compare Statements deletion " + printStatement(g,ss1.get(i+i1)));
1031                                         addDeletion(ss1.get(i+i1));
1032                                 }
1033                                 i1 += same1;
1034                         } else {
1035                                 for (int i = 0; i < same2; i++) {
1036                                         if (DEBUG) System.out.println("Compare Statements addition " + printStatement(g,ss2.get(i+i2)));
1037                                         addAddition(ss2.get(i+i2));
1038                                 }
1039                                 
1040                                 i2 += same2;
1041                         }
1042                 }
1043         }
1044         
1045
1046         
1047         private int sameRel(List<Statement> statements, int off) {
1048                 if (statements.size() <= off)
1049                         return 0;
1050                 int same = 1;
1051                 long id = statements.get(off).getPredicate().getResourceId();
1052                 for (int i = off+1; i <statements.size(); i++) {
1053                         if (statements.get(i).getPredicate().getResourceId() == id)
1054                                 same++;
1055                         else 
1056                                 break;
1057                 }
1058                 return same;
1059                 
1060         }
1061
1062         private int compareObject(Resource o1, Resource o2) throws DatabaseException {
1063                 if (o1.equals(o2))
1064                         return -1;
1065                 if (comparableResources.contains(o1, o2))
1066                         return (-1);
1067                 if (comparableResources.containsLeft(o1))
1068                         return Integer.MAX_VALUE;
1069                 if (comparableResources.containsRight(o2))
1070                         return Integer.MAX_VALUE;
1071                 if (nonMatchedLeft.contains(o1))
1072                         return Integer.MAX_VALUE;
1073                 if (nonMatchedRight.contains(o2))
1074                         return Integer.MAX_VALUE;
1075                 return comparator.compare(g, o1, o2);
1076         }
1077         
1078         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 {
1079                 boolean[] used1 = new boolean[len1];
1080                 for (int i = 0; i < used1.length; i++) {
1081                         used1[i] = false;
1082                 }
1083                 
1084                 boolean[] used2 = new boolean[len2];
1085                 for (int i = 0; i < used2.length; i++) {
1086                         used2[i] = false;
1087                 }
1088                                 
1089                 // left, right, difference
1090                 List<List<Integer>> differences = new ArrayList<List<Integer>>();
1091                 for (int i1 = off1; i1 < off1 + len1; i1++) {
1092                         Statement s1 = ss1.get(i1);
1093                         List<Integer> diff = new ArrayList<Integer>();
1094                         for (int i2 = off2; i2 < off2 + len2; i2++) {
1095                                 Statement s2 = ss2.get(i2);
1096                                 int d = compareObject(s1.getObject(), s2.getObject());
1097                                 if (d == 0) {
1098                                         for (Resource t : strong) {
1099                                                  if (s1.getPredicate().equals(t) || g.isSubrelationOf(s1.getPredicate(), t)) {
1100                                                          d = 1;
1101                                                          break;
1102                                                  }
1103                                         }
1104                                 }
1105                                 diff.add(d);
1106                         }
1107                         differences.add(diff);
1108                 }
1109                 // difference, left
1110                 MapList<Integer, Integer> priorities = new MapList<Integer, Integer>();
1111                 for (int i = 0; i < differences.size(); i++) {
1112                         List<Integer> list = differences.get(i);
1113                         for (int j = 0; j < list.size(); j++) {
1114                                 priorities.add(list.get(j), i);
1115                         }
1116                 }
1117                 
1118                 Integer[] pris = priorities.getKeys(new Integer[]{});
1119                 Arrays.sort(pris);
1120                 boolean matchFail = priorityMatching(ss1, off1, len1, ss2, off2, len2, pris, differences, priorities, used1, used2, objectsLeft, objectsRight, false);
1121                 if (matchFail) 
1122                         matchFail = priorityMatching(ss1, off1, len1, ss2, off2, len2, pris, differences, priorities, used1, used2, objectsLeft, objectsRight, objectsLeft == null);
1123                 
1124                 for (Integer pri : pris) {
1125                         if (pri != 0 && !matchFail && unreliableLeft == null)
1126                                 continue;
1127                         Set<Statement> s1s = new HashSet<Statement>();
1128                         Set<Statement> s2s = new HashSet<Statement>();
1129                         Set<Integer> s1i = new HashSet<Integer>();
1130                         Set<Integer> s2i = new HashSet<Integer>();
1131                         List<Integer> i1s = priorities.getValues(pri);
1132                         for (Integer i1 : i1s) {
1133                                 if (used1[i1])
1134                                         continue;
1135                                 List<Integer> i2diff = differences.get(i1);
1136                                 for (int i2 = 0; i2 < i2diff.size(); i2++) {
1137                                         if (i2diff.get(i2) == pri) {
1138                                                 if (used2[i2])
1139                                                         continue;
1140                                                 Statement s1  = ss1.get(i1+off1);
1141                                                 Statement s2  = ss2.get(i2+off2);
1142                                                 s1s.add(s1);
1143                                                 s2s.add(s2);
1144                                                 s1i.add(i1);
1145                                                 s2i.add(i2);
1146                                         }
1147                                 }
1148                         }
1149                         if (unreliableLeft != null) {
1150                                 unreliableLeft.addAll(s1s);
1151                                 unreliableRight.addAll(s2s);
1152                         }
1153                         for (Integer i : s1i)
1154                                 used1[i] = true;
1155                         for (Integer i : s2i)
1156                                 used2[i] = true;
1157
1158                 }
1159                 for (int i1 = off1; i1 < off1 + len1; i1++) {
1160                         if (!used1[i1-off1]) {
1161                                 if (DEBUG) System.out.println("Compare Object deletion " + printStatement(g,ss1.get(i1)));
1162                                 addDeletion(ss1.get(i1));
1163                         }
1164                 }
1165                 for (int i2 = off2; i2 < off2 + len2; i2++) {
1166                         if (!used2[i2-off2]) {
1167                                 if (DEBUG) System.out.println("Compare Object addition " + printStatement(g,ss2.get(i2)));
1168                                 addAddition(ss2.get(i2));
1169                         }
1170                 }
1171         }
1172         
1173         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 {
1174                 boolean matchFail = false;
1175                 for (Integer pri : pris) {
1176                         if (pri == Integer.MAX_VALUE) {
1177
1178                         } else if (pri == 0) {
1179                                 
1180                         } else {
1181                                 List<Integer> i1s = priorities.getValues(pri);
1182                                 
1183                                 for (Integer i1 : i1s) {
1184                                         if (used1[i1])
1185                                                 continue;
1186                                         List<Integer> i2diff = differences.get(i1);
1187                                         List<Integer> matches = new ArrayList<Integer>();
1188                                         for (int i2 = 0; i2 < i2diff.size(); i2++) {
1189                                                 if (i2diff.get(i2) == pri) { 
1190                                                         if (used2[i2])
1191                                                                 continue;
1192                                                         matches.add(i2);
1193                                                 }
1194                                         }
1195                                         if (matches.size() == 1 || (force && matches.size() > 1)) {
1196                                                 int i2 = matches.get(0);
1197                                                 used1[i1] = true;
1198                                                 used2[i2] = true;
1199                                                 Statement s1  = ss1.get(i1+off1);
1200                                                 Statement s2  = ss2.get(i2+off2);
1201                                                 
1202                                                 if (objectsLeft != null) {
1203                                                         objectsLeft.add(s1.getObject());
1204                                                         objectsRight.add(s2.getObject());
1205                                                 } 
1206                                                 addComparable(s1, s2);
1207                                         } else if (matches.size() > 1) {
1208                                                 matchFail = true;
1209                                         }
1210                                 }
1211                                 if (matchFail)
1212                                         break;
1213                         }
1214                 }
1215                 return matchFail;
1216         }
1217
1218         
1219         /**
1220          * compares properties, assumes functional relations
1221          * @param r1
1222          * @param r2
1223          * @throws ServiceException
1224          * @throws DoesNotContainValueException
1225          * @throws ValidationException 
1226          */
1227         private void compareProps(Resource r1, Resource r2) throws DatabaseException {
1228                 if (DEBUG) System.out.println("compareProps " + r1 + " " + NameUtils.getSafeName(g, r1) + " " + r2 + " " + NameUtils.getSafeName(g, r2));
1229                 List<Statement> ss1 = new ArrayList<Statement>();
1230                 List<Statement> ss2 = new ArrayList<Statement>();
1231                 ss1.addAll(g.getStatements(r1, b.HasProperty));
1232                 ss2.addAll(g.getStatements(r2, b.HasProperty));
1233                 ss1 = filterNonTested(ss1);
1234                 ss2 = filterNonTested(ss2);
1235                 sortStatement(ss1, ss2);
1236                 // getStatements(r1, b.HasProperty) returns both instance and asserted statements for the same property relation. 
1237                 ss1 = filterAssertedDuplicates(r1, ss1);
1238                 ss2 = filterAssertedDuplicates(r2, ss2);
1239                 
1240                 int i1 = 0; 
1241                 int i2 = 0;
1242                 
1243                 while (true) {
1244                         if (i1 >= ss1.size()) {
1245                                 if (i2 >= ss2.size())
1246                                         break;
1247                                 else {
1248                                         while (i2 < ss2.size()) {
1249                                                 Statement s = ss2.get(i2);
1250                                                 if (DEBUG) System.out.println("Compare Prop diff2 " + printStatement(g,s));
1251                                                 if (!s.isAsserted(r2))
1252                                                         addAddition(s);
1253                                                 i2++;
1254                                         }
1255                                         break;
1256                                 }
1257                         } else if (i2 >= ss2.size()) {
1258                                 while (i1 < ss1.size()) {
1259                                         Statement s = ss1.get(i1);
1260                                         if (DEBUG) System.out.println("Compare Prop diff1 " + printStatement(g,s));
1261                                         if (!s.isAsserted(r1))
1262                                                 addDeletion(s);
1263                                         i1++;
1264                                 }
1265                                 break;
1266                         }
1267                         Statement s1 = ss1.get(i1);
1268                         Statement s2 = ss2.get(i2);
1269                         if (s1.isAsserted(r1) && s2.isAsserted(r2)) {
1270                                 i1++;
1271                                 i2++;
1272                                 continue;
1273                         }
1274                         int c = scomp.compare(s1, s2);
1275                         switch (c) {
1276                                 case 0:{
1277                                         boolean b1 = g.hasValue(s1.getObject());
1278                                         boolean b2 = g.hasValue(s2.getObject());
1279                                         boolean a1 = s1.isAsserted(r1);
1280                                         boolean a2 = s2.isAsserted(r2);
1281                                         if (b1 == b2) {
1282                                                 if (b1) {
1283                                                         // Literals
1284                                                         boolean eq = compareValue(g,b,s1.getObject(), s2.getObject());
1285                                                         if (!eq) {
1286                                                                 addModification(r1,s1,r2,s2);
1287                                                                 if (!a1 && !a2)
1288                                                                         addComparable(s1, s2);
1289                                                         }
1290                                                 } else {
1291                                                         // Non literal properties.
1292                                                         int comp = comparator.compare(g, s1.getObject(), s2.getObject());
1293                                                         if (comp == ResourceComparator.NO_MATCH) {
1294                                                                 addModification(r1,s1,r2,s2);
1295                                                         } else if (comp != ResourceComparator.EXACT_MATCH) {
1296                                                                 if (!s1.getObject().equals(s1.getSubject()) && !s2.getObject().equals(s2.getSubject())) {
1297                                                                         if (!a1 && !a2) {
1298                                                                                 // compare props matches objects, so we can call that only for non asserted statements
1299                                                                                 compareProps(s1.getObject(), s2.getObject());
1300                                                                         } else if (a1 && a2) {
1301                                                                                 // TODO : compare asserted statements?
1302                                                                         } else {
1303                                                                                 addModification(r1,s1,r2,s2);
1304                                                                         }
1305                                                                 } else {
1306                                                                         addModification(r1,s1,r2,s2);
1307                                                                 }
1308                                                         } else {
1309                                                                 // Exact match, nothing to do.
1310                                                         }
1311                                                 }
1312                                         } else {
1313                                                 addModification(r1,s1,r2,s2);
1314                                         }
1315                                         i1++;
1316                                         i2++;
1317                                         break;
1318                                 }
1319                                 case -1:{
1320                                         if (DEBUG) System.out.println("Compare Prop diff1s " + printStatement(g,s1));
1321                                         // Use modification, since deletions do not support asserted statements
1322                                         addModification(r1,s1,r2,null);
1323                                         //addDeletion(s1);
1324                                         i1++;
1325                                         break;
1326                                 }
1327                                         
1328                                 case 1:{
1329                                         if (DEBUG) System.out.println("Compare Prop diff2s " + printStatement(g,s2));
1330                                         // Use modification, since additions do not support asserted statements
1331                                         addModification(r1,null,r2,s2);
1332                                         //addAddition(s2);
1333                                         i2++;
1334                                         break;
1335                                 }
1336                         }
1337
1338                 }
1339                 
1340                 ss1.clear();
1341                 ss2.clear();
1342                 
1343         }
1344         
1345         public static boolean compareValue(ReadGraph g, Layer0 b, Resource r1, Resource r2) throws DatabaseException {
1346                 Resource t1 = g.getSingleType(r1);
1347                 Resource t2 = g.getSingleType(r2);
1348                 if (!t1.equals(t2))
1349                         return false;
1350                 if (t1.equals(b.Integer)) {
1351                         int v1 = g.getValue(r1, Bindings.INTEGER);
1352                         int v2 = g.getValue(r2, Bindings.INTEGER);
1353                         return v1 == v2;
1354                 } else if (t1.equals(b.Float)) {
1355                         float v1 = g.getValue(r1, Bindings.FLOAT);
1356                         float v2 = g.getValue(r2, Bindings.FLOAT);
1357                         return v1 == v2;
1358                 } else if (t1.equals(b.Double)) {
1359                         double v1 = g.getValue(r1, Bindings.DOUBLE);
1360                         double v2 = g.getValue(r2, Bindings.DOUBLE);
1361                         return v1 == v2;
1362                 } else if (t1.equals(b.String)) {
1363                         String v1 = g.getValue(r1, Bindings.STRING);
1364                         String v2 = g.getValue(r2, Bindings.STRING);
1365                         return v1.equals(v2);
1366                 } else if (t1.equals(b.Boolean)) {
1367                         boolean v1 = g.getValue(r1, Bindings.BOOLEAN);
1368                         boolean v2 = g.getValue(r2, Bindings.BOOLEAN);
1369                         return v1 == v2;
1370                 } else if (t1.equals(b.Byte)) {
1371                         byte v1 = g.getValue(r1, Bindings.BYTE);
1372                         byte v2 = g.getValue(r2, Bindings.BYTE);
1373                         return v1 == v2;
1374                 } else if (t1.equals(b.Long)) {
1375                         long v1 = g.getValue(r1, Bindings.LONG);
1376                         long v2 = g.getValue(r2, Bindings.LONG);
1377                         return v1 == v2;
1378                 } else if (t1.equals(b.IntegerArray)) {
1379                         int[] v1 = g.getValue(r1, Bindings.INT_ARRAY);
1380                         int[] v2 = g.getValue(r2, Bindings.INT_ARRAY);
1381                         return Arrays.equals(v1,v2);
1382                 } else if (t1.equals(b.FloatArray)) {
1383                         float[] v1 = g.getValue(r1, Bindings.FLOAT_ARRAY);
1384                         float[] v2 = g.getValue(r2, Bindings.FLOAT_ARRAY);
1385                         return Arrays.equals(v1,v2);
1386                 } else if (t1.equals(b.DoubleArray)) {
1387                         double[] v1 = g.getValue(r1, Bindings.DOUBLE_ARRAY);
1388                         double[] v2 = g.getValue(r2, Bindings.DOUBLE_ARRAY);
1389                         return Arrays.equals(v1,v2);
1390                 } else if (t1.equals(b.StringArray)) {
1391                         String[] v1 = g.getValue(r1, Bindings.STRING_ARRAY);
1392                         String[] v2 = g.getValue(r2, Bindings.STRING_ARRAY);
1393                         return Arrays.equals(v1,v2);
1394                 } else if (t1.equals(b.BooleanArray)) {
1395                         boolean[] v1 = g.getValue(r1, Bindings.BOOLEAN_ARRAY);
1396                         boolean[] v2 = g.getValue(r2, Bindings.BOOLEAN_ARRAY);
1397                         return Arrays.equals(v1,v2);
1398                 } else if (t1.equals(b.ByteArray)) {
1399                         byte[] v1 = g.getValue(r1, Bindings.BYTE_ARRAY);
1400                         byte[] v2 = g.getValue(r2, Bindings.BYTE_ARRAY);
1401                         return Arrays.equals(v1,v2);
1402                 } else if (t1.equals(b.LongArray)) {
1403                         long[] v1 = g.getValue(r1, Bindings.LONG_ARRAY);
1404                         long[] v2 = g.getValue(r2, Bindings.LONG_ARRAY);
1405                         return Arrays.equals(v1,v2);
1406                 } else {
1407                         Object v1 = g.getValue(r1);
1408                         Object v2 = g.getValue(r2);
1409                         return compareValue(v1, v2);
1410                 }
1411                 
1412         }
1413         
1414         public static boolean compareValue(Object v1, Object v2) {
1415                 if (v1 instanceof Object[] && v2 instanceof Object[])
1416                         return Arrays.deepEquals((Object[])v1, (Object[])v2);
1417                 else if (v1 instanceof int[] && v2 instanceof int[]) 
1418                         return Arrays.equals((int[])v1, (int[])v2);
1419                 else if (v1 instanceof float[] && v2 instanceof float[]) 
1420                         return Arrays.equals((float[])v1, (float[])v2);
1421                 else if (v1 instanceof double[] && v2 instanceof double[]) 
1422                         return Arrays.equals((double[])v1, (double[])v2);
1423                 else if (v1 instanceof long[] && v2 instanceof long[]) 
1424                         return  Arrays.equals((long[])v1, (long[])v2);
1425                 else if (v1 instanceof byte[] && v2 instanceof byte[]) 
1426                         return Arrays.equals((byte[])v1, (byte[])v2);
1427                 else if (v1 instanceof boolean[] && v2 instanceof boolean[]) 
1428                         return Arrays.equals((boolean[])v1, (boolean[])v2);
1429                 else
1430                         return v1.equals(v2);
1431         }
1432
1433         
1434         public class PredicateComparator implements Comparator<Statement> {
1435                 @Override
1436                 public int compare(Statement o1, Statement o2) {
1437                         if (comparableResources.contains(o1.getPredicate(), o2.getPredicate()))
1438                                 return 0;
1439                         if (o1.getPredicate().getResourceId() < o2.getPredicate().getResourceId())
1440                                 return -1;
1441                         if (o1.getPredicate().getResourceId() > o2.getPredicate().getResourceId())
1442                                 return 1;
1443                         return 0;
1444                 }
1445         }
1446         
1447         public class SubjectComparator implements Comparator<Statement> {
1448                 @Override
1449                 public int compare(Statement o1, Statement o2) {
1450                         if (comparableResources.contains(o1.getSubject(), o2.getSubject()))
1451                                 return 0;
1452                         if (o1.getSubject().getResourceId() < o2.getSubject().getResourceId())
1453                                 return -1;
1454                         if (o1.getSubject().getResourceId() > o2.getSubject().getResourceId())
1455                                 return 1;
1456                         return 0;
1457                 }
1458         }
1459         
1460         public class ObjectComparator implements Comparator<Statement> {
1461                 @Override
1462                 public int compare(Statement o1, Statement o2) {
1463                         if (comparableResources.contains(o1.getObject(), o2.getObject()))
1464                                 return 0;
1465                         if (o1.getObject().getResourceId() < o2.getObject().getResourceId())
1466                                 return -1;
1467                         if (o1.getObject().getResourceId() > o2.getObject().getResourceId())
1468                                 return 1;
1469                         return 0;
1470                 }
1471         }
1472         
1473         public static class FullStatementComparator implements Comparator<Statement> {
1474                 @Override
1475                 public int compare(Statement o1, Statement o2) {
1476                         if (o1.getSubject().getResourceId() < o2.getSubject().getResourceId())
1477                                 return -1;
1478                         if (o1.getSubject().getResourceId() > o2.getSubject().getResourceId())
1479                                 return 1;
1480                         if (o1.getPredicate().getResourceId() < o2.getPredicate().getResourceId())
1481                                 return -1;
1482                         if (o1.getPredicate().getResourceId() > o2.getPredicate().getResourceId())
1483                                 return 1;
1484                         if (o1.getObject().getResourceId() < o2.getObject().getResourceId())
1485                                 return -1;
1486                         if (o1.getObject().getResourceId() > o2.getObject().getResourceId())
1487                                 return 1;
1488                         return 0;
1489                 }
1490         }
1491         
1492         public class ResComparator implements Comparator<Resource> {
1493                 @Override
1494                 public int compare(Resource o1, Resource o2) {
1495                         if (comparableResources.contains(o1, o2))
1496                                 return 0;
1497                         if (o1.getResourceId() < o2.getResourceId())
1498                                 return -1;
1499                         if (o1.getResourceId() > o2.getResourceId())
1500                                 return 1;
1501                         return 0;
1502                 }
1503         }
1504
1505 }