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.Enumeration; |
20 | |
import java.util.HashMap; |
21 | |
import java.util.Iterator; |
22 | |
import java.util.List; |
23 | |
import java.util.Map; |
24 | |
|
25 | |
import org.apache.commons.lang.builder.ToStringBuilder; |
26 | |
import org.apache.commons.lang.builder.ToStringStyle; |
27 | |
import org.apache.commons.lang.SystemUtils; |
28 | |
import org.apache.ojb.broker.Identity; |
29 | |
import org.apache.ojb.broker.OJBRuntimeException; |
30 | |
import org.apache.ojb.broker.OptimisticLockException; |
31 | |
import org.apache.ojb.broker.PersistenceBroker; |
32 | |
import org.apache.ojb.broker.accesslayer.ConnectionManagerIF; |
33 | |
import org.apache.ojb.broker.core.proxy.CollectionProxy; |
34 | |
import org.apache.ojb.broker.core.proxy.CollectionProxyDefaultImpl; |
35 | |
import org.apache.ojb.broker.core.proxy.IndirectionHandler; |
36 | |
import org.apache.ojb.broker.core.proxy.ProxyHelper; |
37 | |
import org.apache.ojb.broker.metadata.ClassDescriptor; |
38 | |
import org.apache.ojb.broker.metadata.CollectionDescriptor; |
39 | |
import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor; |
40 | |
import org.apache.ojb.broker.util.BrokerHelper; |
41 | |
import org.apache.ojb.broker.util.logging.Logger; |
42 | |
import org.apache.ojb.broker.util.logging.LoggerFactory; |
43 | |
import org.apache.ojb.odmg.link.LinkEntry; |
44 | |
import org.apache.ojb.odmg.link.LinkEntryMtoN; |
45 | |
import org.apache.ojb.odmg.states.StateOldClean; |
46 | |
import org.odmg.LockNotGrantedException; |
47 | |
import org.odmg.ODMGRuntimeException; |
48 | |
import org.odmg.Transaction; |
49 | |
import org.odmg.TransactionAbortedException; |
50 | |
|
51 | |
|
52 | |
|
53 | |
|
54 | |
|
55 | |
|
56 | |
|
57 | |
|
58 | |
|
59 | |
|
60 | |
|
61 | |
public class ObjectEnvelopeTable |
62 | |
{ |
63 | |
private Logger log = LoggerFactory.getLogger(ObjectEnvelopeTable.class); |
64 | |
private TransactionImpl transaction; |
65 | |
|
66 | |
|
67 | |
|
68 | |
|
69 | |
|
70 | |
|
71 | |
|
72 | |
private List newAssociatedIdentites = new ArrayList(); |
73 | |
private List m2nLinkList = new ArrayList(); |
74 | |
private List m2nUnlinkList = new ArrayList(); |
75 | |
private List markedForDeletionList = new ArrayList(); |
76 | |
private List markedForInsertList = new ArrayList(); |
77 | |
|
78 | |
|
79 | |
private Map mhtObjectEnvelopes = new HashMap(); |
80 | |
|
81 | |
|
82 | |
|
83 | |
|
84 | |
|
85 | |
|
86 | |
private ArrayList mvOrderOfIds = new ArrayList(); |
87 | |
|
88 | |
|
89 | |
private boolean needsCommit = false; |
90 | |
|
91 | |
|
92 | |
public ObjectEnvelopeTable(TransactionImpl myTransaction) |
93 | |
{ |
94 | |
transaction = myTransaction; |
95 | |
} |
96 | |
|
97 | |
TransactionImpl getTransaction() |
98 | |
{ |
99 | |
return transaction; |
100 | |
} |
101 | |
|
102 | |
|
103 | |
public void refresh() |
104 | |
{ |
105 | |
needsCommit = false; |
106 | |
mhtObjectEnvelopes = new HashMap(); |
107 | |
mvOrderOfIds = new ArrayList(); |
108 | |
afterWriteCleanup(); |
109 | |
} |
110 | |
|
111 | |
void afterWriteCleanup() |
112 | |
{ |
113 | |
m2nLinkList.clear(); |
114 | |
m2nUnlinkList.clear(); |
115 | |
newAssociatedIdentites.clear(); |
116 | |
markedForDeletionList.clear(); |
117 | |
markedForInsertList.clear(); |
118 | |
} |
119 | |
|
120 | |
|
121 | |
|
122 | |
|
123 | |
|
124 | |
|
125 | |
|
126 | |
public void writeObjects(boolean reuse) throws TransactionAbortedException, LockNotGrantedException |
127 | |
{ |
128 | |
PersistenceBroker broker = transaction.getBroker(); |
129 | |
ConnectionManagerIF connMan = broker.serviceConnectionManager(); |
130 | |
boolean saveBatchMode = connMan.isBatchMode(); |
131 | |
|
132 | |
try |
133 | |
{ |
134 | |
if(log.isDebugEnabled()) |
135 | |
{ |
136 | |
log.debug( |
137 | |
"PB is in internal tx: " |
138 | |
+ broker.isInTransaction() |
139 | |
+ " broker was: " |
140 | |
+ broker); |
141 | |
} |
142 | |
|
143 | |
if(!broker.isInTransaction()) |
144 | |
{ |
145 | |
log.error("PB associated with current odmg-tx is not in tx"); |
146 | |
throw new TransactionAbortedException("Underlying PB is not in tx, was begin call done before commit?"); |
147 | |
} |
148 | |
|
149 | |
|
150 | |
|
151 | |
|
152 | |
|
153 | |
|
154 | |
|
155 | |
connMan.setBatchMode(true); |
156 | |
|
157 | |
|
158 | |
|
159 | |
checkAllEnvelopes(broker); |
160 | |
|
161 | |
|
162 | |
cascadingDependents(); |
163 | |
|
164 | |
|
165 | |
|
166 | |
upgradeLockIfNeeded(); |
167 | |
|
168 | |
|
169 | |
reorder(); |
170 | |
|
171 | |
|
172 | |
|
173 | |
|
174 | |
|
175 | |
|
176 | |
|
177 | |
|
178 | |
writeAllEnvelopes(reuse); |
179 | |
|
180 | |
|
181 | |
connMan.executeBatch(); |
182 | |
|
183 | |
|
184 | |
prepareForReuse(reuse); |
185 | |
|
186 | |
|
187 | |
afterWriteCleanup(); |
188 | |
|
189 | |
} |
190 | |
catch(Exception e) |
191 | |
{ |
192 | |
connMan.clearBatch(); |
193 | |
|
194 | |
|
195 | |
|
196 | |
|
197 | |
|
198 | |
if(e instanceof OptimisticLockException) |
199 | |
{ |
200 | |
|
201 | |
log.error("Optimistic lock exception while write objects", e); |
202 | |
|
203 | |
Object sourceObject = ((OptimisticLockException) e).getSourceObject(); |
204 | |
throw new LockNotGrantedException("Optimistic lock exception occur, source object was (" + sourceObject + ")," + |
205 | |
" message was (" + e.getMessage() + ")"); |
206 | |
} |
207 | |
else if(!(e instanceof RuntimeException)) |
208 | |
{ |
209 | |
log.warn("Error while write objects for tx " + transaction, e); |
210 | |
throw new ODMGRuntimeException("Unexpected error while write objects: " + e.getMessage()); |
211 | |
} |
212 | |
else |
213 | |
{ |
214 | |
log.warn("Error while write objects for tx " + transaction, e); |
215 | |
throw (RuntimeException) e; |
216 | |
} |
217 | |
} |
218 | |
finally |
219 | |
{ |
220 | |
needsCommit = false; |
221 | |
connMan.setBatchMode(saveBatchMode); |
222 | |
} |
223 | |
} |
224 | |
|
225 | |
|
226 | |
private void writeAllEnvelopes(boolean reuse) |
227 | |
{ |
228 | |
|
229 | |
performM2NUnlinkEntries(); |
230 | |
|
231 | |
Iterator iter; |
232 | |
|
233 | |
iter = ((List) mvOrderOfIds.clone()).iterator(); |
234 | |
while(iter.hasNext()) |
235 | |
{ |
236 | |
ObjectEnvelope mod = (ObjectEnvelope) mhtObjectEnvelopes.get(iter.next()); |
237 | |
boolean insert = false; |
238 | |
if(needsCommit) |
239 | |
{ |
240 | |
insert = mod.needsInsert(); |
241 | |
mod.getModificationState().commit(mod); |
242 | |
if(reuse && insert) |
243 | |
{ |
244 | |
getTransaction().doSingleLock(mod.getClassDescriptor(), mod.getObject(), mod.getIdentity(), Transaction.WRITE); |
245 | |
} |
246 | |
} |
247 | |
|
248 | |
|
249 | |
|
250 | |
|
251 | |
|
252 | |
mod.cleanup(reuse, insert); |
253 | |
} |
254 | |
|
255 | |
performM2NLinkEntries(); |
256 | |
} |
257 | |
|
258 | |
|
259 | |
|
260 | |
|
261 | |
|
262 | |
|
263 | |
private void checkAllEnvelopes(PersistenceBroker broker) |
264 | |
{ |
265 | |
Iterator iter = ((List) mvOrderOfIds.clone()).iterator(); |
266 | |
while(iter.hasNext()) |
267 | |
{ |
268 | |
ObjectEnvelope mod = (ObjectEnvelope) mhtObjectEnvelopes.get(iter.next()); |
269 | |
|
270 | |
if(!mod.getModificationState().isTransient()) |
271 | |
{ |
272 | |
mod.markReferenceElements(broker); |
273 | |
} |
274 | |
} |
275 | |
} |
276 | |
|
277 | |
|
278 | |
|
279 | |
|
280 | |
|
281 | |
private void prepareForReuse(boolean reuse) |
282 | |
{ |
283 | |
if(reuse) |
284 | |
{ |
285 | |
|
286 | |
Iterator iter = ((List) mvOrderOfIds.clone()).iterator(); |
287 | |
while(iter.hasNext()) |
288 | |
{ |
289 | |
ObjectEnvelope mod = (ObjectEnvelope) mhtObjectEnvelopes.get(iter.next()); |
290 | |
if(!needsCommit || (mod.getModificationState() == StateOldClean.getInstance() |
291 | |
|| mod.getModificationState().isTransient())) |
292 | |
{ |
293 | |
|
294 | |
} |
295 | |
else |
296 | |
{ |
297 | |
mod.setModificationState(mod.getModificationState().markClean()); |
298 | |
} |
299 | |
} |
300 | |
} |
301 | |
} |
302 | |
|
303 | |
|
304 | |
|
305 | |
|
306 | |
|
307 | |
|
308 | |
private void upgradeLockIfNeeded() |
309 | |
{ |
310 | |
|
311 | |
Iterator iter = ((List) mvOrderOfIds.clone()).iterator(); |
312 | |
TransactionImpl tx = getTransaction(); |
313 | |
ObjectEnvelope mod; |
314 | |
while(iter.hasNext()) |
315 | |
{ |
316 | |
mod = (ObjectEnvelope) mhtObjectEnvelopes.get(iter.next()); |
317 | |
|
318 | |
if(!mod.getModificationState().isTransient()) |
319 | |
{ |
320 | |
|
321 | |
|
322 | |
|
323 | |
|
324 | |
if(!mod.needsInsert()) |
325 | |
{ |
326 | |
if((mod.needsDelete() || mod.needsUpdate() |
327 | |
|| mod.hasChanged(tx.getBroker()))) |
328 | |
{ |
329 | |
needsCommit = true; |
330 | |
|
331 | |
mod.setModificationState(mod.getModificationState().markDirty()); |
332 | |
ClassDescriptor cld = mod.getClassDescriptor(); |
333 | |
|
334 | |
if(!mod.isWriteLocked()) |
335 | |
{ |
336 | |
tx.doSingleLock(cld, mod.getObject(), mod.getIdentity(), Transaction.WRITE); |
337 | |
} |
338 | |
} |
339 | |
} |
340 | |
else |
341 | |
{ |
342 | |
needsCommit = true; |
343 | |
} |
344 | |
} |
345 | |
} |
346 | |
} |
347 | |
|
348 | |
|
349 | |
public void rollback() |
350 | |
{ |
351 | |
try |
352 | |
{ |
353 | |
Iterator iter = mvOrderOfIds.iterator(); |
354 | |
while(iter.hasNext()) |
355 | |
{ |
356 | |
ObjectEnvelope mod = (ObjectEnvelope) mhtObjectEnvelopes.get(iter.next()); |
357 | |
if(log.isDebugEnabled()) |
358 | |
log.debug("rollback: " + mod); |
359 | |
|
360 | |
if(mod.hasChanged(transaction.getBroker())) |
361 | |
{ |
362 | |
mod.setModificationState(mod.getModificationState().markDirty()); |
363 | |
} |
364 | |
mod.getModificationState().rollback(mod); |
365 | |
} |
366 | |
} |
367 | |
finally |
368 | |
{ |
369 | |
needsCommit = false; |
370 | |
} |
371 | |
afterWriteCleanup(); |
372 | |
} |
373 | |
|
374 | |
|
375 | |
public void remove(Object pKey) |
376 | |
{ |
377 | |
Identity id; |
378 | |
if(pKey instanceof Identity) |
379 | |
{ |
380 | |
id = (Identity) pKey; |
381 | |
} |
382 | |
else |
383 | |
{ |
384 | |
id = transaction.getBroker().serviceIdentity().buildIdentity(pKey); |
385 | |
} |
386 | |
mhtObjectEnvelopes.remove(id); |
387 | |
mvOrderOfIds.remove(id); |
388 | |
} |
389 | |
|
390 | |
|
391 | |
|
392 | |
|
393 | |
|
394 | |
|
395 | |
|
396 | |
public Enumeration elements() |
397 | |
{ |
398 | |
return java.util.Collections.enumeration(mhtObjectEnvelopes.values()); |
399 | |
} |
400 | |
|
401 | |
|
402 | |
public ObjectEnvelope getByIdentity(Identity id) |
403 | |
{ |
404 | |
return (ObjectEnvelope) mhtObjectEnvelopes.get(id); |
405 | |
} |
406 | |
|
407 | |
|
408 | |
|
409 | |
|
410 | |
|
411 | |
|
412 | |
|
413 | |
public ObjectEnvelope get(Object pKey, boolean isNew) |
414 | |
{ |
415 | |
PersistenceBroker broker = transaction.getBroker(); |
416 | |
Identity oid = broker.serviceIdentity().buildIdentity(pKey); |
417 | |
return get(oid, pKey, isNew); |
418 | |
} |
419 | |
|
420 | |
|
421 | |
|
422 | |
|
423 | |
|
424 | |
|
425 | |
|
426 | |
public ObjectEnvelope get(Identity oid, Object pKey, boolean isNew) |
427 | |
{ |
428 | |
ObjectEnvelope result = getByIdentity(oid); |
429 | |
if(result == null) |
430 | |
{ |
431 | |
result = new ObjectEnvelope(this, oid, pKey, isNew); |
432 | |
mhtObjectEnvelopes.put(oid, result); |
433 | |
mvOrderOfIds.add(oid); |
434 | |
if(log.isDebugEnabled()) |
435 | |
log.debug("register: " + result); |
436 | |
} |
437 | |
return result; |
438 | |
} |
439 | |
|
440 | |
|
441 | |
public String toString() |
442 | |
{ |
443 | |
ToStringBuilder buf = new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE); |
444 | |
String eol = SystemUtils.LINE_SEPARATOR; |
445 | |
buf.append("# ObjectEnvelopeTable dump:" + eol + "start["); |
446 | |
Enumeration en = elements(); |
447 | |
while(en.hasMoreElements()) |
448 | |
{ |
449 | |
ObjectEnvelope mod = (ObjectEnvelope) en.nextElement(); |
450 | |
buf.append(mod.toString() + eol); |
451 | |
} |
452 | |
buf.append("]end"); |
453 | |
return buf.toString(); |
454 | |
} |
455 | |
|
456 | |
|
457 | |
public boolean contains(Identity oid) |
458 | |
{ |
459 | |
|
460 | |
return mhtObjectEnvelopes.containsKey(oid); |
461 | |
} |
462 | |
|
463 | |
|
464 | |
private void reorder() |
465 | |
{ |
466 | |
if(getTransaction().isOrdering() && needsCommit && mhtObjectEnvelopes.size() > 1) |
467 | |
{ |
468 | |
ObjectEnvelopeOrdering ordering = new ObjectEnvelopeOrdering(mvOrderOfIds, mhtObjectEnvelopes); |
469 | |
ordering.reorder(); |
470 | |
Identity[] newOrder = ordering.getOrdering(); |
471 | |
|
472 | |
mvOrderOfIds.clear(); |
473 | |
for(int i = 0; i < newOrder.length; i++) |
474 | |
{ |
475 | |
mvOrderOfIds.add(newOrder[i]); |
476 | |
} |
477 | |
} |
478 | |
} |
479 | |
|
480 | |
void cascadingDependents() |
481 | |
{ |
482 | |
Iterator it = mhtObjectEnvelopes.values().iterator(); |
483 | |
ObjectEnvelope mod; |
484 | |
|
485 | |
while(it.hasNext()) |
486 | |
{ |
487 | |
mod = (ObjectEnvelope) it.next(); |
488 | |
if(mod.needsDelete()) |
489 | |
{ |
490 | |
addForDeletionDependent(mod); |
491 | |
} |
492 | |
else if(mod.needsInsert()) |
493 | |
{ |
494 | |
addForInsertDependent(mod); |
495 | |
} |
496 | |
} |
497 | |
|
498 | |
|
499 | |
|
500 | |
|
501 | |
|
502 | |
|
503 | |
|
504 | |
cascadeMarkedForDeletion(); |
505 | |
cascadeMarkedForInsert(); |
506 | |
} |
507 | |
|
508 | |
void addNewAssociatedIdentity(Identity oid) |
509 | |
{ |
510 | |
newAssociatedIdentites.add(oid); |
511 | |
} |
512 | |
|
513 | |
boolean isNewAssociatedObject(Identity oid) |
514 | |
{ |
515 | |
return newAssociatedIdentites.contains(oid); |
516 | |
} |
517 | |
|
518 | |
void addForInsertDependent(ObjectEnvelope mod) |
519 | |
{ |
520 | |
markedForInsertList.add(mod); |
521 | |
} |
522 | |
|
523 | |
|
524 | |
private void cascadeMarkedForInsert() |
525 | |
{ |
526 | |
|
527 | |
List alreadyPrepared = new ArrayList(); |
528 | |
for(int i = 0; i < markedForInsertList.size(); i++) |
529 | |
{ |
530 | |
ObjectEnvelope mod = (ObjectEnvelope) markedForInsertList.get(i); |
531 | |
|
532 | |
if(mod.needsInsert()) |
533 | |
{ |
534 | |
cascadeInsertFor(mod, alreadyPrepared); |
535 | |
alreadyPrepared.clear(); |
536 | |
} |
537 | |
} |
538 | |
markedForInsertList.clear(); |
539 | |
} |
540 | |
|
541 | |
|
542 | |
|
543 | |
|
544 | |
|
545 | |
private void cascadeInsertFor(ObjectEnvelope mod, List alreadyPrepared) |
546 | |
{ |
547 | |
|
548 | |
if(alreadyPrepared.contains(mod.getIdentity())) return; |
549 | |
alreadyPrepared.add(mod.getIdentity()); |
550 | |
|
551 | |
ClassDescriptor cld = getTransaction().getBroker().getClassDescriptor(mod.getObject().getClass()); |
552 | |
|
553 | |
List refs = cld.getObjectReferenceDescriptors(true); |
554 | |
cascadeInsertSingleReferences(mod, refs, alreadyPrepared); |
555 | |
|
556 | |
List colls = cld.getCollectionDescriptors(true); |
557 | |
cascadeInsertCollectionReferences(mod, colls, alreadyPrepared); |
558 | |
} |
559 | |
|
560 | |
private void cascadeInsertSingleReferences(ObjectEnvelope source, List descriptor, List alreadyPrepared) |
561 | |
{ |
562 | |
for(int i = 0; i < descriptor.size(); i++) |
563 | |
{ |
564 | |
ObjectReferenceDescriptor ord = (ObjectReferenceDescriptor) descriptor.get(i); |
565 | |
Object depObj = ord.getPersistentField().get(source.getObject()); |
566 | |
|
567 | |
if(depObj != null) |
568 | |
{ |
569 | |
|
570 | |
source.addLinkOneToOne(ord, false); |
571 | |
|
572 | |
IndirectionHandler handler = ProxyHelper.getIndirectionHandler(depObj); |
573 | |
|
574 | |
if(handler == null || handler.alreadyMaterialized()) |
575 | |
{ |
576 | |
RuntimeObject rt; |
577 | |
|
578 | |
if(handler != null) |
579 | |
{ |
580 | |
rt = new RuntimeObject(handler.getRealSubject(), getTransaction(), false); |
581 | |
} |
582 | |
else |
583 | |
{ |
584 | |
rt = new RuntimeObject(depObj, getTransaction()); |
585 | |
} |
586 | |
Identity oid = rt.getIdentity(); |
587 | |
if(!alreadyPrepared.contains(oid)) |
588 | |
{ |
589 | |
ObjectEnvelope depMod = getByIdentity(oid); |
590 | |
|
591 | |
|
592 | |
if(depMod == null && rt.isNew()) |
593 | |
{ |
594 | |
getTransaction().lockAndRegister(rt, Transaction.WRITE, false, getTransaction().getRegistrationList()); |
595 | |
depMod = getByIdentity(oid); |
596 | |
cascadeInsertFor(depMod, alreadyPrepared); |
597 | |
} |
598 | |
} |
599 | |
} |
600 | |
} |
601 | |
} |
602 | |
} |
603 | |
|
604 | |
private void cascadeInsertCollectionReferences(ObjectEnvelope source, List descriptor, List alreadyPrepared) |
605 | |
{ |
606 | |
|
607 | |
for(int i = 0; i < descriptor.size(); i++) |
608 | |
{ |
609 | |
CollectionDescriptor col = (CollectionDescriptor) descriptor.get(i); |
610 | |
Object collOrArray = col.getPersistentField().get(source.getObject()); |
611 | |
CollectionProxy proxy = ProxyHelper.getCollectionProxy(collOrArray); |
612 | |
|
613 | |
|
614 | |
|
615 | |
|
616 | |
|
617 | |
if(proxy == null && collOrArray != null) |
618 | |
{ |
619 | |
Iterator it = BrokerHelper.getCollectionIterator(collOrArray); |
620 | |
while(it.hasNext()) |
621 | |
{ |
622 | |
Object colObj = it.next(); |
623 | |
if(colObj != null) |
624 | |
{ |
625 | |
RuntimeObject rt = new RuntimeObject(colObj, getTransaction()); |
626 | |
Identity oid = rt.getIdentity(); |
627 | |
|
628 | |
|
629 | |
|
630 | |
|
631 | |
|
632 | |
|
633 | |
if(source.needsInsert()) |
634 | |
{ |
635 | |
|
636 | |
|
637 | |
|
638 | |
|
639 | |
|
640 | |
|
641 | |
|
642 | |
colObj = ProxyHelper.getRealObject(colObj); |
643 | |
ObjectEnvelope oe = getByIdentity(oid); |
644 | |
if(oe == null) |
645 | |
{ |
646 | |
getTransaction().lockAndRegister(rt, Transaction.WRITE, false, getTransaction().getRegistrationList()); |
647 | |
oe = getByIdentity(oid); |
648 | |
} |
649 | |
if(col.isMtoNRelation()) |
650 | |
{ |
651 | |
|
652 | |
addM2NLinkEntry(col, source.getObject(), colObj); |
653 | |
} |
654 | |
else |
655 | |
{ |
656 | |
|
657 | |
oe.addLinkOneToN(col, source.getObject(), false); |
658 | |
|
659 | |
|
660 | |
|
661 | |
|
662 | |
oe.setModificationState(oe.getModificationState().markDirty()); |
663 | |
} |
664 | |
cascadeInsertFor(oe, alreadyPrepared); |
665 | |
} |
666 | |
} |
667 | |
} |
668 | |
} |
669 | |
} |
670 | |
} |
671 | |
|
672 | |
void addForDeletionDependent(ObjectEnvelope mod) |
673 | |
{ |
674 | |
markedForDeletionList.add(mod); |
675 | |
} |
676 | |
|
677 | |
|
678 | |
private void cascadeMarkedForDeletion() |
679 | |
{ |
680 | |
List alreadyPrepared = new ArrayList(); |
681 | |
for(int i = 0; i < markedForDeletionList.size(); i++) |
682 | |
{ |
683 | |
ObjectEnvelope mod = (ObjectEnvelope) markedForDeletionList.get(i); |
684 | |
|
685 | |
if(!isNewAssociatedObject(mod.getIdentity())) |
686 | |
{ |
687 | |
cascadeDeleteFor(mod, alreadyPrepared); |
688 | |
alreadyPrepared.clear(); |
689 | |
} |
690 | |
} |
691 | |
markedForDeletionList.clear(); |
692 | |
} |
693 | |
|
694 | |
|
695 | |
|
696 | |
|
697 | |
|
698 | |
private void cascadeDeleteFor(ObjectEnvelope mod, List alreadyPrepared) |
699 | |
{ |
700 | |
|
701 | |
if(alreadyPrepared.contains(mod.getIdentity())) return; |
702 | |
|
703 | |
alreadyPrepared.add(mod.getIdentity()); |
704 | |
|
705 | |
ClassDescriptor cld = getTransaction().getBroker().getClassDescriptor(mod.getObject().getClass()); |
706 | |
|
707 | |
List refs = cld.getObjectReferenceDescriptors(true); |
708 | |
cascadeDeleteSingleReferences(mod, refs, alreadyPrepared); |
709 | |
|
710 | |
List colls = cld.getCollectionDescriptors(true); |
711 | |
cascadeDeleteCollectionReferences(mod, colls, alreadyPrepared); |
712 | |
} |
713 | |
|
714 | |
private void cascadeDeleteSingleReferences(ObjectEnvelope source, List descriptor, List alreadyPrepared) |
715 | |
{ |
716 | |
for(int i = 0; i < descriptor.size(); i++) |
717 | |
{ |
718 | |
ObjectReferenceDescriptor ord = (ObjectReferenceDescriptor) descriptor.get(i); |
719 | |
if(getTransaction().cascadeDeleteFor(ord)) |
720 | |
{ |
721 | |
Object depObj = ord.getPersistentField().get(source.getObject()); |
722 | |
if(depObj != null) |
723 | |
{ |
724 | |
Identity oid = getTransaction().getBroker().serviceIdentity().buildIdentity(depObj); |
725 | |
|
726 | |
|
727 | |
if(!isNewAssociatedObject(oid)) |
728 | |
{ |
729 | |
ObjectEnvelope depMod = get(oid, depObj, false); |
730 | |
depMod.setModificationState(depMod.getModificationState().markDelete()); |
731 | |
cascadeDeleteFor(depMod, alreadyPrepared); |
732 | |
} |
733 | |
} |
734 | |
} |
735 | |
} |
736 | |
} |
737 | |
|
738 | |
private void cascadeDeleteCollectionReferences(ObjectEnvelope source, List descriptor, List alreadyPrepared) |
739 | |
{ |
740 | |
PersistenceBroker pb = getTransaction().getBroker(); |
741 | |
for(int i = 0; i < descriptor.size(); i++) |
742 | |
{ |
743 | |
CollectionDescriptor col = (CollectionDescriptor) descriptor.get(i); |
744 | |
boolean cascadeDelete = getTransaction().cascadeDeleteFor(col); |
745 | |
Object collOrArray = col.getPersistentField().get(source.getObject()); |
746 | |
|
747 | |
CollectionProxyDefaultImpl proxy = (CollectionProxyDefaultImpl) ProxyHelper.getCollectionProxy(collOrArray); |
748 | |
|
749 | |
if(proxy != null) |
750 | |
{ |
751 | |
collOrArray = proxy.getData(); |
752 | |
} |
753 | |
if(collOrArray != null) |
754 | |
{ |
755 | |
Iterator it = BrokerHelper.getCollectionIterator(collOrArray); |
756 | |
while(it.hasNext()) |
757 | |
{ |
758 | |
Object colObj = ProxyHelper.getRealObject(it.next()); |
759 | |
Identity oid = pb.serviceIdentity().buildIdentity(colObj); |
760 | |
ObjectEnvelope colMod = get(oid, colObj, false); |
761 | |
if(cascadeDelete) |
762 | |
{ |
763 | |
colMod.setModificationState(colMod.getModificationState().markDelete()); |
764 | |
cascadeDeleteFor(colMod, alreadyPrepared); |
765 | |
} |
766 | |
else |
767 | |
{ |
768 | |
if(!col.isMtoNRelation()) |
769 | |
{ |
770 | |
colMod.addLinkOneToN(col, source.getObject(), true); |
771 | |
colMod.setModificationState(colMod.getModificationState().markDirty()); |
772 | |
} |
773 | |
} |
774 | |
if(col.isMtoNRelation()) |
775 | |
{ |
776 | |
addM2NUnlinkEntry(col, source.getObject(), colObj); |
777 | |
} |
778 | |
} |
779 | |
} |
780 | |
} |
781 | |
} |
782 | |
|
783 | |
void addM2NLinkEntry(CollectionDescriptor cod, Object leftSource, Object rightSource) |
784 | |
{ |
785 | |
if(!cod.isMtoNRelation()) throw new OJBRuntimeException("Expect a m:n releation, but specified a 1:n"); |
786 | |
m2nLinkList.add(new LinkEntryMtoN(leftSource, cod, rightSource, false)); |
787 | |
} |
788 | |
|
789 | |
void performM2NLinkEntries() |
790 | |
{ |
791 | |
PersistenceBroker broker = getTransaction().getBroker(); |
792 | |
LinkEntry entry; |
793 | |
for(int i = 0; i < m2nLinkList.size(); i++) |
794 | |
{ |
795 | |
entry = (LinkEntry) m2nLinkList.get(i); |
796 | |
entry.execute(broker); |
797 | |
} |
798 | |
} |
799 | |
|
800 | |
void addM2NUnlinkEntry(CollectionDescriptor cod, Object leftSource, Object rightSource) |
801 | |
{ |
802 | |
if(!cod.isMtoNRelation()) throw new OJBRuntimeException("Expect a m:n releation, but specified a 1:n"); |
803 | |
m2nUnlinkList.add(new LinkEntryMtoN(leftSource, cod, rightSource, true)); |
804 | |
} |
805 | |
|
806 | |
void performM2NUnlinkEntries() |
807 | |
{ |
808 | |
PersistenceBroker broker = getTransaction().getBroker(); |
809 | |
LinkEntry entry; |
810 | |
for(int i = 0; i < m2nUnlinkList.size(); i++) |
811 | |
{ |
812 | |
entry = (LinkEntry) m2nUnlinkList.get(i); |
813 | |
entry.execute(broker); |
814 | |
} |
815 | |
} |
816 | |
|
817 | |
|
818 | |
|
819 | |
|
820 | |
|
821 | |
|
822 | |
|
823 | |
|
824 | |
|
825 | |
boolean replaceRegisteredIdentity(Identity newOid, Identity oldOid) |
826 | |
{ |
827 | |
|
828 | |
|
829 | |
|
830 | |
boolean result = false; |
831 | |
Object oe = mhtObjectEnvelopes.remove(oldOid); |
832 | |
if(oe != null) |
833 | |
{ |
834 | |
mhtObjectEnvelopes.put(newOid, oe); |
835 | |
int index = mvOrderOfIds.indexOf(oldOid); |
836 | |
mvOrderOfIds.remove(index); |
837 | |
mvOrderOfIds.add(index, newOid); |
838 | |
result = true; |
839 | |
if(log.isDebugEnabled()) log.debug("Replace identity: " + oldOid + " --replaced-by--> " + newOid); |
840 | |
} |
841 | |
else |
842 | |
{ |
843 | |
log.warn("Can't replace unregistered object identity (" + oldOid + ") with new identity (" + newOid + ")"); |
844 | |
} |
845 | |
return result; |
846 | |
} |
847 | |
} |