import java.util.Collection;\r
import java.util.Collections;\r
import java.util.Comparator;\r
+import java.util.HashMap;\r
import java.util.HashSet;\r
import java.util.List;\r
+import java.util.Map;\r
import java.util.Set;\r
import java.util.Stack;\r
\r
import org.simantics.db.ReadGraph;\r
import org.simantics.db.Resource;\r
+import org.simantics.db.Session;\r
import org.simantics.db.Statement;\r
+import org.simantics.db.common.request.ReadRequest;\r
import org.simantics.db.common.utils.NameUtils;\r
+import org.simantics.db.exception.DatabaseException;\r
import org.simantics.db.exception.DoesNotContainValueException;\r
import org.simantics.db.exception.ManyObjectsForFunctionalRelationException;\r
import org.simantics.db.exception.ServiceException;\r
*/\r
public class GraphComparator {\r
\r
- \r
+ private Resource r1;\r
+ private Resource r2;\r
+ private Set<Resource> strong = new HashSet<Resource>(); // List of relations that identify object, if subject is already identified. \r
private List<Resource> traversed = new ArrayList<Resource>(); // list of relations that are traversed (and tested)\r
private List<Resource> tested = new ArrayList<Resource>(); // list of relations that are tested, but not traversed\r
private List<Resource> nonTraversed = new ArrayList<Resource>(); // list of relations that are not traversed\r
\r
private BijectionMap<Statement, Statement> comparableStatements = new BijectionMap<Statement, Statement>();\r
private BijectionMap<Resource, Resource> comparableResources = new BijectionMap<Resource, Resource>();\r
+ private Set<Resource> processedResources = new HashSet<Resource>();\r
+ \r
+ private ResourceComparator comparator;\r
\r
+ private Comparator<Statement> scomp = new PredicateComparator();\r
+ private Comparator<Resource> rcomp = new ResComparator();\r
\r
// runtime attributes\r
\r
private ReadGraph g;\r
private Layer0 b;\r
\r
- ArrayList<Resource> rs1 = new ArrayList<Resource>();\r
- ArrayList<Resource> rs2 = new ArrayList<Resource>();\r
+ public GraphComparator(Resource r1, Resource r2) {\r
+ this.r1 = r1;\r
+ this.r2 = r2;\r
+ comparator = new TypeComparator();\r
+ }\r
+ \r
+ public GraphComparator(Resource r1, Resource r2, ResourceComparator comparator) {\r
+ this.r1 = r1;\r
+ this.r2 = r2;\r
+ this.comparator = comparator;\r
+ }\r
+ \r
ArrayList<Statement> ss1 = new ArrayList<Statement>();\r
ArrayList<Statement> ss2 = new ArrayList<Statement>();\r
- Comparator<Statement> scomp = new PredicateComparator();\r
- Comparator<Resource> rcomp = new ResourceComparator();\r
-\r
+ \r
+ \r
+ public Comparator<Resource> getResourceComparator() {\r
+ return rcomp;\r
+ }\r
+ \r
+ public Comparator<Statement> getStatementComparator() {\r
+ return scomp;\r
+ }\r
+ \r
+ public Resource getR1() {\r
+ return r1;\r
+ }\r
+ \r
+ public Resource getR2() {\r
+ return r2;\r
+ }\r
\r
public void addTraversed(Resource rel) {\r
traversed.add(rel);\r
nonTested.addAll(rels);\r
}\r
\r
- public void clearRels() {\r
- traversed.clear();\r
- tested.clear();\r
+ public void addComparableResources(Resource r1, Resource r2) {\r
+ comparableResources.map(r1, r2);\r
+ }\r
+ \r
+ public void addComparableResources(BijectionMap<Resource, Resource> matching) {\r
+ comparableResources.addAll(matching);\r
+ }\r
+ \r
+ public void addStrong(Resource r) {\r
+ strong.add(r);\r
}\r
\r
- public void test(ReadGraph g, Resource r1, Resource r2) throws ServiceException, DoesNotContainValueException, ValidationException {\r
+ public void addStrong(Collection<Resource> rels) {\r
+ strong.addAll(rels);\r
+ }\r
+ \r
+ \r
+ public void test(ReadGraph g) throws DatabaseException {\r
this.g = g;\r
this.b = Layer0.getInstance(g);\r
+ comparator.setComparator(this);\r
+ \r
+ Stack<Resource> objectsLeft = new Stack<Resource>();\r
+ Stack<Resource> objectsRight = new Stack<Resource>();\r
+ objectsLeft.push(r1);\r
+ objectsRight.push(r2);\r
+ \r
+ Set<Statement> unreliableLeft = new HashSet<Statement>();\r
+ Set<Statement> unreliableRight = new HashSet<Statement>();\r
+ \r
+ while (true) {\r
+ if (objectsLeft.isEmpty())\r
+ break;\r
+ \r
+ \r
+ // process compares objects that are identified and searches for more resources to process. \r
+ process(objectsLeft, objectsRight, unreliableLeft, unreliableRight);\r
+ // process unreliable handles cases where unidentified statements subject and object have been identified \r
+ processUnreliable(unreliableLeft, unreliableRight);\r
+ // process unreliable handles cases where unidentified resources have path of length one to identified resource\r
+ processUnreliable(unreliableLeft, unreliableRight,objectsLeft,objectsRight);\r
+ if (objectsLeft.isEmpty() && unreliableLeft.size() > 0 && unreliableRight.size() > 0) {\r
+ // comparison is ending, but we have still unprocessed unidentified resources left.\r
+ // These cases have longer path than one to identified objects.\r
+ processUnreliableDeep(unreliableLeft, unreliableRight, objectsLeft, objectsRight);\r
+ }\r
+ \r
+ }\r
+ for (Statement s : unreliableLeft) {\r
+ if (!comparableStatements.containsLeft(s))\r
+ addDeletion(s);\r
+ }\r
+ for (Statement s : unreliableRight) {\r
+ if (!comparableStatements.containsRight(s))\r
+ addAddition(s);\r
+ }\r
+ \r
+ \r
+ }\r
+ \r
+ public void test(Session session) throws DatabaseException {\r
+ \r
+ comparator.setComparator(this);\r
\r
- changes1Set.clear();\r
- changes2Set.clear();\r
- modificationsSet.clear();\r
- changes1.clear();\r
- changes2.clear();\r
- modifications.clear();\r
- comparableResources.clear();\r
+ comparableResources.map(r1, r2);\r
\r
- Stack<Resource> stack1 = new Stack<Resource>();\r
- Stack<Resource> stack2 = new Stack<Resource>();\r
- stack1.push(r1);\r
- stack2.push(r2);\r
+ final Stack<Resource> objectsLeft = new Stack<Resource>();\r
+ final Stack<Resource> objectsRight = new Stack<Resource>();\r
+ objectsLeft.push(r1);\r
+ objectsRight.push(r2);\r
\r
+ final Set<Statement> unreliableLeft = new HashSet<Statement>();\r
+ final Set<Statement> unreliableRight = new HashSet<Statement>();\r
\r
+ while (true) {\r
+ if (objectsLeft.isEmpty())\r
+ break;\r
+ session.syncRequest(new ReadRequest() {\r
+ \r
+ @Override\r
+ public void run(ReadGraph graph) throws DatabaseException {\r
+ g = graph;\r
+ b = Layer0.getInstance(graph);\r
+ // process compares objects that are identified and searches for more resources to process. \r
+ process(objectsLeft, objectsRight, unreliableLeft, unreliableRight);\r
+ // process unreliable handles cases where unidentified statements subject and object have been identified \r
+ processUnreliable(unreliableLeft, unreliableRight);\r
+ // process unreliable handles cases where unidentified resources have path of length one to identified resource\r
+ processUnreliable(unreliableLeft, unreliableRight,objectsLeft,objectsRight);\r
+ if (objectsLeft.isEmpty() && unreliableLeft.size() > 0 && unreliableRight.size() > 0) {\r
+ // comparison is ending, but we have still unprocessed unidentified resources left.\r
+ // These cases have longer path than one to identified objects.\r
+ processUnreliableDeep(unreliableLeft, unreliableRight, objectsLeft, objectsRight);\r
+ }\r
+ }\r
+ });\r
+ \r
+ \r
+ \r
+ }\r
+ for (Statement s : unreliableLeft) {\r
+ if (!comparableStatements.containsLeft(s))\r
+ addDeletion(s);\r
+ }\r
+ for (Statement s : unreliableRight) {\r
+ if (!comparableStatements.containsRight(s))\r
+ addAddition(s);\r
+ }\r
+ \r
+ \r
+ }\r
+ \r
+ private void process(Stack<Resource> objectsLeft, Stack<Resource> objectsRight, Set<Statement> unreliableLeft, Set<Statement> unreliableRight) throws DatabaseException {\r
List<Statement> ss1 = new ArrayList<Statement>();\r
List<Statement> ss2 = new ArrayList<Statement>();\r
\r
- while (!stack1.isEmpty()) {\r
- r1 = stack1.pop();\r
- r2 = stack2.pop();\r
- \r
- if (comparableResources.contains(r1, r2)) {\r
- System.out.println("already tested " + NameUtils.getSafeName(g, r1) + " " + NameUtils.getSafeName(g, r2));\r
+ while (!objectsLeft.isEmpty()) {\r
+ Resource r1 = objectsLeft.pop();\r
+ Resource r2 = objectsRight.pop();\r
+ \r
+ if (r1.equals(r2))\r
continue;\r
+ \r
+ if (processedResources.contains(r1))\r
+ continue;\r
+ processedResources.add(r1);\r
+ \r
+ \r
+ if(!comparableResources.contains(r1, r2) && (comparableResources.containsLeft(r1)||comparableResources.containsRight(r2))) {\r
+ 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
}\r
- comparableResources.map(r1, r2);\r
\r
- System.out.println("test " + NameUtils.getSafeName(g, r1) + " " + NameUtils.getSafeName(g, r2));\r
+ //System.out.println("test " + NameUtils.getSafeName(g, r1) + " " + NameUtils.getSafeName(g, r2));\r
compareProps(r1, r2);\r
\r
for (Resource rel : tested) {\r
ss1 = filterNonTested(ss1);\r
ss2 = filterNonTested(ss2);\r
\r
- compareStatement(ss1, ss2, null, null);\r
+ compareStatements(ss1, ss2, null, null,null,null);\r
ss1.clear();\r
ss2.clear();\r
}\r
ss2.addAll(g.getStatements(r2, rel));\r
ss1 = filterAsserted(r1, ss1);\r
ss2 = filterAsserted(r2, ss2);\r
- compareStatement(ss1, ss2, stack1, stack2);\r
+ compareStatements(ss1, ss2, objectsLeft, objectsRight,unreliableLeft,unreliableRight);\r
ss1.clear();\r
ss2.clear();\r
+ \r
}\r
}\r
- }\r
+ }\r
+ \r
+ private void processUnreliable(Set<Statement> unreliableLeft, Set<Statement> unreliableRight) {\r
+ MapList<Resource,Statement> subjectLeft = new MapList<Resource, Statement>();\r
+ MapList<Resource,Statement> subjectRight = new MapList<Resource, Statement>();\r
+ MapList<Resource,Statement> objectLeft = new MapList<Resource, Statement>();\r
+ MapList<Resource,Statement> objectRight = new MapList<Resource, Statement>();\r
+ \r
+ for (Statement s : unreliableLeft) {\r
+ subjectLeft.add(s.getSubject(),s);\r
+ objectLeft.add(s.getObject(),s);\r
+ }\r
+ for (Statement s : unreliableRight) {\r
+ subjectRight.add(s.getSubject(),s);\r
+ objectRight.add(s.getObject(),s);\r
+ }\r
+ \r
+ for (Resource left : subjectLeft.getKeys()) {\r
+ if (!comparableResources.containsLeft(left))\r
+ continue;\r
+ Resource right = comparableResources.getRight(left);\r
+ for (Statement leftS : subjectLeft.getValues(left)) {\r
+ Resource leftO = leftS.getObject();\r
+ if (!comparableResources.containsLeft(leftO)) \r
+ continue;\r
+ if (!unreliableLeft.contains(leftS))\r
+ continue;\r
+ Resource rightO = comparableResources.getRight(leftO);\r
+ for (Statement rightS : subjectRight.getValues(right)) {\r
+ if (!rightS.getObject().equals(rightO))\r
+ continue;\r
+ if (!unreliableRight.contains(rightS))\r
+ continue;\r
+ if (leftS.getPredicate().equals(rightS.getPredicate()) ||\r
+ comparableResources.contains(leftS.getPredicate(), rightS.getPredicate())) {\r
+ unreliableLeft.remove(leftS);\r
+ unreliableRight.remove(rightS);\r
+ addComparable(leftS, rightS, false);\r
+ }\r
+ }\r
+ }\r
+ \r
+ }\r
+ }\r
+ \r
+ private void processUnreliable(Set<Statement> unreliableLeft, Set<Statement> unreliableRight, Stack<Resource> objectsLeft, Stack<Resource> objectsRight) {\r
+ MapList<Resource,Statement> subjectLeft = new MapList<Resource, Statement>();\r
+ MapList<Resource,Statement> subjectRight = new MapList<Resource, Statement>();\r
+ MapList<Resource,Statement> objectLeft = new MapList<Resource, Statement>();\r
+ MapList<Resource,Statement> objectRight = new MapList<Resource, Statement>();\r
+ \r
+ for (Statement s : unreliableLeft) {\r
+ subjectLeft.add(s.getSubject(),s);\r
+ objectLeft.add(s.getObject(),s);\r
+ }\r
+ for (Statement s : unreliableRight) {\r
+ subjectRight.add(s.getSubject(),s);\r
+ objectRight.add(s.getObject(),s);\r
+ }\r
+ \r
+ for (Resource ol : objectLeft.getKeys()) {\r
+ // all statements to the left side object\r
+ List<Statement> left = objectLeft.getValues(ol);\r
+ // all subjects that have statements to the left side object (ol)\r
+ Set<Resource> sLeft = new HashSet<Resource>();\r
+ // all matching subjects on the right side\r
+ Set<Resource> sRight = new HashSet<Resource>();\r
+ for (Statement s : left) {\r
+ sLeft.add(s.getSubject());\r
+ sRight.add(comparableResources.getRight(s.getSubject()));\r
+ }\r
+ \r
+ // check if object left can be reliably identified by available statements\r
+ // if there are any objects on the left side with similar statements, object left cannot be mapped.\r
+ boolean hasSimilar = false;\r
+ MapList<Resource, Statement> comparableOLeft = new MapList<Resource, Statement>();\r
+ for (Resource sl : sLeft) {\r
+ for (Statement s : subjectLeft.getValues(sl)) {\r
+ if (!s.getObject().equals(ol)) {\r
+ comparableOLeft.add(s.getObject(),s);\r
+ }\r
+ }\r
+ }\r
+ \r
+ for (Resource similarOl : comparableOLeft.getKeys()) {\r
+ List<Statement> similarLeft = comparableOLeft.getValues(similarOl);\r
+ if (similarLeft.size() == left.size()) {\r
+ boolean useL[] = new boolean[left.size()];\r
+ boolean useSL[] = new boolean[left.size()];\r
+ for (int i = 0; i < left.size(); i++) {\r
+ useL[i] = false;\r
+ useSL[i] = false;\r
+ }\r
+ for (int i = 0; i < left.size(); i++) {\r
+ for (int j = 0; j < left.size(); j++) {\r
+ if (useSL[j])\r
+ continue;\r
+ Resource pl = left.get(i).getPredicate();\r
+ Resource psl = similarLeft.get(j).getPredicate();\r
+ if (pl.equals(psl)) {\r
+ useL[i] = true;\r
+ useSL[j] = true;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ boolean diff = false;\r
+ for (int i = 0; i < left.size(); i++) {\r
+ if (!useL[i] || !useSL[i]) {\r
+ diff = true;\r
+ }\r
+ }\r
+ if (!diff) {\r
+ hasSimilar = true;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ \r
+ if (hasSimilar)\r
+ continue;\r
+ \r
+ \r
+ // all objects that subjects on the right side point to. Object left has its matching resource among these, if it has matching resource\r
+ MapList<Resource,Statement> possibleOR = new MapList<Resource, Statement>();\r
+ for (Resource sr : sRight) {\r
+ for (Statement s : subjectRight.getValues(sr))\r
+ possibleOR.add(s.getObject(),s);\r
+ }\r
+ \r
+ // filter possible right side objects to those that have same amount of statements as the left side object\r
+ for (Resource or : possibleOR.getKeys().toArray(new Resource[possibleOR.getKeys().size()])) {\r
+ List<Statement> right = possibleOR.getValues(or);\r
+ if (right.size() != left.size())\r
+ possibleOR.remove(or);\r
+ \r
+ }\r
+ \r
+ // check for matching statements (comparable subjects, matching predicates)\r
+ MapList<Resource,Statement> matchingOR = new MapList<Resource, Statement>(); // list of objects that have matching statements\r
+ Map<Resource,Pair<int[], int[]>> matchingStatements = new HashMap<Resource, Pair<int[], int[]>>(); // matching statements\r
+ for (Resource or : possibleOR.getKeys()) {\r
+ List<Statement> right = possibleOR.getValues(or);\r
+ int iLeft[] = new int[left.size()];\r
+ int iRight[] = new int[right.size()];\r
+ \r
+ for (int i = 0; i < left.size(); i++) {\r
+ iLeft[i] = -1;\r
+ iRight[i] = -1;\r
+ }\r
+ \r
+ for (int l = 0; l < left.size(); l++) {\r
+ Statement ls = left.get(l);\r
+ for (int r = 0; r < right.size(); r++) {\r
+ if (iRight[r] >= 0)\r
+ continue;\r
+ Statement rs = right.get(r);\r
+ if (!comparableResources.contains(ls.getSubject(), rs.getSubject()))\r
+ continue;\r
+ if (rcomp.compare(ls.getPredicate(),rs.getPredicate()) == 0) {\r
+ iLeft[l] = r;\r
+ iRight[r] = l;\r
+ break;\r
+ }\r
+ }\r
+ \r
+ }\r
+ boolean success = true;\r
+ for (int i = 0; i < left.size(); i++) {\r
+ if (iLeft[i] < 0) {\r
+ success = false;\r
+ break;\r
+ }\r
+ if (iRight[i] < 0) {\r
+ success = false;\r
+ break;\r
+ }\r
+ \r
+ }\r
+ if (success) {\r
+ for (Statement s : right) \r
+ matchingOR.add(or,s);\r
+ matchingStatements.put(or, new Pair<int[], int[]>(iLeft, iRight));\r
+ }\r
+ }\r
+ // if there is only one matching right side object, we have found a match \r
+ if (matchingOR.getKeySize() == 1) {\r
+ Resource or = matchingOR.getKeys().iterator().next();\r
+ List<Statement> right = matchingOR.getValues(or);\r
+ Pair<int[], int[]> indices = matchingStatements.get(or);\r
+ \r
+ comparableResources.map(ol, or);\r
+ objectsLeft.add(ol);\r
+ objectsRight.add(or);\r
+ for (int l = 0; l < left.size(); l++) {\r
+ int r = indices.first[l];\r
+ Statement sl = left.get(l);\r
+ Statement sr = right.get(r);\r
+ addComparable(sl, sr, true);\r
+ unreliableLeft.remove(sl);\r
+ unreliableRight.remove(sr);\r
+ }\r
+ \r
+ }\r
+\r
+ }\r
+ \r
+ \r
+ }\r
+ \r
+ private void processUnreliableDeep(Set<Statement> unreliableLeft, Set<Statement> unreliableRight, Stack<Resource> objectsLeft, Stack<Resource> objectsRight) throws ManyObjectsForFunctionalRelationException, ServiceException {\r
+ MapList<Resource,Statement> subjectLeft = new MapList<Resource, Statement>();\r
+ MapList<Resource,Statement> subjectRight = new MapList<Resource, Statement>();\r
+ MapList<Resource,Statement> objectLeft = new MapList<Resource, Statement>();\r
+ MapList<Resource,Statement> objectRight = new MapList<Resource, Statement>();\r
+ \r
+ for (Statement s : unreliableLeft) {\r
+ subjectLeft.add(s.getSubject(),s);\r
+ objectLeft.add(s.getObject(),s);\r
+ }\r
+ for (Statement s : unreliableRight) {\r
+ subjectRight.add(s.getSubject(),s);\r
+ objectRight.add(s.getObject(),s);\r
+ }\r
+ for (Resource ol : objectLeft.getKeys()) {\r
+ Set<Path> pathsLeft = new HashSet<Path>();\r
+ for (Resource rel : traversed) {\r
+ pathsLeft.addAll(Path.create(g.getStatements(ol, rel)));\r
+ }\r
+ while (true) {\r
+ expand(pathsLeft);\r
+ if (pathsLeft.size() == 0)\r
+ break;\r
+ Collection<Path> endPaths = new ArrayList<Path>(1);\r
+ for (Path p : pathsLeft) {\r
+ if (comparableResources.containsLeft(p.getEnd())) {\r
+ endPaths.add(p);\r
+ }\r
+ }\r
+ if (endPaths.size() > 0) {\r
+ pathsLeft.clear();\r
+ pathsLeft.addAll(endPaths);\r
+ break;\r
+ } \r
+ }\r
+ if (pathsLeft.size() > 0) {\r
+ Resource sl = objectLeft.getValues(ol).get(0).getSubject();\r
+ Resource sr = comparableResources.getRight(sl);\r
+ Collection<Resource> possibleOR = new ArrayList<Resource>();\r
+ for (Statement s : subjectRight.getValues(sr)) {\r
+ possibleOR.add(s.getObject());\r
+ }\r
+ Map<Resource,Set<Path>> matchingPaths = new HashMap<Resource, Set<Path>>();\r
+ for (Resource or : possibleOR) {\r
+ Set<Path> possiblePathsRight = new HashSet<Path>();\r
+ for (Path leftPath : pathsLeft) {\r
+ possiblePathsRight.addAll(findComparableRight(leftPath, or));\r
+ }\r
+ if (possiblePathsRight.size() == pathsLeft.size()) {\r
+ matchingPaths.put(or, possiblePathsRight);\r
+ }\r
+ }\r
+ if (matchingPaths.size() > 0) {\r
+ if (matchingPaths.size() == 1) {\r
+ Resource or = matchingPaths.keySet().iterator().next();\r
+ objectsLeft.add(ol);\r
+ objectsRight.add(or);\r
+ comparableResources.map(ol, or);\r
+ Collection<Statement> statementsLeft = objectLeft.getValues(ol);\r
+ Collection<Statement> statementsRight = objectRight.getValues(or);\r
+ unreliableLeft.removeAll(statementsLeft);\r
+ unreliableRight.removeAll(statementsRight);\r
+ System.out.println("Compare not implemented");\r
+ } else {\r
+ System.out.println("Compare not implemented");\r
+ }\r
+ }\r
+ }\r
+ \r
+ }\r
+ \r
+ }\r
\r
+ private void expand(Set<Path> paths) throws ManyObjectsForFunctionalRelationException, ServiceException {\r
+ Set<Path> stepPathsLeft = new HashSet<Path>();\r
+ if (paths.size() == 0)\r
+ return;\r
+ int length = paths.iterator().next().getLength() + 1;\r
+ for (Path p : paths) {\r
+ for (Resource rel : traversed) {\r
+ stepPathsLeft.addAll(Path.expand(p,g.getStatements(p.getEnd(), rel)));\r
+ }\r
+ }\r
+ paths.clear();\r
+ for (Path p : stepPathsLeft) {\r
+ if (p.getLength() == length)\r
+ paths.add(p);\r
+ }\r
+ }\r
+ \r
+ private Collection<Path> findComparableRight(Path leftPath, Resource beginRight) throws ManyObjectsForFunctionalRelationException, ServiceException {\r
+ Set<Path> rightPaths = new HashSet<Path>();\r
+ rightPaths.addAll(Path.create(g.getStatements(beginRight, getRight(leftPath.getStatements().get(0).getPredicate()))));\r
+ for (int i = 1; i < leftPath.getLength(); i++) {\r
+ if (rightPaths.size() == 0)\r
+ return rightPaths;\r
+ Set<Path> stepPaths = new HashSet<Path>();\r
+ for (Path p : rightPaths) {\r
+ stepPaths.addAll(Path.expand(p, g.getStatements(p.getEnd(), getRight(leftPath.getStatements().get(i).getPredicate()))));\r
+ }\r
+ rightPaths.clear();\r
+ for (Path p : stepPaths)\r
+ if (p.getLength() == i+1) \r
+ rightPaths.add(p);\r
+ }\r
+ return rightPaths;\r
+ \r
+ }\r
\r
+ private Resource getRight(Resource r) {\r
+ if (comparableResources.containsLeft(r))\r
+ return comparableResources.getRight(r);\r
+ return r;\r
+ }\r
+ \r
+\r
\r
public BijectionMap<Statement, Statement> getComparableStatements() {\r
return comparableStatements;\r
}\r
\r
public GraphChanges getChanges() {\r
-// List<Statement> deletions = new ArrayList<Statement>();\r
-// List<Statement> additions = new ArrayList<Statement>();\r
-// deletions.addAll(changes1);\r
-// additions.addAll(changes2);\r
-// Collections.sort(deletions, new FullStatementComparator());\r
-// Collections.sort(additions, new FullStatementComparator());\r
-// return new GraphChanges(deletions, additions, modifications);\r
- return new GraphChanges(changes1,changes2,modifications);\r
+ return new GraphChanges(r1,r2,changes1,changes2,modifications,comparableResources);\r
+ }\r
+ \r
+ private void addComparable(Statement left, Statement right, boolean process) {\r
+ comparableStatements.map(left, right);\r
+ comparableResources.map(left.getObject(), right.getObject());\r
}\r
\r
- private List<Statement> filterAsserted(Resource r, Collection<Statement> in) throws ServiceException {\r
+ public List<Statement> filterAsserted(Resource r, Collection<Statement> in) throws ServiceException {\r
List<Statement> out = new ArrayList<Statement>();\r
for (Statement s : in) {\r
if (!s.isAsserted(r))\r
}\r
return out;\r
}\r
- \r
+\r
private String printStatement(ReadGraph graph, Statement s) throws ValidationException, ServiceException {\r
return NameUtils.getSafeName(graph, s.getSubject()) + " " + NameUtils.getSafeName(graph, s.getPredicate()) + " " + NameUtils.getSafeName(graph, s.getObject());\r
}\r
}\r
}\r
\r
- private void compareStatement(List<Statement> ss1, List<Statement> ss2, Stack<Resource> stack1, Stack<Resource> stack2) throws ServiceException, DoesNotContainValueException, ValidationException {\r
- Collections.sort(ss1, scomp);\r
- Collections.sort(ss2, scomp);\r
+ public void sortStatement(List<Statement> list1, List<Statement> list2) {\r
+ sortStatement(list1, list2, scomp);\r
+ }\r
+ \r
+ public void sortStatement(List<Statement> list1, List<Statement> list2, Comparator<Statement> scomp) {\r
+ Collections.sort(list1,scomp);\r
+ Collections.sort(list2,scomp);\r
+ \r
+ List<Statement> sorted1 = new ArrayList<Statement>(list1.size());\r
+ List<Statement> sorted2 = new ArrayList<Statement>(list2.size());\r
+ sorted1.addAll(list1);\r
+ sorted2.addAll(list2);\r
+ \r
+ int ss1 = 0;\r
+ int ss2 = 0;\r
+ for (int i = 0; i < list1.size(); ) {\r
+ Statement s1 = list1.get(i);\r
+ int same1 = sameRel(list1, i); \r
+ for (int j = 0; j < list2.size(); j++) {\r
+ Statement s2 = list2.get(j);\r
+ if (scomp.compare(s1, s2) == 0) {\r
+ int same2 = sameRel(list2, j);\r
+ copy(sorted1,ss1,list1,i,same1);\r
+ ss1 += same1;\r
+ copy(sorted2,ss2,list2,j,same2);\r
+ ss2 += same2;\r
+ break;\r
+ }\r
+ }\r
+ i+= same1;\r
+ }\r
+ if (ss1 < sorted1.size()) {\r
+ for (Statement s : list1) {\r
+ if (!sorted1.contains(s)) {\r
+ sorted1.set(ss1,s);\r
+ ss1++;\r
+ }\r
+ }\r
+ }\r
+ if (ss2 < sorted2.size()) {\r
+ for (Statement s : list2) {\r
+ if (!sorted2.contains(s)) {\r
+ sorted2.set(ss2,s);\r
+ ss2++;\r
+ }\r
+ }\r
+ }\r
+ \r
+ list1.clear();\r
+ list2.clear();\r
+ list1.addAll(sorted1);\r
+ list2.addAll(sorted2);\r
+ }\r
+ \r
+ public <T> void copy(List<T> to, int toIndex, List<T> from, int fromIndex, int amount) {\r
+ for (int i = 0; i < amount; i++) {\r
+ to.set(toIndex + i, from.get(fromIndex+ i));\r
+ }\r
+ }\r
+ \r
+ public void sortResource(List<Resource> list1, List<Resource> list2) {\r
+ Collections.sort(list1,rcomp);\r
+ int js = 0;\r
+ for (int i = 0; i < list1.size(); i++) {\r
+ Resource s1 = list1.get(i);\r
+ for (int j = js; j < list2.size(); j++) {\r
+ Resource s2 = list2.get(j);\r
+ if (rcomp.compare(s1, s2) == 0) {\r
+ Resource t = list2.get(js);\r
+ list2.set(js, s2);\r
+ list2.set(j, t);\r
+ break;\r
+ }\r
+ }\r
+ js++;\r
+ }\r
+ }\r
+ \r
+ private void compareStatements(List<Statement> ss1, List<Statement> ss2, Stack<Resource> objectsLeft, Stack<Resource> objectsRight, Collection<Statement> unreliableLeft, Collection<Statement> unreliableRight) throws DatabaseException {\r
+ sortStatement(ss1, ss2);\r
\r
int i1 = 0;\r
int i2 = 0;\r
break;\r
} else {\r
while (i2 < ss2.size()) {\r
- System.out.println("Compare Statement diff2 " + printStatement(g,ss2.get(i2)));\r
+ System.out.println("Compare Statements diff2 " + printStatement(g,ss2.get(i2)));\r
\r
addAddition(ss2.get(i2));\r
i2++;\r
}\r
} else if (i2 >= ss2.size()) {\r
while (i1 < ss1.size()) {\r
- System.out.println("Compare Statement diff1 " + printStatement(g,ss1.get(i1)));\r
+ System.out.println("Compare Statements diff1 " + printStatement(g,ss1.get(i1)));\r
addDeletion(ss1.get(i1));\r
i1++;\r
}\r
int same2 = sameRel(ss2, i2);\r
int c = rcomp.compare(ss1.get(i1).getPredicate(),ss2.get(i2).getPredicate());\r
if (c == 0) {\r
- compareObject(ss1, i1, same1, ss2, i2, same2,stack1,stack2);\r
+ compareStatements(ss1, i1, same1, ss2, i2, same2,objectsLeft,objectsRight,unreliableLeft,unreliableRight);\r
i1+=same1;\r
i2+=same2;\r
} else if (c < 0) {\r
for (int i = 0; i < same1; i++) {\r
- System.out.println("Compare Statement diff1 " + printStatement(g,ss1.get(i+i1)));\r
+ System.out.println("Compare Statements diff1 " + printStatement(g,ss1.get(i+i1)));\r
addDeletion(ss1.get(i+i1));\r
}\r
i1 += same1;\r
} else {\r
for (int i = 0; i < same2; i++) {\r
- System.out.println("Compare Statement diff2 " + printStatement(g,ss2.get(i+i2)));\r
+ System.out.println("Compare Statements diff2 " + printStatement(g,ss2.get(i+i2)));\r
addAddition(ss2.get(i+i2));\r
}\r
\r
i2 += same2;\r
}\r
- \r
}\r
}\r
\r
+\r
+ \r
private int sameRel(List<Statement> statements, int off) {\r
if (statements.size() <= off)\r
return 0;\r
\r
}\r
\r
+ private int compareObject(Resource o1, Resource o2) throws DatabaseException {\r
+ if (o1.equals(o2))\r
+ return -1;\r
+ if (comparableResources.contains(o1, o2))\r
+ return (-1);\r
+ if (comparableResources.containsLeft(o1))\r
+ return Integer.MAX_VALUE;\r
+ if (comparableResources.containsRight(o2))\r
+ return Integer.MAX_VALUE;\r
+ return comparator.compare(g, o1, o2);\r
+ }\r
\r
- private void compareObject(List<Statement> ss1, int off1, int len1, List<Statement> ss2, int off2, int len2, Stack<Resource> stack1, Stack<Resource> stack2) throws ServiceException, DoesNotContainValueException, ValidationException {\r
+ 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
boolean[] used1 = new boolean[len1];\r
for (int i = 0; i < used1.length; i++) {\r
used1[i] = false;\r
List<List<Integer>> differences = new ArrayList<List<Integer>>();\r
for (int i1 = off1; i1 < off1 + len1; i1++) {\r
Statement s1 = ss1.get(i1);\r
- //Map<Integer,Integer> differences = new HashMap<Integer, Integer>();\r
List<Integer> diff = new ArrayList<Integer>();\r
for (int i2 = off2; i2 < off2 + len2; i2++) {\r
Statement s2 = ss2.get(i2);\r
- if (!compareType(s1.getObject(), s2.getObject())) {\r
- diff.add(Integer.MAX_VALUE);\r
- continue;\r
+ int d = compareObject(s1.getObject(), s2.getObject());\r
+ if (d == 0) {\r
+ for (Resource t : strong) {\r
+ if (s1.getPredicate().equals(t) || g.isSubrelationOf(s1.getPredicate(), t)) {\r
+ d = 1;\r
+ break;\r
+ }\r
+ }\r
}\r
- if (comparableResources.contains(s1.getObject(), s2.getObject()))\r
- diff.add(-1);\r
- else\r
- diff.add(propsDiffCount(s1.getObject(), s2.getObject()));\r
+ diff.add(d);\r
}\r
differences.add(diff);\r
}\r
Arrays.sort(pris);\r
\r
for (Integer pri : pris) {\r
- if (pri == Integer.MAX_VALUE)\r
+ if (pri == Integer.MAX_VALUE) {\r
+\r
+ } else if (pri == 0) {\r
+ \r
+ } else {\r
+ List<Integer> i1s = priorities.getValues(pri);\r
+ for (Integer i1 : i1s) {\r
+ if (used1[i1])\r
+ continue;\r
+ List<Integer> i2diff = differences.get(i1);\r
+ for (int i2 = 0; i2 < i2diff.size(); i2++) {\r
+ if (i2diff.get(i2) == pri) {\r
+ if (used2[i2])\r
+ continue;\r
+ used1[i1] = true;\r
+ used2[i2] = true;\r
+ Statement s1 = ss1.get(i1+off1);\r
+ Statement s2 = ss2.get(i2+off2);\r
+ \r
+ if (objectsLeft != null) {\r
+ objectsLeft.add(s1.getObject());\r
+ objectsRight.add(s2.getObject());\r
+ } \r
+ addComparable(s1, s2, true);\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ \r
+ for (Integer pri : pris) {\r
+ if (pri != 0)\r
continue;\r
+ Set<Statement> s1s = new HashSet<Statement>();\r
+ Set<Statement> s2s = new HashSet<Statement>();\r
+ Set<Integer> s1i = new HashSet<Integer>();\r
+ Set<Integer> s2i = new HashSet<Integer>();\r
List<Integer> i1s = priorities.getValues(pri);\r
for (Integer i1 : i1s) {\r
if (used1[i1])\r
if (i2diff.get(i2) == pri) {\r
if (used2[i2])\r
continue;\r
- used1[i1] = true;\r
- used2[i2] = true;\r
Statement s1 = ss1.get(i1+off1);\r
Statement s2 = ss2.get(i2+off2);\r
- \r
- if (stack1 != null) {\r
- \r
- stack1.add(s1.getObject());\r
- stack2.add(s2.getObject());\r
- \r
- } else {\r
- // TODO : how should we report non traversed differences\r
- // using compareProps assumes that referenced objects are the same (references are not different)\r
- // using propsDiffCount assumes that objects are different, and cannot report changes in referred object.\r
- \r
- \r
-// int diff = propsDiffCount(ss1.get(i1+off1).getObject(), ss2.get(i2+off2).getObject());\r
-// if (diff != 0) {\r
-// //changes1.add(ss1.get(i1+off1));\r
-// //changes2.add(ss2.get(i2+off2));\r
-// modifies.add(new Pair<Statement, Statement>(ss1.get(i1+off1), ss2.get(i2+off2)));\r
-// }\r
- }\r
- comparableStatements.map(s1, s2);\r
- //comparableResources.map(s1.getObject(), s2.getObject());\r
- break;\r
+ s1s.add(s1);\r
+ s2s.add(s2);\r
+ s1i.add(i1);\r
+ s2i.add(i2);\r
}\r
}\r
}\r
+ if (unreliableLeft != null) {\r
+ unreliableLeft.addAll(s1s);\r
+ unreliableRight.addAll(s2s);\r
+ }\r
+ for (Integer i : s1i)\r
+ used1[i] = true;\r
+ for (Integer i : s2i)\r
+ used2[i] = true;\r
+\r
}\r
for (int i1 = off1; i1 < off1 + len1; i1++) {\r
if (!used1[i1-off1]) {\r
}\r
}\r
\r
- private boolean compareType(Resource r1, Resource r2) throws ServiceException, ManyObjectsForFunctionalRelationException {\r
- rs1.addAll(g.getObjects(r1, b.InstanceOf));\r
- rs2.addAll(g.getObjects(r2, b.InstanceOf));\r
- if (rs1.size() != rs2.size()) {\r
- rs1.clear();\r
- rs2.clear();\r
- return false;\r
- }\r
- Collections.sort(rs1, rcomp);\r
- Collections.sort(rs2, rcomp);\r
- for (int i = 0; i < rs1.size(); i++) {\r
- int c = rcomp.compare(rs1.get(i), rs2.get(i));\r
- if (c != 0) {\r
- rs1.clear();\r
- rs2.clear();\r
- return false;\r
- }\r
- }\r
- \r
- rs1.clear();\r
- rs2.clear();\r
- \r
- return true;\r
- }\r
+ \r
\r
/**\r
* compares properties, assumes functional relations\r
* @throws ValidationException \r
*/\r
private void compareProps(Resource r1, Resource r2) throws ServiceException, DoesNotContainValueException, ValidationException {\r
+ System.out.println("compareProps " + r1 + " " + NameUtils.getSafeName(g, r1) + " " + r2 + " " + NameUtils.getSafeName(g, r2));\r
ArrayList<Statement> ss1 = new ArrayList<Statement>();\r
ArrayList<Statement> ss2 = new ArrayList<Statement>();\r
ss1.addAll(g.getStatements(r1, b.HasProperty));\r
ss2.addAll(g.getStatements(r2, b.HasProperty));\r
- Collections.sort(ss1, scomp);\r
- Collections.sort(ss2, scomp);\r
+ sortStatement(ss1, ss2);\r
\r
int i1 = 0; \r
int i2 = 0;\r
}\r
Statement s1 = ss1.get(i1);\r
Statement s2 = ss2.get(i2);\r
- int c = scomp.compare(s1, s2);\r
- switch (c) {\r
- case 0:{\r
- boolean b1 = g.hasValue(s1.getObject());\r
- boolean b2 = g.hasValue(s2.getObject());\r
- if (b1 == b2) {\r
- if (b1) {\r
- Object v1 = g.getValue(s1.getObject());\r
- Object v2 = g.getValue(s2.getObject());\r
- boolean eq = false;\r
- if (v1 instanceof Object[] && v2 instanceof Object[])\r
- eq = Arrays.deepEquals((Object[])v1, (Object[])v2);\r
- else if (v1 instanceof int[] && v2 instanceof int[]) \r
- eq = Arrays.equals((int[])v1, (int[])v2);\r
- else if (v1 instanceof float[] && v2 instanceof float[]) \r
- eq = Arrays.equals((float[])v1, (float[])v2);\r
- else if (v1 instanceof double[] && v2 instanceof double[]) \r
- eq = Arrays.equals((double[])v1, (double[])v2);\r
- else if (v1 instanceof long[] && v2 instanceof long[]) \r
- eq = Arrays.equals((long[])v1, (long[])v2);\r
- else if (v1 instanceof byte[] && v2 instanceof byte[]) \r
- eq = Arrays.equals((byte[])v1, (byte[])v2);\r
- else if (v1 instanceof boolean[] && v2 instanceof boolean[]) \r
- eq = Arrays.equals((boolean[])v1, (boolean[])v2);\r
- else\r
- eq = v1.equals(v2);\r
- if (!eq) {\r
- //changes1.add(s1);\r
- //changes2.add(s2);\r
- addModification(s1, s2);\r
- comparableStatements.map(s1, s2);\r
- comparableResources.map(s1.getObject(),s2.getObject());\r
- }\r
- } else {\r
- compareProps(s1.getObject(), s2.getObject());\r
- }\r
- } else {\r
- //changes1.add(s1);\r
- //changes2.add(s2);\r
- addModification(s1, s2);\r
- comparableStatements.map(s1, s2);\r
- comparableResources.map(s1.getObject(),s2.getObject());\r
- }\r
+ if (s1.isAsserted(r1) && s2.isAsserted(r2)) {\r
i1++;\r
i2++;\r
- break;\r
- }\r
- case -1:{\r
- System.out.println("Compare Prop diff1s " + printStatement(g,s1));\r
- addDeletion(s1);\r
- i1++;\r
- break;\r
- }\r
- \r
- case 1:{\r
- System.out.println("Compare Prop diff2s " + printStatement(g,s2));\r
- addAddition(s2);\r
- i2++;\r
- break;\r
- }\r
- }\r
- \r
- \r
- }\r
- \r
- ss1.clear();\r
- ss2.clear();\r
- \r
- }\r
- \r
- private int propsDiffCount(Resource r1, Resource r2) throws ServiceException, DoesNotContainValueException, ValidationException {\r
- ArrayList<Statement> ss1 = new ArrayList<Statement>();\r
- ArrayList<Statement> ss2 = new ArrayList<Statement>();\r
- ss1.addAll(g.getStatements(r1, b.HasProperty));\r
- ss2.addAll(g.getStatements(r2, b.HasProperty));\r
- //System.out.println("Props count " + GraphUtils.getReadableName(g, r1) + " " + GraphUtils.getReadableName(g, r2));\r
- Collections.sort(ss1, scomp);\r
- Collections.sort(ss2, scomp);\r
- \r
- int count = 0;\r
- \r
- int i1 = 0; \r
- int i2 = 0;\r
- \r
- while (true) {\r
- if (i1 >= ss1.size()) {\r
- if (i2 >= ss2.size())\r
- break;\r
- else {\r
- while (i2 < ss2.size()) {\r
- count++;\r
- i2++;\r
- }\r
- break;\r
- }\r
- } else if (i2 >= ss2.size()) {\r
- while (i1 < ss1.size()) {\r
- count++;\r
- i1++;\r
- }\r
- break;\r
+ continue;\r
}\r
- Statement s1 = ss1.get(i1);\r
- Statement s2 = ss2.get(i2);\r
int c = scomp.compare(s1, s2);\r
switch (c) {\r
case 0:{\r
if (b1) {\r
Object v1 = g.getValue(s1.getObject());\r
Object v2 = g.getValue(s2.getObject());\r
- boolean eq = false;\r
- if (v1 instanceof Object[] && v2 instanceof Object[])\r
- eq = Arrays.deepEquals((Object[])v1, (Object[])v2);\r
- else if (v1 instanceof int[] && v2 instanceof int[]) \r
- eq = Arrays.equals((int[])v1, (int[])v2);\r
- else if (v1 instanceof float[] && v2 instanceof float[]) \r
- eq = Arrays.equals((float[])v1, (float[])v2);\r
- else if (v1 instanceof double[] && v2 instanceof double[]) \r
- eq = Arrays.equals((double[])v1, (double[])v2);\r
- else if (v1 instanceof long[] && v2 instanceof long[]) \r
- eq = Arrays.equals((long[])v1, (long[])v2);\r
- else if (v1 instanceof byte[] && v2 instanceof byte[]) \r
- eq = Arrays.equals((byte[])v1, (byte[])v2);\r
- else if (v1 instanceof boolean[] && v2 instanceof boolean[]) \r
- eq = Arrays.equals((boolean[])v1, (boolean[])v2);\r
- else\r
- eq = v1.equals(v2);\r
+ boolean eq = compareValue(v1, v2);\r
if (!eq) {\r
- count++;\r
+ addModification(s1, s2);\r
+ addComparable(s1, s2, false);\r
}\r
- //System.out.println("Prop count values " + v1 + " " + v2);\r
} else {\r
- count += propsDiffCount(s1.getObject(), s2.getObject());\r
+ if (!s1.getObject().equals(s1.getSubject()) && !s2.getObject().equals(s2.getSubject()))\r
+ compareProps(s1.getObject(), s2.getObject());\r
}\r
} else {\r
- //System.out.println("Props count structural vs literal");\r
- count++;\r
+ addModification(s1, s2);\r
+ addComparable(s1, s2, false);\r
}\r
i1++;\r
i2++;\r
break;\r
}\r
case -1:{\r
- count++;\r
+ System.out.println("Compare Prop diff1s " + printStatement(g,s1));\r
+ addDeletion(s1);\r
i1++;\r
break;\r
}\r
\r
case 1:{\r
- count++;\r
+ System.out.println("Compare Prop diff2s " + printStatement(g,s2));\r
+ addAddition(s2);\r
i2++;\r
break;\r
}\r
\r
ss1.clear();\r
ss2.clear();\r
- return count;\r
+ \r
}\r
-\r
\r
+ public static boolean compareValue(Object v1, Object v2) {\r
+ if (v1 instanceof Object[] && v2 instanceof Object[])\r
+ return Arrays.deepEquals((Object[])v1, (Object[])v2);\r
+ else if (v1 instanceof int[] && v2 instanceof int[]) \r
+ return Arrays.equals((int[])v1, (int[])v2);\r
+ else if (v1 instanceof float[] && v2 instanceof float[]) \r
+ return Arrays.equals((float[])v1, (float[])v2);\r
+ else if (v1 instanceof double[] && v2 instanceof double[]) \r
+ return Arrays.equals((double[])v1, (double[])v2);\r
+ else if (v1 instanceof long[] && v2 instanceof long[]) \r
+ return Arrays.equals((long[])v1, (long[])v2);\r
+ else if (v1 instanceof byte[] && v2 instanceof byte[]) \r
+ return Arrays.equals((byte[])v1, (byte[])v2);\r
+ else if (v1 instanceof boolean[] && v2 instanceof boolean[]) \r
+ return Arrays.equals((boolean[])v1, (boolean[])v2);\r
+ else\r
+ return v1.equals(v2);\r
+ }\r
+\r
\r
public class PredicateComparator implements Comparator<Statement> {\r
@Override\r
public int compare(Statement o1, Statement o2) {\r
+ if (comparableResources.contains(o1.getPredicate(), o2.getPredicate()))\r
+ return 0;\r
if (o1.getPredicate().getResourceId() < o2.getPredicate().getResourceId())\r
return -1;\r
if (o1.getPredicate().getResourceId() > o2.getPredicate().getResourceId())\r
}\r
}\r
\r
- public class FullStatementComparator implements Comparator<Statement> {\r
+ public class SubjectComparator implements Comparator<Statement> {\r
+ @Override\r
+ public int compare(Statement o1, Statement o2) {\r
+ if (comparableResources.contains(o1.getSubject(), o2.getSubject()))\r
+ return 0;\r
+ if (o1.getSubject().getResourceId() < o2.getSubject().getResourceId())\r
+ return -1;\r
+ if (o1.getSubject().getResourceId() > o2.getSubject().getResourceId())\r
+ return 1;\r
+ return 0;\r
+ }\r
+ }\r
+ \r
+ public class ObjectComparator implements Comparator<Statement> {\r
+ @Override\r
+ public int compare(Statement o1, Statement o2) {\r
+ if (comparableResources.contains(o1.getObject(), o2.getObject()))\r
+ return 0;\r
+ if (o1.getObject().getResourceId() < o2.getObject().getResourceId())\r
+ return -1;\r
+ if (o1.getObject().getResourceId() > o2.getObject().getResourceId())\r
+ return 1;\r
+ return 0;\r
+ }\r
+ }\r
+ \r
+ public static class FullStatementComparator implements Comparator<Statement> {\r
@Override\r
public int compare(Statement o1, Statement o2) {\r
if (o1.getSubject().getResourceId() < o2.getSubject().getResourceId())\r
}\r
}\r
\r
-\r
- \r
- public class ResourceComparator implements Comparator<Resource> {\r
+ public class ResComparator implements Comparator<Resource> {\r
@Override\r
public int compare(Resource o1, Resource o2) {\r
+ if (comparableResources.contains(o1, o2))\r
+ return 0;\r
if (o1.getResourceId() < o2.getResourceId())\r
return -1;\r
if (o1.getResourceId() > o2.getResourceId())\r
return 0;\r
}\r
}\r
+\r
}\r