1 package org.apache.ojb.odmg;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 import java.util.ArrayList;
19 import java.util.Iterator;
20 import java.util.List;
21 import java.util.Map;
22
23 import org.apache.commons.lang.ArrayUtils;
24 import org.apache.commons.lang.builder.ToStringBuilder;
25 import org.apache.ojb.broker.Identity;
26 import org.apache.ojb.broker.core.proxy.ProxyHelper;
27 import org.apache.ojb.broker.metadata.ClassDescriptor;
28 import org.apache.ojb.broker.metadata.CollectionDescriptor;
29 import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor;
30 import org.apache.ojb.broker.util.BrokerHelper;
31 import org.apache.ojb.broker.util.logging.Logger;
32 import org.apache.ojb.broker.util.logging.LoggerFactory;
33 import org.apache.ojb.odmg.states.ModificationState;
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78 class ObjectEnvelopeOrdering
79 {
80 private static final int CONCRETE_EDGE_WEIGHT = 3;
81 private static final int CONCRETE_EDGE_WEIGHT_WITH_FK = 4;
82 private static final int POTENTIAL_EDGE_WEIGHT = 1;
83 private static final int POTENTIAL_EDGE_WEIGHT_WITH_FK = 2;
84 private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
85
86 private static Logger log = LoggerFactory.getLogger(ObjectEnvelopeOrdering.class);
87
88 private List originalOrder;
89 private Map envelopes;
90
91 private Vertex[] vertices;
92 private List edgeList;
93
94 private Identity[] newOrder;
95
96
97
98
99
100
101
102
103 public ObjectEnvelopeOrdering(List originalOrder, Map envelopes)
104 {
105 this.originalOrder = originalOrder;
106 this.envelopes = envelopes;
107 }
108
109
110
111
112
113
114 public void reorder()
115 {
116 int newOrderIndex = 0;
117 long t1 = 0, t2 = 0, t3;
118
119 if (log.isDebugEnabled())
120 {
121 t1 = System.currentTimeMillis();
122 }
123 newOrder = new Identity[originalOrder.size()];
124
125 if(log.isDebugEnabled()) log.debug("Orginal order: " + originalOrder);
126
127 List vertexList = new ArrayList(originalOrder.size());
128
129 for (Iterator it = originalOrder.iterator(); it.hasNext();)
130 {
131 ObjectEnvelope envelope = (ObjectEnvelope) envelopes.get(it.next());
132 if (envelope.needsUpdate() || envelope.needsInsert() || envelope.needsDelete())
133 {
134 Vertex vertex = new Vertex(envelope);
135 vertexList.add(vertex);
136 if (log.isDebugEnabled())
137 {
138 log.debug("Add new Vertex object "+envelope.getIdentity()+" to VertexList");
139 }
140 }
141 else
142 {
143
144 newOrder[newOrderIndex++] = envelope.getIdentity();
145 if (log.isDebugEnabled())
146 {
147 log.debug("Add unmodified object "+envelope.getIdentity()+" to new OrderList");
148 }
149 }
150 }
151 vertices = (Vertex[]) vertexList.toArray(new Vertex[vertexList.size()]);
152
153
154 edgeList = new ArrayList(2 * vertices.length);
155 for (int i = 0; i < vertices.length; i++)
156 {
157 addEdgesForVertex(vertices[i]);
158 }
159
160 if (log.isDebugEnabled())
161 {
162 t2 = System.currentTimeMillis();
163 log.debug("Building object envelope graph took " + (t2 - t1) + " ms");
164 log.debug("Object envelope graph contains " + vertices.length + " vertices" + " and " + edgeList.size()
165 + " edges");
166 }
167
168 int remainingVertices = vertices.length;
169 int iterationCount = 0;
170 while (remainingVertices > 0)
171 {
172
173 iterationCount++;
174
175
176 for (Iterator it = edgeList.iterator(); it.hasNext();)
177 {
178 Edge edge = (Edge) it.next();
179 if (!edge.isProcessed())
180 {
181 if(log.isDebugEnabled())
182 {
183 final String msg = "Add weight '"+edge.getWeight()+"' for terminal vertex " + edge.getTerminalVertex() + " of edge " + edge;
184 log.debug(msg);
185 }
186 edge.getTerminalVertex().incrementIncomingEdgeWeight(edge.getWeight());
187 }
188 }
189
190
191 int minIncomingEdgeWeight = Integer.MAX_VALUE;
192 for (int i = 0; i < vertices.length; i++)
193 {
194 Vertex vertex = vertices[i];
195 if (!vertex.isProcessed() && minIncomingEdgeWeight > vertex.getIncomingEdgeWeight())
196 {
197 minIncomingEdgeWeight = vertex.getIncomingEdgeWeight();
198 if (minIncomingEdgeWeight == 0)
199 {
200
201 break;
202 }
203 }
204 }
205
206
207 int processCount = 0;
208 for (int i = 0; i < vertices.length; i++)
209 {
210 Vertex vertex = vertices[i];
211 if (!vertex.isProcessed() && vertex.getIncomingEdgeWeight() == minIncomingEdgeWeight)
212 {
213 newOrder[newOrderIndex++] = vertex.getEnvelope().getIdentity();
214 vertex.markProcessed();
215 processCount++;
216 if (log.isDebugEnabled())
217 {
218 log.debug("add minimum edge weight - "+minIncomingEdgeWeight
219 + ", newOrderList: " + ArrayUtils.toString(newOrder));
220 }
221 }
222 vertex.resetIncomingEdgeWeight();
223 }
224
225 if (log.isDebugEnabled())
226 {
227 log.debug("Processed " + processCount + " of " + remainingVertices
228 + " remaining vertices in iteration #" + iterationCount);
229 }
230 remainingVertices -= processCount;
231 }
232
233 if (log.isDebugEnabled())
234 {
235 t3 = System.currentTimeMillis();
236 log.debug("New ordering: " + ArrayUtils.toString(newOrder));
237 log.debug("Processing object envelope graph took " + (t3 - t2) + " ms");
238 }
239
240 }
241
242
243
244
245
246
247 public Identity[] getOrdering()
248 {
249 if (newOrder == null)
250 {
251 reorder();
252 }
253 return newOrder;
254 }
255
256
257
258
259
260
261 private void addEdgesForVertex(Vertex vertex)
262 {
263 ClassDescriptor cld = vertex.getEnvelope().getClassDescriptor();
264 Iterator rdsIter = cld.getObjectReferenceDescriptors(true).iterator();
265 while (rdsIter.hasNext())
266 {
267 ObjectReferenceDescriptor rds = (ObjectReferenceDescriptor) rdsIter.next();
268 addObjectReferenceEdges(vertex, rds);
269 }
270 Iterator cdsIter = cld.getCollectionDescriptors(true).iterator();
271 while (cdsIter.hasNext())
272 {
273 CollectionDescriptor cds = (CollectionDescriptor) cdsIter.next();
274 addCollectionEdges(vertex, cds);
275 }
276 }
277
278
279
280
281
282
283
284 private void addObjectReferenceEdges(Vertex vertex, ObjectReferenceDescriptor rds)
285 {
286 Object refObject = rds.getPersistentField().get(vertex.getEnvelope().getRealObject());
287 Class refClass = rds.getItemClass();
288 for (int i = 0; i < vertices.length; i++)
289 {
290 Edge edge = null;
291
292 Vertex refVertex = vertices[i];
293 ObjectEnvelope refEnvelope = refVertex.getEnvelope();
294 if (refObject == refEnvelope.getRealObject())
295 {
296 edge = buildConcrete11Edge(vertex, refVertex, rds.hasConstraint());
297 }
298 else if (refClass.isInstance(refVertex.getEnvelope().getRealObject()))
299 {
300 edge = buildPotential11Edge(vertex, refVertex, rds.hasConstraint());
301 }
302 if (edge != null)
303 {
304 if (!edgeList.contains(edge))
305 {
306 edgeList.add(edge);
307 }
308 else
309 {
310 edge.increaseWeightTo(edge.getWeight());
311 }
312 }
313 }
314 }
315
316
317
318
319
320
321
322 private void addCollectionEdges(Vertex vertex, CollectionDescriptor cds)
323 {
324 ObjectEnvelope envelope = vertex.getEnvelope();
325 Object col = cds.getPersistentField().get(envelope.getRealObject());
326 Object[] refObjects;
327 if (col == null || (ProxyHelper.isCollectionProxy(col) && !ProxyHelper.getCollectionProxy(col).isLoaded()))
328 {
329 refObjects = EMPTY_OBJECT_ARRAY;
330 }
331 else
332 {
333 refObjects = BrokerHelper.getCollectionArray(col);
334 }
335 Class refClass = cds.getItemClass();
336
337 for (int i = 0; i < vertices.length; i++)
338 {
339 Edge edge = null;
340 Vertex refVertex = vertices[i];
341 ObjectEnvelope refEnvelope = refVertex.getEnvelope();
342
343 if (refClass.isInstance(refEnvelope.getRealObject()))
344 {
345 if (containsObject(refEnvelope.getRealObject(), refObjects))
346 {
347 if (cds.isMtoNRelation())
348 {
349 edge = buildConcreteMNEdge(vertex, refVertex);
350 }
351 else
352 {
353 edge = buildConcrete1NEdge(vertex, refVertex);
354 }
355 }
356 else
357 {
358 if (cds.isMtoNRelation())
359 {
360 edge = buildPotentialMNEdge(vertex, refVertex);
361 }
362 else
363 {
364 edge = buildPotential1NEdge(vertex, refVertex);
365 }
366 }
367 }
368 if (edge != null)
369 {
370 if (!edgeList.contains(edge))
371 {
372 edgeList.add(edge);
373 }
374 else
375 {
376 edge.increaseWeightTo(edge.getWeight());
377 }
378 }
379 }
380 }
381
382
383
384
385
386
387
388
389 private static boolean containsObject(Object searchFor, Object[] searchIn)
390 {
391 for (int i = 0; i < searchIn.length; i++)
392 {
393 if (searchFor == searchIn[i])
394 {
395 return true;
396 }
397 }
398 return false;
399 }
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424 protected Edge buildConcrete11Edge(Vertex vertex1, Vertex vertex2, boolean fkToRef)
425 {
426 ModificationState state1 = vertex1.getEnvelope().getModificationState();
427 ModificationState state2 = vertex2.getEnvelope().getModificationState();
428 if (state1.needsUpdate() || state1.needsInsert())
429 {
430 if (state2.needsInsert())
431 {
432
433 return new Edge(vertex2, vertex1, fkToRef ? CONCRETE_EDGE_WEIGHT_WITH_FK : CONCRETE_EDGE_WEIGHT);
434 }
435 }
436 else if (state1.needsDelete())
437 {
438 if (state2.needsDelete())
439 {
440
441 return new Edge(vertex1, vertex2, fkToRef ? CONCRETE_EDGE_WEIGHT_WITH_FK : CONCRETE_EDGE_WEIGHT);
442 }
443 }
444 return null;
445 }
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473 protected Edge buildPotential11Edge(Vertex vertex1, Vertex vertex2, boolean fkToRef)
474 {
475 ModificationState state1 = vertex1.getEnvelope().getModificationState();
476 ModificationState state2 = vertex2.getEnvelope().getModificationState();
477 if (state1.needsUpdate() || state1.needsDelete())
478 {
479 if (state2.needsDelete())
480 {
481
482 return new Edge(vertex1, vertex2, fkToRef ? POTENTIAL_EDGE_WEIGHT_WITH_FK : POTENTIAL_EDGE_WEIGHT);
483 }
484 }
485 return null;
486 }
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513 protected Edge buildConcrete1NEdge(Vertex vertex1, Vertex vertex2)
514 {
515 ModificationState state1 = vertex1.getEnvelope().getModificationState();
516 ModificationState state2 = vertex2.getEnvelope().getModificationState();
517 if (state1.needsInsert())
518 {
519 if (state2.needsUpdate() || state2.needsInsert())
520 {
521
522 return new Edge(vertex1, vertex2, CONCRETE_EDGE_WEIGHT);
523 }
524 }
525 else if (state1.needsDelete())
526 {
527 if (state2.needsUpdate() || state2.needsDelete())
528 {
529
530 return new Edge(vertex2, vertex1, CONCRETE_EDGE_WEIGHT);
531 }
532 }
533 return null;
534 }
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562 protected Edge buildPotential1NEdge(Vertex vertex1, Vertex vertex2)
563 {
564 ModificationState state1 = vertex1.getEnvelope().getModificationState();
565 ModificationState state2 = vertex2.getEnvelope().getModificationState();
566 if (state1.needsDelete())
567 {
568 if (state2.needsUpdate() || state2.needsDelete())
569 {
570
571
572 return new Edge(vertex2, vertex1, POTENTIAL_EDGE_WEIGHT);
573 }
574 }
575 return null;
576 }
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603 protected Edge buildConcreteMNEdge(Vertex vertex1, Vertex vertex2)
604 {
605 ModificationState state1 = vertex1.getEnvelope().getModificationState();
606 ModificationState state2 = vertex2.getEnvelope().getModificationState();
607 if (state1.needsUpdate() || state1.needsInsert())
608 {
609 if (state2.needsInsert())
610 {
611
612 return new Edge(vertex2, vertex1, CONCRETE_EDGE_WEIGHT);
613 }
614 }
615 else if (state1.needsDelete())
616 {
617 if (state2.needsDelete())
618 {
619
620
621 return new Edge(vertex1, vertex2, POTENTIAL_EDGE_WEIGHT);
622 }
623 }
624 return null;
625 }
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653 protected Edge buildPotentialMNEdge(Vertex vertex1, Vertex vertex2)
654 {
655 ModificationState state1 = vertex1.getEnvelope().getModificationState();
656 ModificationState state2 = vertex2.getEnvelope().getModificationState();
657 if (state1.needsUpdate() || state1.needsDelete())
658 {
659 if (state2.needsDelete())
660 {
661
662 return new Edge(vertex1, vertex2, POTENTIAL_EDGE_WEIGHT);
663 }
664 }
665 return null;
666 }
667
668
669
670
671 private static class Edge
672 {
673 private Vertex initial;
674 private Vertex terminal;
675 private Identity initialIdentity;
676 private Identity terminalIdentity;
677 private int weight;
678 private boolean knownToBeProcessed;
679 private int hashCode;
680
681 public Edge(Vertex initial, Vertex terminal, int weight)
682 {
683 this.initial = initial;
684 this.terminal = terminal;
685 this.initialIdentity = initial.getEnvelope().getIdentity();
686 this.terminalIdentity = terminal.getEnvelope().getIdentity();
687 this.weight = weight;
688 this.knownToBeProcessed = false;
689 this.hashCode = initialIdentity.hashCode() + 13 * terminalIdentity.hashCode();
690 }
691
692 public Vertex getInitialVertex()
693 {
694 return initial;
695 }
696
697 public Vertex getTerminalVertex()
698 {
699 return terminal;
700 }
701
702 public boolean connects(Vertex vertex)
703 {
704 return initial == vertex || terminal == vertex;
705 }
706
707 public void increaseWeightTo(int minWeight)
708 {
709 if (weight < minWeight)
710 {
711 weight = minWeight;
712 }
713 }
714
715 public int getWeight()
716 {
717 return weight;
718 }
719
720 public boolean isProcessed()
721 {
722 if (knownToBeProcessed)
723 {
724 return true;
725 }
726 else
727 {
728 boolean processed = initial.isProcessed() || terminal.isProcessed();
729 if (processed)
730 {
731 knownToBeProcessed = true;
732 }
733 return processed;
734 }
735 }
736
737 public boolean equals(Object obj)
738 {
739 if (obj instanceof Edge)
740 {
741 Edge other = (Edge) obj;
742 return this.initialIdentity.equals(other.initialIdentity)
743 && this.terminalIdentity.equals(other.terminalIdentity);
744 }
745 else
746 {
747 return false;
748 }
749 }
750
751 public int hashCode()
752 {
753 return hashCode;
754 }
755
756 public String toString()
757 {
758 return new ToStringBuilder(this)
759 .append("initial", initialIdentity)
760 .append("terminal", terminalIdentity)
761 .append("weight", weight)
762 .append("processed", knownToBeProcessed)
763 .toString();
764 }
765 }
766
767
768
769
770 private static class Vertex
771 {
772 private ObjectEnvelope envelope;
773 private boolean processed;
774 private int incomingEdgeWeight;
775
776 public Vertex(ObjectEnvelope envelope)
777 {
778 this.envelope = envelope;
779 this.incomingEdgeWeight = 0;
780 this.processed = false;
781 }
782
783 public ObjectEnvelope getEnvelope()
784 {
785 return envelope;
786 }
787
788 public void markProcessed()
789 {
790 processed = true;
791 }
792
793 public boolean isProcessed()
794 {
795 return processed;
796 }
797
798 public void resetIncomingEdgeWeight()
799 {
800 incomingEdgeWeight = 0;
801 }
802
803 public void incrementIncomingEdgeWeight(int weight)
804 {
805 incomingEdgeWeight += weight;
806 }
807
808 public int getIncomingEdgeWeight()
809 {
810 return incomingEdgeWeight;
811 }
812
813 public String toString()
814 {
815 return new ToStringBuilder(this)
816 .append("identity", envelope.getIdentity())
817 .append("processed", processed)
818 .append("incomingEdgeWeight", incomingEdgeWeight)
819 .toString();
820 }
821 }
822
823 }