]> gerrit.simantics Code Review - simantics/interop.git/blob - org.simantics.interop/src/org/simantics/interop/test/GraphComparator.java
GraphComparator behavior can be customized with ObjectComparator
[simantics/interop.git] / org.simantics.interop / src / org / simantics / interop / test / GraphComparator.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
3  * in Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     Foster Wheeler Energia Oy - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.interop.test;\r
13 \r
14 import java.util.ArrayList;\r
15 import java.util.Arrays;\r
16 import java.util.Collection;\r
17 import java.util.Collections;\r
18 import java.util.Comparator;\r
19 import java.util.HashSet;\r
20 import java.util.List;\r
21 import java.util.Set;\r
22 import java.util.Stack;\r
23 \r
24 import org.simantics.db.ReadGraph;\r
25 import org.simantics.db.Resource;\r
26 import org.simantics.db.Statement;\r
27 import org.simantics.db.common.utils.NameUtils;\r
28 import org.simantics.db.exception.DatabaseException;\r
29 import org.simantics.db.exception.DoesNotContainValueException;\r
30 import org.simantics.db.exception.ServiceException;\r
31 import org.simantics.db.exception.ValidationException;\r
32 import org.simantics.layer0.Layer0;\r
33 import org.simantics.utils.datastructures.BijectionMap;\r
34 import org.simantics.utils.datastructures.MapList;\r
35 import org.simantics.utils.datastructures.Pair;\r
36 \r
37 /**\r
38  * Compares two subgraphs and reports differences.\r
39  * \r
40  * Assumes that subgraphs (defined using traverse relations) are not cyclic.\r
41  * \r
42  * Assumes that properties can be used to identify objects, if relation type is not enough.\r
43  * \r
44  * \r
45  * \r
46  * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
47  *\r
48  */\r
49 public class GraphComparator {\r
50 \r
51         private Resource r1;\r
52         private Resource r2;\r
53         private List<Resource> traversed = new ArrayList<Resource>(); // list of relations that are traversed (and tested)\r
54         private List<Resource> tested = new ArrayList<Resource>();    // list of relations that are tested, but not traversed\r
55         private List<Resource> nonTraversed = new ArrayList<Resource>(); // list of relations that are not traversed\r
56         private List<Resource> nonTested = new ArrayList<Resource>(); // list of relations that are not tested\r
57         \r
58         private List<Statement> changes1 = new ArrayList<Statement>();\r
59         private List<Statement> changes2 = new ArrayList<Statement>();\r
60         private List<Pair<Statement,Statement>> modifications = new ArrayList<Pair<Statement,Statement>>();\r
61         private Set<Statement> changes1Set = new HashSet<Statement>();\r
62         private Set<Statement> changes2Set = new HashSet<Statement>();\r
63         private Set<Pair<Statement,Statement>> modificationsSet = new HashSet<Pair<Statement,Statement>>();\r
64 \r
65         private BijectionMap<Statement, Statement> comparableStatements = new BijectionMap<Statement, Statement>();\r
66         private BijectionMap<Resource, Resource> comparableResources = new BijectionMap<Resource, Resource>();\r
67         \r
68         \r
69         private ObjectComparator comparator;\r
70         \r
71         // runtime attributes\r
72         \r
73         private ReadGraph g;\r
74         private Layer0 b;\r
75         \r
76         public GraphComparator() {\r
77                  comparator = new TypeComparator();\r
78         }\r
79         \r
80         public GraphComparator(ObjectComparator comparator) {\r
81                  this.comparator = comparator;\r
82         }\r
83         \r
84         ArrayList<Statement> ss1 = new ArrayList<Statement>();\r
85         ArrayList<Statement> ss2 = new ArrayList<Statement>();\r
86         \r
87         Comparator<Statement> scomp = new PredicateComparator();\r
88         Comparator<Resource> rcomp = new ResourceComparator();\r
89 \r
90         \r
91         public void addTraversed(Resource rel) {\r
92                 traversed.add(rel);\r
93         }\r
94         \r
95         public void addTraversed(Collection<Resource> rels) {\r
96                 traversed.addAll(rels);\r
97         }\r
98         \r
99         public void addNonTraversed(Resource rel) {\r
100                 nonTraversed.add(rel);\r
101         }\r
102         \r
103         public void addNonTraversed(Collection<Resource> rels) {\r
104                 nonTraversed.addAll(rels);\r
105         }\r
106         \r
107         public void addTested(Resource rel) {\r
108                 tested.add(rel);\r
109         }\r
110         \r
111         public void addTested(Collection<Resource> rels) {\r
112                 tested.addAll(rels);\r
113         }\r
114         \r
115         public void addNonTested(Resource rel) {\r
116                 nonTested.add(rel);\r
117         }\r
118         \r
119         public void addNonTested(Collection<Resource> rels) {\r
120                 nonTested.addAll(rels);\r
121         }\r
122         \r
123         public void clearRels() {\r
124                 traversed.clear();\r
125                 tested.clear();\r
126         }\r
127         \r
128         public void test(ReadGraph g, Resource r1, Resource r2) throws DatabaseException {\r
129                 this.g = g;\r
130                 this.b = Layer0.getInstance(g);\r
131                 \r
132                 this.r1 = r1;\r
133                 this.r2 = r2;\r
134                 changes1Set.clear();\r
135                 changes2Set.clear();\r
136                 modificationsSet.clear();\r
137                 changes1.clear();\r
138                 changes2.clear();\r
139                 modifications.clear();\r
140                 comparableResources.clear();\r
141                 \r
142                 Stack<Resource> stack1 = new Stack<Resource>();\r
143                 Stack<Resource> stack2 = new Stack<Resource>();\r
144                 stack1.push(r1);\r
145                 stack2.push(r2);\r
146                 \r
147                 \r
148                 List<Statement> ss1 = new ArrayList<Statement>();\r
149                 List<Statement> ss2 = new ArrayList<Statement>();\r
150                 \r
151                 while (!stack1.isEmpty()) {\r
152                         r1 = stack1.pop();\r
153                         r2 = stack2.pop();\r
154                 \r
155                         if (comparableResources.contains(r1, r2)) {\r
156                                 System.out.println("already tested " + NameUtils.getSafeName(g, r1) + " " + NameUtils.getSafeName(g, r2));\r
157                                 continue;\r
158                         }\r
159                         comparableResources.map(r1, r2);\r
160                         \r
161                         System.out.println("test " + NameUtils.getSafeName(g, r1) + " " + NameUtils.getSafeName(g, r2));\r
162                         compareProps(r1, r2);\r
163                         \r
164                         for (Resource rel : tested) {\r
165                                 ss1.addAll(g.getStatements(r1, rel));\r
166                                 ss2.addAll(g.getStatements(r2, rel));\r
167                                 ss1 = filterAsserted(r1, ss1);\r
168                                 ss2 = filterAsserted(r2, ss2);\r
169                                 ss1 = filterTraversed(ss1);\r
170                                 ss2 = filterTraversed(ss2);\r
171                                 ss1 = filterNonTested(ss1);\r
172                                 ss2 = filterNonTested(ss2);\r
173                                 \r
174                                 compareStatements(ss1, ss2, null, null);\r
175                                 ss1.clear();\r
176                                 ss2.clear();\r
177                         }\r
178                         \r
179                         for (Resource rel : traversed) {\r
180                                 ss1.addAll(g.getStatements(r1, rel));\r
181                                 ss2.addAll(g.getStatements(r2, rel));\r
182                                 ss1 = filterAsserted(r1, ss1);\r
183                                 ss2 = filterAsserted(r2, ss2);\r
184                                 compareStatements(ss1, ss2, stack1, stack2);\r
185                                 ss1.clear();\r
186                                 ss2.clear();\r
187                         }\r
188                 }\r
189         }\r
190         \r
191         \r
192         \r
193         public BijectionMap<Statement, Statement> getComparableStatements() {\r
194                 return comparableStatements;\r
195         }\r
196         \r
197         public GraphChanges getChanges() {\r
198                 return new GraphChanges(r1,r2,changes1,changes2,modifications);\r
199         }\r
200         \r
201         private List<Statement> filterAsserted(Resource r, Collection<Statement> in) throws ServiceException {\r
202                 List<Statement> out = new ArrayList<Statement>();\r
203                 for (Statement s : in) {\r
204                         if (!s.isAsserted(r))\r
205                                 out.add(s);\r
206                         \r
207                 }\r
208                 return out;\r
209         }\r
210         \r
211         private String printStatement(ReadGraph graph, Statement s) throws ValidationException, ServiceException {\r
212                 return NameUtils.getSafeName(graph, s.getSubject()) + " " + NameUtils.getSafeName(graph, s.getPredicate()) + " " + NameUtils.getSafeName(graph, s.getObject());\r
213         }\r
214         \r
215         private List<Statement> filterTraversed(List<Statement> in) throws ServiceException {\r
216                 return filter(traversed, in);\r
217         }\r
218         \r
219         private List<Statement> filterNonTested(List<Statement> in) throws ServiceException {\r
220                 return filter(nonTested, in);\r
221         }\r
222         \r
223         private List<Statement> filter(Collection<Resource> toFilter, List<Statement> in) throws ServiceException {\r
224                 if (toFilter.size() == 0)\r
225                         return in;\r
226                 List<Statement> out = new ArrayList<Statement>();\r
227                 for (Statement s : in) {\r
228                         boolean usable = true;\r
229                         for (Resource r : toFilter) {\r
230                                 if (g.isSubrelationOf(s.getPredicate(),r)) {\r
231                                         usable = false;\r
232                                         break;\r
233                                 }\r
234                         }\r
235                         if (usable) {\r
236                                 out.add(s);\r
237                         }\r
238                         \r
239                 }\r
240                 return out;\r
241         }\r
242         \r
243         \r
244         private void addDeletion(Statement s) {\r
245                 if (!changes1Set.contains(s)) {\r
246                         changes1Set.add(s);\r
247                         changes1.add(s);\r
248                 }\r
249         }\r
250         \r
251         private void addAddition(Statement s) {\r
252                 if (!changes2Set.contains(s)) {\r
253                         changes2Set.add(s);\r
254                         changes2.add(s);\r
255                 }\r
256         }\r
257         \r
258         private void addModification(Statement s1, Statement s2) {\r
259                 Pair<Statement, Statement> mod = new Pair<Statement, Statement>(s1,s2);\r
260                 if (!modificationsSet.contains(mod)) {\r
261                         modificationsSet.add(mod);\r
262                         modifications.add(mod);\r
263                 }\r
264         }\r
265         \r
266         private void compareStatements(List<Statement> ss1, List<Statement> ss2, Stack<Resource> stack1, Stack<Resource> stack2) throws DatabaseException {\r
267                 Collections.sort(ss1, scomp);\r
268                 Collections.sort(ss2, scomp);\r
269                 \r
270                 int i1 = 0;\r
271                 int i2 = 0;\r
272                 \r
273                 while (true) {\r
274                         if (i1 >= ss1.size()) {\r
275                                 if (i2 >= ss2.size()) {\r
276                                         break;\r
277                                 } else {\r
278                                         while (i2 < ss2.size()) {\r
279                                                 System.out.println("Compare Statement diff2 " + printStatement(g,ss2.get(i2)));\r
280                                                 \r
281                                                 addAddition(ss2.get(i2));\r
282                                                 i2++;\r
283                                         }\r
284                                         break;\r
285                                 }\r
286                         } else if (i2 >= ss2.size()) {\r
287                                 while (i1 < ss1.size()) {\r
288                                         System.out.println("Compare Statement diff1 " + printStatement(g,ss1.get(i1)));\r
289                                         addDeletion(ss1.get(i1));\r
290                                         i1++;\r
291                                 }\r
292                                 break;\r
293                         }\r
294                         int same1 = sameRel(ss1, i1);\r
295                         int same2 = sameRel(ss2, i2);\r
296                         int c = rcomp.compare(ss1.get(i1).getPredicate(),ss2.get(i2).getPredicate());\r
297                         if (c == 0) {\r
298                                 compareStatements(ss1, i1, same1, ss2, i2, same2,stack1,stack2);\r
299                                 i1+=same1;\r
300                                 i2+=same2;\r
301                         } else if (c < 0) {\r
302                                 for (int i = 0; i < same1; i++) {\r
303                                         System.out.println("Compare Statement diff1 " + printStatement(g,ss1.get(i+i1)));\r
304                                         addDeletion(ss1.get(i+i1));\r
305                                 }\r
306                                 i1 += same1;\r
307                         } else {\r
308                                 for (int i = 0; i < same2; i++) {\r
309                                         System.out.println("Compare Statement diff2 " + printStatement(g,ss2.get(i+i2)));\r
310                                         addAddition(ss2.get(i+i2));\r
311                                 }\r
312                                 \r
313                                 i2 += same2;\r
314                         }\r
315                         \r
316                 }\r
317         }\r
318         \r
319         private int sameRel(List<Statement> statements, int off) {\r
320                 if (statements.size() <= off)\r
321                         return 0;\r
322                 int same = 1;\r
323                 long id = statements.get(off).getPredicate().getResourceId();\r
324                 for (int i = off+1; i <statements.size(); i++) {\r
325                         if (statements.get(i).getPredicate().getResourceId() == id)\r
326                                 same++;\r
327                         else \r
328                                 break;\r
329                 }\r
330                 return same;\r
331                 \r
332         }\r
333 \r
334         private int compareObject(Resource o1, Resource o2) throws DatabaseException {\r
335                 if (comparableResources.contains(o1, o2))\r
336                         return (-1);\r
337                 return comparator.compare(g, o1, o2);\r
338         }\r
339         \r
340         private void compareStatements(List<Statement> ss1, int off1, int len1, List<Statement> ss2, int off2, int len2, Stack<Resource> stack1, Stack<Resource> stack2) throws DatabaseException {\r
341                 boolean[] used1 = new boolean[len1];\r
342                 for (int i = 0; i < used1.length; i++) {\r
343                         used1[i] = false;\r
344                 }\r
345                 \r
346                 boolean[] used2 = new boolean[len2];\r
347                 for (int i = 0; i < used2.length; i++) {\r
348                         used2[i] = false;\r
349                 }\r
350                 \r
351                 // left, right, difference\r
352                 List<List<Integer>> differences = new ArrayList<List<Integer>>();\r
353                 for (int i1 = off1; i1 < off1 + len1; i1++) {\r
354                         Statement s1 = ss1.get(i1);\r
355                         List<Integer> diff = new ArrayList<Integer>();\r
356                         for (int i2 = off2; i2 < off2 + len2; i2++) {\r
357                                 Statement s2 = ss2.get(i2);\r
358                                 diff.add(compareObject(s1.getObject(), s2.getObject()));\r
359                         }\r
360                         differences.add(diff);\r
361                 }\r
362                 // difference, left\r
363                 MapList<Integer, Integer> priorities = new MapList<Integer, Integer>();\r
364                 for (int i = 0; i < differences.size(); i++) {\r
365                         List<Integer> list = differences.get(i);\r
366                         for (int j = 0; j < list.size(); j++) {\r
367                                 priorities.add(list.get(j), i);\r
368                         }\r
369                 }\r
370                 \r
371                 Integer[] pris = priorities.getKeys(new Integer[]{});\r
372                 Arrays.sort(pris);\r
373                 \r
374                 for (Integer pri : pris) {\r
375                         if (pri == Integer.MAX_VALUE)\r
376                                 continue;\r
377                         List<Integer> i1s = priorities.getValues(pri);\r
378                         for (Integer i1 : i1s) {\r
379                                 if (used1[i1])\r
380                                         continue;\r
381                                 List<Integer> i2diff = differences.get(i1);\r
382                                 for (int i2 = 0; i2 < i2diff.size(); i2++) {\r
383                                         if (i2diff.get(i2) == pri) {\r
384                                                 if (used2[i2])\r
385                                                         continue;\r
386                                                 used1[i1] = true;\r
387                                                 used2[i2] = true;\r
388                                                 Statement s1  = ss1.get(i1+off1);\r
389                                                 Statement s2  = ss2.get(i2+off2);\r
390                                                 \r
391                                                 if (stack1 != null) {\r
392                                                         \r
393                                                                 stack1.add(s1.getObject());\r
394                                                                 stack2.add(s2.getObject());\r
395                                                         \r
396                                                 } else {\r
397                                                         // TODO : how should we report non traversed differences\r
398                                                         // using compareProps assumes that referenced objects are the same (references are not different)\r
399                                                         // using propsDiffCount assumes that objects are different, and cannot report changes in referred object.\r
400                                                         \r
401                                                         \r
402 //                                                      int diff = propsDiffCount(ss1.get(i1+off1).getObject(), ss2.get(i2+off2).getObject());\r
403 //                                                      if (diff != 0) {\r
404 //                                                              //changes1.add(ss1.get(i1+off1));\r
405 //                                                              //changes2.add(ss2.get(i2+off2));\r
406 //                                                              modifies.add(new Pair<Statement, Statement>(ss1.get(i1+off1), ss2.get(i2+off2)));\r
407 //                                                      }\r
408                                                 }\r
409                                                 comparableStatements.map(s1, s2);\r
410                                                 //comparableResources.map(s1.getObject(), s2.getObject());\r
411                                                 break;\r
412                                         }\r
413                                 }\r
414                         }\r
415                 }\r
416                 for (int i1 = off1; i1 < off1 + len1; i1++) {\r
417                         if (!used1[i1-off1]) {\r
418                                 System.out.println("Compare Object diff1 " + printStatement(g,ss1.get(i1)));\r
419                                 addDeletion(ss1.get(i1));\r
420                         }\r
421                 }\r
422                 for (int i2 = off2; i2 < off2 + len2; i2++) {\r
423                         if (!used2[i2-off2]) {\r
424                                 System.out.println("Compare Object diff2 " + printStatement(g,ss2.get(i2)));\r
425                                 addAddition(ss2.get(i2));\r
426                         }\r
427                 }\r
428         }\r
429         \r
430         \r
431         \r
432         /**\r
433          * compares properties, assumes functional relations\r
434          * @param r1\r
435          * @param r2\r
436          * @throws ServiceException\r
437          * @throws DoesNotContainValueException\r
438          * @throws ValidationException \r
439          */\r
440         private void compareProps(Resource r1, Resource r2) throws ServiceException, DoesNotContainValueException, ValidationException {\r
441                 ArrayList<Statement> ss1 = new ArrayList<Statement>();\r
442                 ArrayList<Statement> ss2 = new ArrayList<Statement>();\r
443                 ss1.addAll(g.getStatements(r1, b.HasProperty));\r
444                 ss2.addAll(g.getStatements(r2, b.HasProperty));\r
445                 Collections.sort(ss1, scomp);\r
446                 Collections.sort(ss2, scomp);\r
447                 \r
448                 int i1 = 0; \r
449                 int i2 = 0;\r
450                 \r
451                 while (true) {\r
452                         if (i1 >= ss1.size()) {\r
453                                 if (i2 >= ss2.size())\r
454                                         break;\r
455                                 else {\r
456                                         while (i2 < ss2.size()) {\r
457                                                 System.out.println("Compare Prop diff2 " + printStatement(g,ss2.get(i2)));\r
458                                                 addAddition(ss2.get(i2));\r
459                                                 i2++;\r
460                                         }\r
461                                         break;\r
462                                 }\r
463                         } else if (i2 >= ss2.size()) {\r
464                                 while (i1 < ss1.size()) {\r
465                                         System.out.println("Compare Prop diff1 " + printStatement(g,ss1.get(i1)));\r
466                                         addDeletion(ss1.get(i1));\r
467                                         i1++;\r
468                                 }\r
469                                 break;\r
470                         }\r
471                         Statement s1 = ss1.get(i1);\r
472                         Statement s2 = ss2.get(i2);\r
473                         int c = scomp.compare(s1, s2);\r
474                         switch (c) {\r
475                         case 0:{\r
476                                 boolean b1 = g.hasValue(s1.getObject());\r
477                                 boolean b2 = g.hasValue(s2.getObject());\r
478                                 if (b1 == b2) {\r
479                                         if (b1) {\r
480                                                 Object v1 = g.getValue(s1.getObject());\r
481                                                 Object v2 = g.getValue(s2.getObject());\r
482                                                 boolean eq = compareValue(v1, v2);\r
483                                                 if (!eq) {\r
484                                                         addModification(s1, s2);\r
485                                                         comparableStatements.map(s1, s2);\r
486                                                         comparableResources.map(s1.getObject(),s2.getObject());\r
487                                                 }\r
488                                         } else {\r
489                                                 compareProps(s1.getObject(), s2.getObject());\r
490                                         }\r
491                                 } else {\r
492                                         addModification(s1, s2);\r
493                                         comparableStatements.map(s1, s2);\r
494                                         comparableResources.map(s1.getObject(),s2.getObject());\r
495                                 }\r
496                                 i1++;\r
497                                 i2++;\r
498                                 break;\r
499                         }\r
500                         case -1:{\r
501                                 System.out.println("Compare Prop diff1s " + printStatement(g,s1));\r
502                                 addDeletion(s1);\r
503                                 i1++;\r
504                                 break;\r
505                         }\r
506                                 \r
507                         case 1:{\r
508                                 System.out.println("Compare Prop diff2s " + printStatement(g,s2));\r
509                                 addAddition(s2);\r
510                                 i2++;\r
511                                 break;\r
512                         }\r
513                         }\r
514                         \r
515                         \r
516                 }\r
517                 \r
518                 ss1.clear();\r
519                 ss2.clear();\r
520                 \r
521         }\r
522         \r
523         \r
524         public static boolean compareValue(Object v1, Object v2) {\r
525                 if (v1 instanceof Object[] && v2 instanceof Object[])\r
526                         return Arrays.deepEquals((Object[])v1, (Object[])v2);\r
527                 else if (v1 instanceof int[] && v2 instanceof int[]) \r
528                         return Arrays.equals((int[])v1, (int[])v2);\r
529                 else if (v1 instanceof float[] && v2 instanceof float[]) \r
530                         return Arrays.equals((float[])v1, (float[])v2);\r
531                 else if (v1 instanceof double[] && v2 instanceof double[]) \r
532                         return Arrays.equals((double[])v1, (double[])v2);\r
533                 else if (v1 instanceof long[] && v2 instanceof long[]) \r
534                         return  Arrays.equals((long[])v1, (long[])v2);\r
535                 else if (v1 instanceof byte[] && v2 instanceof byte[]) \r
536                         return Arrays.equals((byte[])v1, (byte[])v2);\r
537                 else if (v1 instanceof boolean[] && v2 instanceof boolean[]) \r
538                         return Arrays.equals((boolean[])v1, (boolean[])v2);\r
539                 else\r
540                         return v1.equals(v2);\r
541         }\r
542 \r
543         \r
544         \r
545         public static class PredicateComparator implements Comparator<Statement> {\r
546                 @Override\r
547                 public int compare(Statement o1, Statement o2) {\r
548                         if (o1.getPredicate().getResourceId() < o2.getPredicate().getResourceId())\r
549                                 return -1;\r
550                         if (o1.getPredicate().getResourceId() > o2.getPredicate().getResourceId())\r
551                                 return 1;\r
552                         return 0;\r
553                 }\r
554         }\r
555         \r
556         public static class FullStatementComparator implements Comparator<Statement> {\r
557                 @Override\r
558                 public int compare(Statement o1, Statement o2) {\r
559                         if (o1.getSubject().getResourceId() < o2.getSubject().getResourceId())\r
560                                 return -1;\r
561                         if (o1.getSubject().getResourceId() > o2.getSubject().getResourceId())\r
562                                 return 1;\r
563                         if (o1.getPredicate().getResourceId() < o2.getPredicate().getResourceId())\r
564                                 return -1;\r
565                         if (o1.getPredicate().getResourceId() > o2.getPredicate().getResourceId())\r
566                                 return 1;\r
567                         if (o1.getObject().getResourceId() < o2.getObject().getResourceId())\r
568                                 return -1;\r
569                         if (o1.getObject().getResourceId() > o2.getObject().getResourceId())\r
570                                 return 1;\r
571                         return 0;\r
572                 }\r
573         }\r
574         \r
575 \r
576         \r
577         public static class ResourceComparator implements Comparator<Resource> {\r
578                 @Override\r
579                 public int compare(Resource o1, Resource o2) {\r
580                         if (o1.getResourceId() < o2.getResourceId())\r
581                                 return -1;\r
582                         if (o1.getResourceId() > o2.getResourceId())\r
583                                 return 1;\r
584                         return 0;\r
585                 }\r
586         }\r
587         \r
588         \r
589 }\r