1 | |
package org.apache.ojb.otm.core; |
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
|
15 | |
|
16 | |
|
17 | |
|
18 | |
import java.lang.reflect.Array; |
19 | |
import java.math.BigDecimal; |
20 | |
import java.util.ArrayList; |
21 | |
import java.util.Arrays; |
22 | |
import java.util.Collection; |
23 | |
import java.util.Comparator; |
24 | |
import java.util.Iterator; |
25 | |
import java.util.HashMap; |
26 | |
import java.util.HashSet; |
27 | |
import java.util.Date; |
28 | |
import java.util.List; |
29 | |
import java.util.Set; |
30 | |
import java.util.Stack; |
31 | |
|
32 | |
import org.apache.commons.collections.iterators.ArrayIterator; |
33 | |
import org.apache.ojb.broker.Identity; |
34 | |
import org.apache.ojb.broker.OJBRuntimeException; |
35 | |
import org.apache.ojb.broker.PBKey; |
36 | |
import org.apache.ojb.broker.PersistenceBroker; |
37 | |
import org.apache.ojb.broker.accesslayer.ConnectionManagerIF; |
38 | |
import org.apache.ojb.broker.cache.ObjectCache; |
39 | |
import org.apache.ojb.broker.core.proxy.CollectionProxyDefaultImpl; |
40 | |
import org.apache.ojb.broker.core.proxy.ListProxyDefaultImpl; |
41 | |
import org.apache.ojb.broker.core.proxy.SetProxyDefaultImpl; |
42 | |
import org.apache.ojb.broker.core.proxy.CollectionProxyListener; |
43 | |
import org.apache.ojb.broker.core.proxy.IndirectionHandler; |
44 | |
import org.apache.ojb.broker.core.proxy.MaterializationListener; |
45 | |
import org.apache.ojb.broker.core.proxy.ProxyHelper; |
46 | |
import org.apache.ojb.broker.metadata.ClassDescriptor; |
47 | |
import org.apache.ojb.broker.metadata.CollectionDescriptor; |
48 | |
import org.apache.ojb.broker.metadata.FieldDescriptor; |
49 | |
import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor; |
50 | |
import org.apache.ojb.broker.metadata.fieldaccess.PersistentField; |
51 | |
|
52 | |
import org.apache.ojb.otm.EditingContext; |
53 | |
import org.apache.ojb.otm.OTMKit; |
54 | |
import org.apache.ojb.otm.copy.ObjectCopyStrategy; |
55 | |
import org.apache.ojb.otm.lock.LockManager; |
56 | |
import org.apache.ojb.otm.lock.LockType; |
57 | |
import org.apache.ojb.otm.lock.LockingException; |
58 | |
import org.apache.ojb.otm.states.State; |
59 | |
import org.apache.ojb.otm.swizzle.Swizzling; |
60 | |
|
61 | |
|
62 | |
|
63 | |
|
64 | |
|
65 | |
|
66 | |
|
67 | |
|
68 | |
|
69 | |
public class ConcreteEditingContext |
70 | |
implements EditingContext, MaterializationListener, ObjectCache |
71 | |
{ |
72 | |
|
73 | |
|
74 | |
|
75 | |
private static HashMap _withBidirAsscMap = new HashMap(); |
76 | |
private static HashMap _withoutBidirAsscMap = new HashMap(); |
77 | |
|
78 | |
private HashSet _withBidirAssc; |
79 | |
private HashSet _withoutBidirAssc; |
80 | |
|
81 | |
private HashMap _objects; |
82 | |
private ArrayList _order; |
83 | |
private Transaction _tx; |
84 | |
private PersistenceBroker _pb; |
85 | |
private HashMap _original; |
86 | |
private HashMap _checkpointed; |
87 | |
private HashMap _colProxyListeners; |
88 | |
|
89 | |
|
90 | |
|
91 | |
|
92 | |
|
93 | |
public ConcreteEditingContext(Transaction tx, PersistenceBroker pb) |
94 | |
{ |
95 | |
PBKey pbkey; |
96 | |
|
97 | |
_tx = tx; |
98 | |
_pb = pb; |
99 | |
_objects = new HashMap(); |
100 | |
_order = new ArrayList(); |
101 | |
_original = new HashMap(); |
102 | |
_checkpointed = _original; |
103 | |
pbkey = _pb.getPBKey(); |
104 | |
_withoutBidirAssc = (HashSet) _withoutBidirAsscMap.get(pbkey); |
105 | |
if (_withoutBidirAssc != null) |
106 | |
{ |
107 | |
_withBidirAssc = (HashSet) _withBidirAsscMap.get(pbkey); |
108 | |
} |
109 | |
else |
110 | |
{ |
111 | |
_withoutBidirAssc = new HashSet(); |
112 | |
_withoutBidirAsscMap.put(pbkey, _withoutBidirAssc); |
113 | |
_withBidirAssc = new HashSet(); |
114 | |
_withBidirAsscMap.put(pbkey, _withBidirAssc); |
115 | |
} |
116 | |
} |
117 | |
|
118 | |
|
119 | |
|
120 | |
|
121 | |
|
122 | |
|
123 | |
|
124 | |
|
125 | |
public void insert(Identity oid, Object userObject, int lock) |
126 | |
throws LockingException |
127 | |
{ |
128 | |
ContextEntry entry; |
129 | |
|
130 | |
entry = insertInternal(oid, userObject, lock, true, null, new Stack()); |
131 | |
if ((entry != null) && entry.state.needsDelete()) { |
132 | |
|
133 | |
entry.state = State.PERSISTENT_CLEAN; |
134 | |
} |
135 | |
} |
136 | |
|
137 | |
private ContextEntry insertInternal(Identity oid, Object userObject, |
138 | |
int lock, boolean canCreate, Identity insertBeforeThis, Stack stack) |
139 | |
throws LockingException |
140 | |
{ |
141 | |
ContextEntry entry; |
142 | |
LockManager lockManager; |
143 | |
Swizzling swizzlingStrategy; |
144 | |
IndirectionHandler handler = null; |
145 | |
OTMKit kit = _tx.getKit(); |
146 | |
|
147 | |
|
148 | |
|
149 | |
boolean buildingObject = false; |
150 | |
boolean lazySwizzle = false; |
151 | |
|
152 | |
if (lock == LockType.NO_LOCK) |
153 | |
{ |
154 | |
return null; |
155 | |
} |
156 | |
|
157 | |
entry = (ContextEntry) _objects.get(oid); |
158 | |
|
159 | |
if (userObject == null) |
160 | |
{ |
161 | |
|
162 | |
_original.remove(oid); |
163 | |
_checkpointed.remove(oid); |
164 | |
if (entry != null) |
165 | |
{ |
166 | |
entry.userObject = null; |
167 | |
entry.cacheObject = null; |
168 | |
} |
169 | |
return entry; |
170 | |
} |
171 | |
|
172 | |
lockManager = LockManager.getInstance(); |
173 | |
swizzlingStrategy = kit.getSwizzlingStrategy(); |
174 | |
|
175 | |
handler = ProxyHelper.getIndirectionHandler(userObject); |
176 | |
if ((handler != null) && handler.alreadyMaterialized()) |
177 | |
{ |
178 | |
userObject = handler.getRealSubject(); |
179 | |
handler = null; |
180 | |
} |
181 | |
|
182 | |
if ((entry == null) || (entry.userObject == null)) |
183 | |
{ |
184 | |
|
185 | |
Object swizzledObject = swizzlingStrategy.swizzle(userObject, null, _pb, this); |
186 | |
entry = new ContextEntry(swizzledObject); |
187 | |
if (entry.handler != null) |
188 | |
{ |
189 | |
ObjectCopyStrategy copyStrategy = _tx.getKit().getCopyStrategy(oid); |
190 | |
entry.cacheObject = copyStrategy.copy(userObject, _pb); |
191 | |
|
192 | |
_objects.put(oid, entry); |
193 | |
lockManager.ensureLock(oid, _tx, lock, _pb); |
194 | |
entry.handler.addListener(this); |
195 | |
} |
196 | |
else |
197 | |
{ |
198 | |
Object origCacheObj = _pb.getObjectByIdentity(oid); |
199 | |
|
200 | |
if ((origCacheObj == null) && !canCreate) |
201 | |
{ |
202 | |
|
203 | |
throw new IllegalStateException("Related object is neither persistent, nor otm-depentent: " + oid); |
204 | |
} |
205 | |
if (origCacheObj != null) |
206 | |
{ |
207 | |
entry.cacheObject = origCacheObj; |
208 | |
} |
209 | |
buildingObject = true; |
210 | |
_objects.put(oid, entry); |
211 | |
lockManager.ensureLock(oid, _tx, lock, _pb); |
212 | |
|
213 | |
if (userObject != null) |
214 | |
{ |
215 | |
if ((origCacheObj == null) && canCreate) |
216 | |
{ |
217 | |
ObjectCopyStrategy copyStrategy = _tx.getKit().getCopyStrategy(oid); |
218 | |
entry.cacheObject = copyStrategy.copy(userObject, _pb); |
219 | |
entry.state = State.PERSISTENT_NEW; |
220 | |
if (kit.isEagerInsert(userObject) |
221 | |
|| hasBidirectionalAssociation(userObject.getClass())) |
222 | |
{ |
223 | |
_pb.store(entry.cacheObject, entry.state); |
224 | |
entry.state = State.PERSISTENT_CLEAN; |
225 | |
origCacheObj = entry.cacheObject; |
226 | |
} |
227 | |
} |
228 | |
|
229 | |
if (origCacheObj != null) |
230 | |
{ |
231 | |
_original.put(oid, getFields(userObject, false, true)); |
232 | |
} |
233 | |
} |
234 | |
} |
235 | |
if (insertBeforeThis != null) |
236 | |
{ |
237 | |
int insertIndex = _order.indexOf(insertBeforeThis); |
238 | |
_order.add(insertIndex, oid); |
239 | |
} |
240 | |
else |
241 | |
{ |
242 | |
_order.add(oid); |
243 | |
} |
244 | |
} |
245 | |
else |
246 | |
{ |
247 | |
|
248 | |
|
249 | |
lockManager.ensureLock(oid, _tx, lock, _pb); |
250 | |
|
251 | |
if (handler == null) |
252 | |
{ |
253 | |
if (!swizzlingStrategy.isSameInstance(entry.userObject, userObject)) |
254 | |
{ |
255 | |
|
256 | |
if (entry.handler != null) |
257 | |
{ |
258 | |
|
259 | |
|
260 | |
|
261 | |
entry.userObject = entry.handler.getRealSubject(); |
262 | |
entry.handler = null; |
263 | |
} |
264 | |
|
265 | |
|
266 | |
lazySwizzle = true; |
267 | |
} |
268 | |
} |
269 | |
} |
270 | |
|
271 | |
|
272 | |
|
273 | |
if ((handler == null) && !stack.contains(userObject)) |
274 | |
{ |
275 | |
stack.push(userObject); |
276 | |
lockReachableObjects(oid, userObject, entry.cacheObject, lock, stack, buildingObject); |
277 | |
stack.pop(); |
278 | |
if (lazySwizzle) |
279 | |
{ |
280 | |
entry.userObject = swizzlingStrategy.swizzle(userObject, entry.userObject, _pb, this); |
281 | |
} |
282 | |
} |
283 | |
|
284 | |
return entry; |
285 | |
} |
286 | |
|
287 | |
|
288 | |
|
289 | |
|
290 | |
|
291 | |
private void lockReachableObjects(Identity oid, Object userObject, |
292 | |
Object cacheObject, int lock, Stack stack, boolean buildingObject) |
293 | |
throws LockingException |
294 | |
{ |
295 | |
ContextEntry entry; |
296 | |
boolean onlyDependants = !_tx.getKit().isImplicitLockingUsed(); |
297 | |
ClassDescriptor mif = _pb.getClassDescriptor(userObject.getClass()); |
298 | |
|
299 | |
|
300 | |
Iterator iter = mif.getObjectReferenceDescriptors().iterator(); |
301 | |
ObjectReferenceDescriptor rds = null; |
302 | |
PersistentField f; |
303 | |
Object relUserObj; |
304 | |
Identity relOid; |
305 | |
boolean isDependent; |
306 | |
|
307 | |
while (iter.hasNext()) |
308 | |
{ |
309 | |
rds = (ObjectReferenceDescriptor) iter.next(); |
310 | |
isDependent = rds.getOtmDependent(); |
311 | |
if (onlyDependants && !isDependent) |
312 | |
{ |
313 | |
continue; |
314 | |
} |
315 | |
f = rds.getPersistentField(); |
316 | |
relUserObj = f.get(userObject); |
317 | |
if (relUserObj != null) |
318 | |
{ |
319 | |
relOid = new Identity(relUserObj, _pb); |
320 | |
entry = (ContextEntry) _objects.get(relOid); |
321 | |
if ((entry == null) || (entry.userObject != relUserObj)) |
322 | |
{ |
323 | |
entry = insertInternal(relOid, relUserObj, lock, isDependent, |
324 | |
oid, stack); |
325 | |
if (buildingObject && (entry != null)) |
326 | |
{ |
327 | |
f.set(userObject, entry.userObject); |
328 | |
f.set(cacheObject, entry.cacheObject); |
329 | |
} |
330 | |
} |
331 | |
} |
332 | |
} |
333 | |
|
334 | |
|
335 | |
Iterator collections = mif.getCollectionDescriptors().iterator(); |
336 | |
CollectionDescriptor cds; |
337 | |
Object userCol; |
338 | |
Iterator userColIterator; |
339 | |
Class type; |
340 | |
ArrayList newUserCol = null; |
341 | |
ArrayList newCacheCol = null; |
342 | |
|
343 | |
while (collections.hasNext()) |
344 | |
{ |
345 | |
cds = (CollectionDescriptor) collections.next(); |
346 | |
f = cds.getPersistentField(); |
347 | |
type = f.getType(); |
348 | |
isDependent = cds.getOtmDependent(); |
349 | |
if (onlyDependants && !isDependent) |
350 | |
{ |
351 | |
continue; |
352 | |
} |
353 | |
userCol = f.get(userObject); |
354 | |
if (userCol != null) |
355 | |
{ |
356 | |
if ((userCol instanceof CollectionProxyDefaultImpl) |
357 | |
&& !((CollectionProxyDefaultImpl) userCol).isLoaded()) |
358 | |
{ |
359 | |
continue; |
360 | |
} |
361 | |
|
362 | |
if (buildingObject) |
363 | |
{ |
364 | |
newUserCol = new ArrayList(); |
365 | |
newCacheCol = new ArrayList(); |
366 | |
} |
367 | |
|
368 | |
if (Collection.class.isAssignableFrom(type)) |
369 | |
{ |
370 | |
userColIterator = ((Collection) userCol).iterator(); |
371 | |
} |
372 | |
else if (type.isArray()) |
373 | |
{ |
374 | |
userColIterator = new ArrayIterator(userCol); |
375 | |
} |
376 | |
else |
377 | |
{ |
378 | |
throw new OJBRuntimeException( |
379 | |
userCol.getClass() |
380 | |
+ " can not be managed by OJB OTM, use Array or Collection instead !"); |
381 | |
} |
382 | |
|
383 | |
while (userColIterator.hasNext()) |
384 | |
{ |
385 | |
relUserObj = userColIterator.next(); |
386 | |
relOid = new Identity(relUserObj, _pb); |
387 | |
entry = (ContextEntry) _objects.get(relOid); |
388 | |
if ((entry == null) || (entry.userObject != relUserObj)) |
389 | |
{ |
390 | |
entry = insertInternal(relOid, relUserObj, lock, |
391 | |
isDependent, null, stack); |
392 | |
} |
393 | |
if (buildingObject && (entry != null)) |
394 | |
{ |
395 | |
newUserCol.add(entry.userObject); |
396 | |
newCacheCol.add(entry.cacheObject); |
397 | |
} |
398 | |
} |
399 | |
if (buildingObject) |
400 | |
{ |
401 | |
setCollectionField(userObject, f, newUserCol); |
402 | |
setCollectionField(cacheObject, f, newCacheCol); |
403 | |
} |
404 | |
} |
405 | |
} |
406 | |
} |
407 | |
|
408 | |
|
409 | |
|
410 | |
|
411 | |
public void remove(Identity oid) |
412 | |
{ |
413 | |
_objects.remove(oid); |
414 | |
_order.remove(oid); |
415 | |
LockManager.getInstance().releaseLock(oid, _tx); |
416 | |
} |
417 | |
|
418 | |
|
419 | |
public void deletePersistent(Identity oid, Object userObject) |
420 | |
throws LockingException |
421 | |
{ |
422 | |
ContextEntry entry; |
423 | |
|
424 | |
entry = insertInternal(oid, userObject, LockType.WRITE_LOCK, true, null, |
425 | |
new Stack()); |
426 | |
if (entry != null) |
427 | |
{ |
428 | |
entry.state = entry.state.deletePersistent(); |
429 | |
} |
430 | |
_order.remove(oid); |
431 | |
_order.add(oid); |
432 | |
} |
433 | |
|
434 | |
|
435 | |
|
436 | |
|
437 | |
public Object lookup(Identity oid) |
438 | |
{ |
439 | |
ContextEntry entry = (ContextEntry) _objects.get(oid); |
440 | |
return (entry == null ? null : entry.userObject); |
441 | |
} |
442 | |
|
443 | |
public boolean contains(Identity oid) |
444 | |
{ |
445 | |
return lookup(oid) != null; |
446 | |
} |
447 | |
|
448 | |
|
449 | |
|
450 | |
|
451 | |
public State lookupState(Identity oid) |
452 | |
throws LockingException |
453 | |
{ |
454 | |
State retval = null; |
455 | |
ContextEntry entry = (ContextEntry) _objects.get(oid); |
456 | |
if (entry != null) |
457 | |
{ |
458 | |
|
459 | |
|
460 | |
|
461 | |
retval = entry.state; |
462 | |
} |
463 | |
return retval; |
464 | |
} |
465 | |
|
466 | |
|
467 | |
|
468 | |
|
469 | |
public void setState(Identity oid, State state) |
470 | |
{ |
471 | |
ContextEntry entry = (ContextEntry) _objects.get(oid); |
472 | |
entry.state = state; |
473 | |
} |
474 | |
|
475 | |
public Collection getAllObjectsInContext() |
476 | |
{ |
477 | |
return _objects.values(); |
478 | |
} |
479 | |
|
480 | |
|
481 | |
|
482 | |
|
483 | |
|
484 | |
public void beforeMaterialization(IndirectionHandler handler, Identity oid) |
485 | |
{ |
486 | |
|
487 | |
} |
488 | |
|
489 | |
public void afterMaterialization(IndirectionHandler handler, Object cacheObject) |
490 | |
{ |
491 | |
Identity oid = handler.getIdentity(); |
492 | |
ContextEntry entry = (ContextEntry) _objects.get(oid); |
493 | |
|
494 | |
if (entry == null) |
495 | |
{ |
496 | |
return; |
497 | |
} |
498 | |
|
499 | |
int lock = LockManager.getInstance().getLockHeld(oid, _tx); |
500 | |
ObjectCopyStrategy copyStrategy = _tx.getKit().getCopyStrategy(oid); |
501 | |
Object userObject = copyStrategy.copy(cacheObject, _pb); |
502 | |
handler.setRealSubject(userObject); |
503 | |
_original.put(oid, getFields(userObject, false, true)); |
504 | |
|
505 | |
|
506 | |
entry.userObject = userObject; |
507 | |
entry.cacheObject = cacheObject; |
508 | |
entry.handler.removeListener(this); |
509 | |
entry.handler = null; |
510 | |
|
511 | |
|
512 | |
|
513 | |
try |
514 | |
{ |
515 | |
lockReachableObjects(oid, userObject, cacheObject, lock, new Stack(), true); |
516 | |
} |
517 | |
catch (LockingException ex) |
518 | |
{ |
519 | |
throw new LockingPassthruException(ex); |
520 | |
} |
521 | |
} |
522 | |
|
523 | |
|
524 | |
|
525 | |
|
526 | |
|
527 | |
|
528 | |
|
529 | |
|
530 | |
|
531 | |
|
532 | |
|
533 | |
|
534 | |
|
535 | |
public void commit() throws TransactionAbortedException |
536 | |
{ |
537 | |
checkpointInternal(true); |
538 | |
releaseLocksAndClear(); |
539 | |
} |
540 | |
|
541 | |
private void releaseLocksAndClear() |
542 | |
{ |
543 | |
releaseLocks(); |
544 | |
removeMaterializationListener(); |
545 | |
_objects.clear(); |
546 | |
_order.clear(); |
547 | |
_original.clear(); |
548 | |
if (_checkpointed != _original) |
549 | |
{ |
550 | |
_checkpointed.clear(); |
551 | |
} |
552 | |
} |
553 | |
|
554 | |
|
555 | |
|
556 | |
|
557 | |
|
558 | |
|
559 | |
public void checkpoint() throws TransactionAbortedException |
560 | |
{ |
561 | |
checkpointInternal(false); |
562 | |
_checkpointed = new HashMap(); |
563 | |
for (Iterator iterator = _order.iterator(); iterator.hasNext();) |
564 | |
{ |
565 | |
Identity oid = (Identity) iterator.next(); |
566 | |
ContextEntry entry = (ContextEntry) _objects.get(oid); |
567 | |
if (entry.handler == null) |
568 | |
{ |
569 | |
_checkpointed.put(oid, getFields(entry.userObject, false, true)); |
570 | |
} |
571 | |
} |
572 | |
} |
573 | |
|
574 | |
|
575 | |
|
576 | |
|
577 | |
|
578 | |
|
579 | |
private void checkpointInternal(boolean isCommit) |
580 | |
throws TransactionAbortedException |
581 | |
{ |
582 | |
if (_order.size() == 0) |
583 | |
{ |
584 | |
return; |
585 | |
} |
586 | |
|
587 | |
removeCollectionProxyListeners(); |
588 | |
|
589 | |
ConnectionManagerIF connMan = _pb.serviceConnectionManager(); |
590 | |
boolean saveBatchMode = connMan.isBatchMode(); |
591 | |
Swizzling swizzlingStrategy = _tx.getKit().getSwizzlingStrategy(); |
592 | |
LockManager lockManager = LockManager.getInstance(); |
593 | |
Identity[] lockOrder = (Identity[]) _order.toArray(new Identity[_order.size()]); |
594 | |
ObjectCache cache = _pb.serviceObjectCache(); |
595 | |
boolean isInsertVerified = _tx.getKit().isInsertVerified(); |
596 | |
ArrayList changedCollections = new ArrayList(); |
597 | |
|
598 | |
|
599 | |
Arrays.sort(lockOrder, new Comparator() |
600 | |
{ |
601 | |
public int compare(Object o1, Object o2) |
602 | |
{ |
603 | |
return o1.hashCode() - o2.hashCode(); |
604 | |
} |
605 | |
|
606 | |
public boolean equals(Object obj) |
607 | |
{ |
608 | |
return false; |
609 | |
} |
610 | |
}); |
611 | |
|
612 | |
try { |
613 | |
|
614 | |
|
615 | |
|
616 | |
ArrayList newObjects = new ArrayList(); |
617 | |
int countNewObjects; |
618 | |
do |
619 | |
{ |
620 | |
newObjects.clear(); |
621 | |
countNewObjects = 0; |
622 | |
for (int i = 0; i < lockOrder.length; i++) |
623 | |
{ |
624 | |
Identity oid = lockOrder[i]; |
625 | |
ContextEntry entry = (ContextEntry) _objects.get(oid); |
626 | |
State state = entry.state; |
627 | |
|
628 | |
if (entry.userObject == null) |
629 | |
{ |
630 | |
continue; |
631 | |
} |
632 | |
|
633 | |
if (entry.handler == null) |
634 | |
{ |
635 | |
if (!state.isDeleted()) |
636 | |
{ |
637 | |
Object[][] origFields = (Object[][]) _checkpointed.get(oid); |
638 | |
Object[][] newFields = getFields(entry.userObject, true, !isCommit); |
639 | |
|
640 | |
if (origFields == null) |
641 | |
{ |
642 | |
entry.needsCacheSwizzle = true; |
643 | |
newObjects.addAll( |
644 | |
handleDependentReferences(oid, entry.userObject, |
645 | |
null, newFields[0], newFields[2])); |
646 | |
newObjects.addAll( |
647 | |
handleDependentCollections(oid, entry.userObject, |
648 | |
null, newFields[1], newFields[3])); |
649 | |
} |
650 | |
else |
651 | |
{ |
652 | |
if (isModified(origFields[0], newFields[0])) |
653 | |
{ |
654 | |
entry.state = state.markDirty(); |
655 | |
entry.needsCacheSwizzle = true; |
656 | |
lockManager.ensureLock(oid, _tx, LockType.WRITE_LOCK, _pb); |
657 | |
newObjects.addAll( |
658 | |
handleDependentReferences(oid, entry.userObject, |
659 | |
origFields[0], newFields[0], newFields[2])); |
660 | |
} |
661 | |
|
662 | |
if (isModified(origFields[1], newFields[1])) |
663 | |
{ |
664 | |
|
665 | |
|
666 | |
entry.needsCacheSwizzle = true; |
667 | |
lockManager.ensureLock(oid, _tx, LockType.WRITE_LOCK, _pb); |
668 | |
newObjects.addAll( |
669 | |
handleDependentCollections(oid, entry.userObject, |
670 | |
origFields[1], newFields[1], newFields[3])); |
671 | |
changedCollections.add(oid); |
672 | |
} |
673 | |
} |
674 | |
} |
675 | |
} |
676 | |
} |
677 | |
countNewObjects = newObjects.size(); |
678 | |
if (countNewObjects > 0) |
679 | |
{ |
680 | |
|
681 | |
lockOrder = (Identity[]) newObjects.toArray( |
682 | |
new Identity[countNewObjects]); |
683 | |
} |
684 | |
} |
685 | |
while (countNewObjects > 0); |
686 | |
|
687 | |
|
688 | |
for (Iterator it = _order.iterator(); it.hasNext(); ) |
689 | |
{ |
690 | |
Identity oid = (Identity) it.next(); |
691 | |
ContextEntry entry = (ContextEntry) _objects.get(oid); |
692 | |
|
693 | |
if (entry.needsCacheSwizzle) |
694 | |
{ |
695 | |
entry.userObject = swizzlingStrategy.getRealTarget(entry.userObject); |
696 | |
entry.cacheObject = swizzlingStrategy.swizzle( |
697 | |
|
698 | |
|
699 | |
entry.userObject, entry.cacheObject, _pb, new ObjectCache() |
700 | |
{ |
701 | |
public Object lookup(Identity anOid) |
702 | |
{ |
703 | |
ContextEntry ent = (ContextEntry) _objects.get(anOid); |
704 | |
return (ent == null ? null : ent.cacheObject); |
705 | |
} |
706 | |
|
707 | |
public boolean contains(Identity oid) |
708 | |
{ |
709 | |
return lookup(oid) != null; |
710 | |
} |
711 | |
|
712 | |
public void cache(Identity anOid, Object obj) |
713 | |
{ |
714 | |
|
715 | |
} |
716 | |
|
717 | |
public boolean cacheIfNew(Identity oid, Object obj) |
718 | |
{ |
719 | |
return false; |
720 | |
} |
721 | |
|
722 | |
public void clear() |
723 | |
{ |
724 | |
|
725 | |
} |
726 | |
|
727 | |
public void remove(Identity anOid) |
728 | |
{ |
729 | |
|
730 | |
} |
731 | |
}); |
732 | |
} |
733 | |
} |
734 | |
|
735 | |
|
736 | |
int countCascadeDeleted; |
737 | |
do |
738 | |
{ |
739 | |
countCascadeDeleted = 0; |
740 | |
|
741 | |
|
742 | |
for (Iterator it = (new ArrayList(_order)).iterator(); it.hasNext(); ) |
743 | |
{ |
744 | |
Identity oid = (Identity) it.next(); |
745 | |
ContextEntry entry = (ContextEntry) _objects.get(oid); |
746 | |
|
747 | |
if (entry.state.isDeleted()) |
748 | |
{ |
749 | |
countCascadeDeleted += doCascadeDelete(oid, entry.userObject); |
750 | |
} |
751 | |
} |
752 | |
} |
753 | |
while (countCascadeDeleted > 0); |
754 | |
|
755 | |
|
756 | |
connMan.setBatchMode(true); |
757 | |
try |
758 | |
{ |
759 | |
for (Iterator it = _order.iterator(); it.hasNext(); ) |
760 | |
{ |
761 | |
Identity oid = (Identity) it.next(); |
762 | |
ContextEntry entry = (ContextEntry) _objects.get(oid); |
763 | |
State state = entry.state; |
764 | |
|
765 | |
if (!state.needsInsert() && !state.needsUpdate() |
766 | |
&& !state.needsDelete()) |
767 | |
{ |
768 | |
if (changedCollections.contains(oid)) { |
769 | |
_pb.store(entry.cacheObject, state); |
770 | |
} |
771 | |
continue; |
772 | |
} |
773 | |
|
774 | |
if (state.needsInsert()) |
775 | |
{ |
776 | |
if (isInsertVerified) |
777 | |
{ |
778 | |
|
779 | |
_pb.store(entry.cacheObject); |
780 | |
} |
781 | |
else |
782 | |
{ |
783 | |
|
784 | |
if (cache.lookup(oid) == null) { |
785 | |
_pb.store(entry.cacheObject, state); |
786 | |
} |
787 | |
} |
788 | |
|
789 | |
} |
790 | |
else if (state.needsUpdate()) |
791 | |
{ |
792 | |
_pb.store(entry.cacheObject, state); |
793 | |
} |
794 | |
else if (state.needsDelete()) |
795 | |
{ |
796 | |
_pb.delete(entry.cacheObject); |
797 | |
} |
798 | |
entry.state = state.commit(); |
799 | |
} |
800 | |
connMan.executeBatch(); |
801 | |
} |
802 | |
finally |
803 | |
{ |
804 | |
connMan.setBatchMode(saveBatchMode); |
805 | |
} |
806 | |
} catch (Throwable ex) { |
807 | |
ex.printStackTrace(); |
808 | |
throw new TransactionAbortedException(ex); |
809 | |
} |
810 | |
} |
811 | |
|
812 | |
|
813 | |
|
814 | |
|
815 | |
|
816 | |
|
817 | |
|
818 | |
public void rollback() |
819 | |
{ |
820 | |
for (Iterator iterator = _order.iterator(); iterator.hasNext();) |
821 | |
{ |
822 | |
Identity oid = (Identity) iterator.next(); |
823 | |
ContextEntry entry = (ContextEntry) _objects.get(oid); |
824 | |
entry.state = entry.state.rollback(); |
825 | |
Object[][] origFields = (Object[][]) _original.get(oid); |
826 | |
if (origFields != null) |
827 | |
{ |
828 | |
setFields(entry.userObject, origFields); |
829 | |
setFields(entry.cacheObject, origFields); |
830 | |
} |
831 | |
} |
832 | |
releaseLocksAndClear(); |
833 | |
} |
834 | |
|
835 | |
|
836 | |
|
837 | |
|
838 | |
|
839 | |
|
840 | |
public void refresh(Identity oid, Object object) |
841 | |
{ |
842 | |
ContextEntry entry = (ContextEntry) _objects.get(oid); |
843 | |
Object[][] origFields = (Object[][]) _original.get(oid); |
844 | |
if (origFields != null) |
845 | |
{ |
846 | |
setFields(entry.userObject, origFields); |
847 | |
if (object != entry.userObject) |
848 | |
{ |
849 | |
setFields(object, origFields); |
850 | |
} |
851 | |
} |
852 | |
entry.state = entry.state.refresh(); |
853 | |
} |
854 | |
|
855 | |
private void removeMaterializationListener() |
856 | |
{ |
857 | |
for (Iterator it = _order.iterator(); it.hasNext();) |
858 | |
{ |
859 | |
Identity oid = (Identity) it.next(); |
860 | |
ContextEntry entry = (ContextEntry) _objects.get(oid); |
861 | |
if (entry.handler != null) |
862 | |
{ |
863 | |
entry.handler.removeListener(this); |
864 | |
} |
865 | |
} |
866 | |
} |
867 | |
|
868 | |
private void removeCollectionProxyListeners() |
869 | |
{ |
870 | |
if (_colProxyListeners != null) |
871 | |
{ |
872 | |
for (Iterator it = _colProxyListeners.keySet().iterator(); it.hasNext();) |
873 | |
{ |
874 | |
CollectionProxyListener listener = (CollectionProxyListener) it.next(); |
875 | |
CollectionProxyDefaultImpl colProxy = (CollectionProxyDefaultImpl) _colProxyListeners.get(listener); |
876 | |
colProxy.removeListener(listener); |
877 | |
} |
878 | |
_colProxyListeners.clear(); |
879 | |
} |
880 | |
} |
881 | |
|
882 | |
private void releaseLocks() |
883 | |
{ |
884 | |
LockManager lockManager = LockManager.getInstance(); |
885 | |
|
886 | |
for (Iterator it = _objects.keySet().iterator(); it.hasNext(); ) |
887 | |
{ |
888 | |
Identity oid = (Identity) it.next(); |
889 | |
lockManager.releaseLock(oid, _tx); |
890 | |
} |
891 | |
_tx.getKit().getLockMap().gc(); |
892 | |
} |
893 | |
|
894 | |
|
895 | |
|
896 | |
|
897 | |
|
898 | |
private boolean isEqual(Object fld1, Object fld2) |
899 | |
{ |
900 | |
if (fld1 == null || fld2 == null) |
901 | |
{ |
902 | |
return (fld1 == fld2); |
903 | |
} |
904 | |
else if ((fld1 instanceof BigDecimal) && (fld2 instanceof BigDecimal)) |
905 | |
{ |
906 | |
return (((BigDecimal) fld1).compareTo((BigDecimal) fld2) == 0); |
907 | |
} |
908 | |
else if ((fld1 instanceof Date) && (fld2 instanceof Date)) |
909 | |
{ |
910 | |
return (((Date) fld1).getTime() == ((Date) fld2).getTime()); |
911 | |
} |
912 | |
else |
913 | |
{ |
914 | |
return fld1.equals(fld2); |
915 | |
} |
916 | |
} |
917 | |
|
918 | |
private boolean isModified(Object[] newFields, Object[] oldFields) |
919 | |
{ |
920 | |
if (newFields.length != oldFields.length) |
921 | |
{ |
922 | |
return true; |
923 | |
} |
924 | |
|
925 | |
for (int i = 0; i < newFields.length; i++) |
926 | |
{ |
927 | |
if (!isEqual(newFields[i], oldFields[i])) |
928 | |
{ |
929 | |
return true; |
930 | |
} |
931 | |
} |
932 | |
|
933 | |
return false; |
934 | |
} |
935 | |
|
936 | |
|
937 | |
|
938 | |
|
939 | |
|
940 | |
|
941 | |
|
942 | |
|
943 | |
|
944 | |
|
945 | |
|
946 | |
private Object[][] getFields(Object obj, boolean withObjects, boolean addListeners) |
947 | |
{ |
948 | |
ClassDescriptor mif = _pb.getClassDescriptor(obj.getClass()); |
949 | |
FieldDescriptor[] fieldDescs = mif.getFieldDescriptions(); |
950 | |
Collection refDescs = mif.getObjectReferenceDescriptors(); |
951 | |
Collection colDescs = mif.getCollectionDescriptors(); |
952 | |
int count = 0; |
953 | |
Object[] fields = new Object[1 + fieldDescs.length + refDescs.size()]; |
954 | |
ArrayList[] collections = new ArrayList[colDescs.size()]; |
955 | |
Object[] references = null; |
956 | |
ArrayList[] collectionsOfObjects = null; |
957 | |
int lockForListeners = LockType.NO_LOCK; |
958 | |
|
959 | |
if (withObjects) |
960 | |
{ |
961 | |
references = new Object[refDescs.size()]; |
962 | |
collectionsOfObjects = new ArrayList[colDescs.size()]; |
963 | |
} |
964 | |
|
965 | |
if (addListeners) |
966 | |
{ |
967 | |
lockForListeners = LockManager.getInstance().getLockHeld( |
968 | |
new Identity(obj, _pb), _tx); |
969 | |
} |
970 | |
|
971 | |
fields[0] = obj.getClass(); |
972 | |
count++; |
973 | |
|
974 | |
for (int i = 0; i < fieldDescs.length; i++) |
975 | |
{ |
976 | |
FieldDescriptor fd = fieldDescs[i]; |
977 | |
PersistentField f = fd.getPersistentField(); |
978 | |
fields[count] = f.get(obj); |
979 | |
count++; |
980 | |
} |
981 | |
|
982 | |
int countRefs = 0; |
983 | |
for (Iterator it = refDescs.iterator(); it.hasNext(); count++, countRefs++) |
984 | |
{ |
985 | |
ObjectReferenceDescriptor rds = (ObjectReferenceDescriptor) it.next(); |
986 | |
PersistentField f = rds.getPersistentField(); |
987 | |
Object relObj = f.get(obj); |
988 | |
if (relObj != null) |
989 | |
{ |
990 | |
fields[count] = new Identity(relObj, _pb); |
991 | |
if (withObjects) |
992 | |
{ |
993 | |
references[countRefs] = relObj; |
994 | |
} |
995 | |
} |
996 | |
} |
997 | |
|
998 | |
count = 0; |
999 | |
for (Iterator it = colDescs.iterator(); it.hasNext(); count++) |
1000 | |
{ |
1001 | |
CollectionDescriptor cds = (CollectionDescriptor) it.next(); |
1002 | |
PersistentField f = cds.getPersistentField(); |
1003 | |
Class type = f.getType(); |
1004 | |
Object col = f.get(obj); |
1005 | |
|
1006 | |
if ((col != null) && (col instanceof CollectionProxyDefaultImpl) |
1007 | |
&& !((CollectionProxyDefaultImpl) col).isLoaded()) |
1008 | |
{ |
1009 | |
if (addListeners) |
1010 | |
{ |
1011 | |
OTMCollectionProxyListener listener = |
1012 | |
new OTMCollectionProxyListener(cds, collections, |
1013 | |
count, lockForListeners); |
1014 | |
|
1015 | |
((CollectionProxyDefaultImpl) col).addListener(listener); |
1016 | |
if (_colProxyListeners == null) |
1017 | |
{ |
1018 | |
_colProxyListeners = new HashMap(); |
1019 | |
} |
1020 | |
_colProxyListeners.put(listener, col); |
1021 | |
} |
1022 | |
continue; |
1023 | |
} |
1024 | |
|
1025 | |
if (col != null) |
1026 | |
{ |
1027 | |
ArrayList list = new ArrayList(); |
1028 | |
ArrayList listOfObjects = null; |
1029 | |
Iterator colIterator; |
1030 | |
|
1031 | |
collections[count] = list; |
1032 | |
if (withObjects) |
1033 | |
{ |
1034 | |
listOfObjects = new ArrayList(); |
1035 | |
collectionsOfObjects[count] = listOfObjects; |
1036 | |
} |
1037 | |
|
1038 | |
if (Collection.class.isAssignableFrom(type)) |
1039 | |
{ |
1040 | |
colIterator = ((Collection) col).iterator(); |
1041 | |
} |
1042 | |
else if (type.isArray()) |
1043 | |
{ |
1044 | |
colIterator = new ArrayIterator(col); |
1045 | |
} |
1046 | |
else |
1047 | |
{ |
1048 | |
continue; |
1049 | |
} |
1050 | |
|
1051 | |
while (colIterator.hasNext()) |
1052 | |
{ |
1053 | |
Object relObj = colIterator.next(); |
1054 | |
list.add(new Identity(relObj, _pb)); |
1055 | |
if (withObjects) |
1056 | |
{ |
1057 | |
listOfObjects.add(relObj); |
1058 | |
} |
1059 | |
} |
1060 | |
} |
1061 | |
} |
1062 | |
|
1063 | |
return new Object[][] {fields, collections, references, collectionsOfObjects}; |
1064 | |
} |
1065 | |
|
1066 | |
private void setFields(Object obj, Object[][] fieldsAndCollections) |
1067 | |
{ |
1068 | |
ClassDescriptor mif = _pb.getClassDescriptor(obj.getClass()); |
1069 | |
FieldDescriptor[] fieldDescs = mif.getFieldDescriptions(); |
1070 | |
Collection refDescs = mif.getObjectReferenceDescriptors(); |
1071 | |
Collection colDescs = mif.getCollectionDescriptors(); |
1072 | |
Object[] fields = fieldsAndCollections[0]; |
1073 | |
ArrayList[] collections = (ArrayList[]) fieldsAndCollections[1]; |
1074 | |
int count = 0; |
1075 | |
|
1076 | |
if (!fields[0].equals(obj.getClass())) |
1077 | |
{ |
1078 | |
System.err.println("Can't restore the object fields " |
1079 | |
+ "since its class changed during transaction from " |
1080 | |
+ fields[0] + " to " + obj.getClass()); |
1081 | |
return; |
1082 | |
} |
1083 | |
count++; |
1084 | |
|
1085 | |
for (int i = 0; i < fieldDescs.length; i++) |
1086 | |
{ |
1087 | |
FieldDescriptor fd = fieldDescs[i]; |
1088 | |
PersistentField f = fd.getPersistentField(); |
1089 | |
f.set(obj, fields[count]); |
1090 | |
count++; |
1091 | |
} |
1092 | |
|
1093 | |
for (Iterator it = refDescs.iterator(); it.hasNext(); count++) |
1094 | |
{ |
1095 | |
ObjectReferenceDescriptor rds = (ObjectReferenceDescriptor) it.next(); |
1096 | |
PersistentField f = rds.getPersistentField(); |
1097 | |
Identity oid = (Identity) fields[count]; |
1098 | |
Object relObj; |
1099 | |
if (oid == null) |
1100 | |
{ |
1101 | |
relObj = null; |
1102 | |
} |
1103 | |
else |
1104 | |
{ |
1105 | |
relObj = _pb.getObjectByIdentity(oid); |
1106 | |
} |
1107 | |
f.set(obj, relObj); |
1108 | |
} |
1109 | |
|
1110 | |
count = 0; |
1111 | |
for (Iterator it = colDescs.iterator(); it.hasNext(); count++) |
1112 | |
{ |
1113 | |
CollectionDescriptor cds = (CollectionDescriptor) it.next(); |
1114 | |
PersistentField f = cds.getPersistentField(); |
1115 | |
ArrayList list = collections[count]; |
1116 | |
ArrayList newCol; |
1117 | |
|
1118 | |
if (list == null) |
1119 | |
{ |
1120 | |
f.set(obj, null); |
1121 | |
} |
1122 | |
else |
1123 | |
{ |
1124 | |
newCol = new ArrayList(); |
1125 | |
for (Iterator it2 = list.iterator(); it2.hasNext(); ) |
1126 | |
{ |
1127 | |
Identity relOid = (Identity) it2.next(); |
1128 | |
Object relObj = _pb.getObjectByIdentity(relOid); |
1129 | |
|
1130 | |
if (relObj != null) |
1131 | |
{ |
1132 | |
newCol.add(relObj); |
1133 | |
} |
1134 | |
} |
1135 | |
setCollectionField(obj, f, newCol); |
1136 | |
} |
1137 | |
} |
1138 | |
} |
1139 | |
|
1140 | |
private void setCollectionField(Object obj, PersistentField f, List newCol) |
1141 | |
{ |
1142 | |
Class type = f.getType(); |
1143 | |
|
1144 | |
if (Collection.class.isAssignableFrom(type)) |
1145 | |
{ |
1146 | |
Collection col = (Collection) f.get(obj); |
1147 | |
|
1148 | |
if (col == null) |
1149 | |
{ |
1150 | |
if (type == List.class || type == Collection.class) |
1151 | |
{ |
1152 | |
col = new ArrayList(); |
1153 | |
} |
1154 | |
else if (type == Set.class) |
1155 | |
{ |
1156 | |
col = new HashSet(); |
1157 | |
} |
1158 | |
else |
1159 | |
{ |
1160 | |
try |
1161 | |
{ |
1162 | |
col = (Collection) type.newInstance(); |
1163 | |
} |
1164 | |
catch (Throwable ex) |
1165 | |
{ |
1166 | |
System.err.println("Cannot instantiate collection field: " + f); |
1167 | |
ex.printStackTrace(); |
1168 | |
return; |
1169 | |
} |
1170 | |
} |
1171 | |
} |
1172 | |
else |
1173 | |
{ |
1174 | |
if (col instanceof CollectionProxyDefaultImpl) |
1175 | |
{ |
1176 | |
CollectionProxyDefaultImpl cp = (CollectionProxyDefaultImpl) col; |
1177 | |
if (col instanceof List) |
1178 | |
{ |
1179 | |
col = new ListProxyDefaultImpl(_pb.getPBKey(), cp.getData().getClass(), null); |
1180 | |
} |
1181 | |
else if (col instanceof Set) |
1182 | |
{ |
1183 | |
col = new SetProxyDefaultImpl(_pb.getPBKey(), cp.getData().getClass(), null); |
1184 | |
} |
1185 | |
else |
1186 | |
{ |
1187 | |
col = new CollectionProxyDefaultImpl(_pb.getPBKey(), cp.getData().getClass(), null); |
1188 | |
} |
1189 | |
col.clear(); |
1190 | |
} |
1191 | |
else |
1192 | |
{ |
1193 | |
try |
1194 | |
{ |
1195 | |
col = (Collection) col.getClass().newInstance(); |
1196 | |
} |
1197 | |
catch (Exception ex) |
1198 | |
{ |
1199 | |
System.err.println("Cannot instantiate collection field: " + f); |
1200 | |
ex.printStackTrace(); |
1201 | |
return; |
1202 | |
} |
1203 | |
} |
1204 | |
} |
1205 | |
col.addAll(newCol); |
1206 | |
f.set(obj, col); |
1207 | |
} |
1208 | |
else if (type.isArray()) |
1209 | |
{ |
1210 | |
int length = newCol.size(); |
1211 | |
Object array = Array.newInstance(type.getComponentType(), length); |
1212 | |
|
1213 | |
for (int i = 0; i < length; i++) |
1214 | |
{ |
1215 | |
Array.set(array, i, newCol.get(i)); |
1216 | |
} |
1217 | |
f.set(obj, array); |
1218 | |
} |
1219 | |
} |
1220 | |
|
1221 | |
|
1222 | |
|
1223 | |
|
1224 | |
|
1225 | |
private boolean hasBidirectionalAssociation(Class clazz) |
1226 | |
{ |
1227 | |
ClassDescriptor cdesc; |
1228 | |
Collection refs; |
1229 | |
boolean hasBidirAssc; |
1230 | |
|
1231 | |
if (_withoutBidirAssc.contains(clazz)) |
1232 | |
{ |
1233 | |
return false; |
1234 | |
} |
1235 | |
|
1236 | |
if (_withBidirAssc.contains(clazz)) |
1237 | |
{ |
1238 | |
return true; |
1239 | |
} |
1240 | |
|
1241 | |
|
1242 | |
cdesc = _pb.getClassDescriptor(clazz); |
1243 | |
refs = cdesc.getObjectReferenceDescriptors(); |
1244 | |
hasBidirAssc = false; |
1245 | |
REFS_CYCLE: |
1246 | |
for (Iterator it = refs.iterator(); it.hasNext(); ) |
1247 | |
{ |
1248 | |
ObjectReferenceDescriptor ord; |
1249 | |
ClassDescriptor relCDesc; |
1250 | |
Collection relRefs; |
1251 | |
|
1252 | |
ord = (ObjectReferenceDescriptor) it.next(); |
1253 | |
relCDesc = _pb.getClassDescriptor(ord.getItemClass()); |
1254 | |
relRefs = relCDesc.getObjectReferenceDescriptors(); |
1255 | |
for (Iterator relIt = relRefs.iterator(); relIt.hasNext(); ) |
1256 | |
{ |
1257 | |
ObjectReferenceDescriptor relOrd; |
1258 | |
|
1259 | |
relOrd = (ObjectReferenceDescriptor) relIt.next(); |
1260 | |
if (relOrd.getItemClass().equals(clazz)) |
1261 | |
{ |
1262 | |
hasBidirAssc = true; |
1263 | |
break REFS_CYCLE; |
1264 | |
} |
1265 | |
} |
1266 | |
} |
1267 | |
if (hasBidirAssc) |
1268 | |
{ |
1269 | |
_withBidirAssc.add(clazz); |
1270 | |
} |
1271 | |
else |
1272 | |
{ |
1273 | |
_withoutBidirAssc.add(clazz); |
1274 | |
} |
1275 | |
|
1276 | |
return hasBidirAssc; |
1277 | |
} |
1278 | |
|
1279 | |
|
1280 | |
|
1281 | |
|
1282 | |
private int markDelete(Identity oid, Identity mainOid, boolean isCollection) |
1283 | |
{ |
1284 | |
ContextEntry entry = (ContextEntry) _objects.get(oid); |
1285 | |
|
1286 | |
if (entry == null) |
1287 | |
{ |
1288 | |
throw new IllegalStateException("markDelete failed: the dependent object " |
1289 | |
+ oid + " is not in the editing context"); |
1290 | |
} |
1291 | |
|
1292 | |
if (entry.state.isDeleted()) |
1293 | |
{ |
1294 | |
return 0; |
1295 | |
} |
1296 | |
else |
1297 | |
{ |
1298 | |
entry.state = entry.state.deletePersistent(); |
1299 | |
if (mainOid != null) |
1300 | |
{ |
1301 | |
int dependentIndex = _order.indexOf(oid); |
1302 | |
int mainIndex = _order.indexOf(mainOid); |
1303 | |
|
1304 | |
if (isCollection) |
1305 | |
{ |
1306 | |
if (dependentIndex > mainIndex) |
1307 | |
{ |
1308 | |
_order.remove(dependentIndex); |
1309 | |
_order.add(mainIndex, oid); |
1310 | |
} |
1311 | |
} |
1312 | |
else |
1313 | |
{ |
1314 | |
if (dependentIndex < mainIndex) |
1315 | |
{ |
1316 | |
_order.remove(dependentIndex); |
1317 | |
_order.add(mainIndex, oid); |
1318 | |
} |
1319 | |
} |
1320 | |
|
1321 | |
} |
1322 | |
return 1; |
1323 | |
} |
1324 | |
} |
1325 | |
|
1326 | |
|
1327 | |
|
1328 | |
|
1329 | |
|
1330 | |
|
1331 | |
private ArrayList handleDependentReferences(Identity oid, Object userObject, |
1332 | |
Object[] origFields, Object[] newFields, Object[] newRefs) |
1333 | |
throws LockingException |
1334 | |
{ |
1335 | |
ClassDescriptor mif = _pb.getClassDescriptor(userObject.getClass()); |
1336 | |
FieldDescriptor[] fieldDescs = mif.getFieldDescriptions(); |
1337 | |
Collection refDescs = mif.getObjectReferenceDescriptors(); |
1338 | |
int count = 1 + fieldDescs.length; |
1339 | |
ArrayList newObjects = new ArrayList(); |
1340 | |
int countRefs = 0; |
1341 | |
|
1342 | |
for (Iterator it = refDescs.iterator(); it.hasNext(); count++, countRefs++) |
1343 | |
{ |
1344 | |
ObjectReferenceDescriptor rds = (ObjectReferenceDescriptor) it.next(); |
1345 | |
Identity origOid = (origFields == null ? null : (Identity) origFields[count]); |
1346 | |
Identity newOid = (Identity) newFields[count]; |
1347 | |
|
1348 | |
if (rds.getOtmDependent()) |
1349 | |
{ |
1350 | |
if ((origOid == null) && (newOid != null)) |
1351 | |
{ |
1352 | |
ContextEntry entry = (ContextEntry) _objects.get(newOid); |
1353 | |
|
1354 | |
if (entry == null) |
1355 | |
{ |
1356 | |
Object relObj = newRefs[countRefs]; |
1357 | |
insertInternal(newOid, relObj, LockType.WRITE_LOCK, |
1358 | |
true, oid, new Stack()); |
1359 | |
newObjects.add(newOid); |
1360 | |
} |
1361 | |
} |
1362 | |
else if ((origOid != null) && |
1363 | |
((newOid == null) || !newOid.equals(origOid))) |
1364 | |
{ |
1365 | |
markDelete(origOid, oid, false); |
1366 | |
} |
1367 | |
} |
1368 | |
} |
1369 | |
|
1370 | |
return newObjects; |
1371 | |
} |
1372 | |
|
1373 | |
|
1374 | |
|
1375 | |
|
1376 | |
|
1377 | |
private ArrayList handleDependentCollections(Identity oid, Object obj, |
1378 | |
Object[] origCollections, Object[] newCollections, |
1379 | |
Object[] newCollectionsOfObjects) |
1380 | |
throws LockingException |
1381 | |
{ |
1382 | |
ClassDescriptor mif = _pb.getClassDescriptor(obj.getClass()); |
1383 | |
Collection colDescs = mif.getCollectionDescriptors(); |
1384 | |
ArrayList newObjects = new ArrayList(); |
1385 | |
int count = 0; |
1386 | |
|
1387 | |
for (Iterator it = colDescs.iterator(); it.hasNext(); count++) |
1388 | |
{ |
1389 | |
CollectionDescriptor cds = (CollectionDescriptor) it.next(); |
1390 | |
|
1391 | |
if (cds.getOtmDependent()) |
1392 | |
{ |
1393 | |
ArrayList origList = (origCollections == null ? null |
1394 | |
: (ArrayList) origCollections[count]); |
1395 | |
ArrayList newList = (ArrayList) newCollections[count]; |
1396 | |
|
1397 | |
if (origList != null) |
1398 | |
{ |
1399 | |
for (Iterator it2 = origList.iterator(); it2.hasNext(); ) |
1400 | |
{ |
1401 | |
Identity origOid = (Identity) it2.next(); |
1402 | |
|
1403 | |
if ((newList == null) || !newList.contains(origOid)) |
1404 | |
{ |
1405 | |
markDelete(origOid, oid, true); |
1406 | |
} |
1407 | |
} |
1408 | |
} |
1409 | |
|
1410 | |
if (newList != null) |
1411 | |
{ |
1412 | |
int countElem = 0; |
1413 | |
for (Iterator it2 = newList.iterator(); it2.hasNext(); countElem++) |
1414 | |
{ |
1415 | |
Identity newOid = (Identity) it2.next(); |
1416 | |
|
1417 | |
if ((origList == null) || !origList.contains(newOid)) |
1418 | |
{ |
1419 | |
ContextEntry entry = (ContextEntry) _objects.get(newOid); |
1420 | |
|
1421 | |
if (entry == null) |
1422 | |
{ |
1423 | |
ArrayList relCol = (ArrayList) |
1424 | |
newCollectionsOfObjects[count]; |
1425 | |
Object relObj = relCol.get(countElem); |
1426 | |
insertInternal(newOid, relObj, LockType.WRITE_LOCK, |
1427 | |
true, null, new Stack()); |
1428 | |
newObjects.add(newOid); |
1429 | |
} |
1430 | |
} |
1431 | |
} |
1432 | |
} |
1433 | |
} |
1434 | |
} |
1435 | |
|
1436 | |
return newObjects; |
1437 | |
} |
1438 | |
|
1439 | |
|
1440 | |
|
1441 | |
|
1442 | |
|
1443 | |
private int doCascadeDelete(Identity oid, Object obj) |
1444 | |
{ |
1445 | |
ClassDescriptor mif = _pb.getClassDescriptor(ProxyHelper.getRealClass(obj)); |
1446 | |
Collection refDescs = mif.getObjectReferenceDescriptors(); |
1447 | |
Collection colDescs = mif.getCollectionDescriptors(); |
1448 | |
int countCascadeDeleted = 0; |
1449 | |
|
1450 | |
for (Iterator it = refDescs.iterator(); it.hasNext(); ) |
1451 | |
{ |
1452 | |
ObjectReferenceDescriptor rds = (ObjectReferenceDescriptor) it.next(); |
1453 | |
|
1454 | |
if (rds.getOtmDependent()) |
1455 | |
{ |
1456 | |
PersistentField f = rds.getPersistentField(); |
1457 | |
Object relObj = f.get(obj); |
1458 | |
|
1459 | |
if (relObj != null) |
1460 | |
{ |
1461 | |
countCascadeDeleted += |
1462 | |
markDelete(new Identity(relObj, _pb), oid, false); |
1463 | |
} |
1464 | |
} |
1465 | |
} |
1466 | |
|
1467 | |
for (Iterator it = colDescs.iterator(); it.hasNext(); ) |
1468 | |
{ |
1469 | |
CollectionDescriptor cds = (CollectionDescriptor) it.next(); |
1470 | |
|
1471 | |
if (cds.getOtmDependent()) |
1472 | |
{ |
1473 | |
PersistentField f = cds.getPersistentField(); |
1474 | |
Class type = f.getType(); |
1475 | |
Object col = f.get(obj); |
1476 | |
|
1477 | |
if (col != null) |
1478 | |
{ |
1479 | |
Iterator colIterator; |
1480 | |
|
1481 | |
if (Collection.class.isAssignableFrom(type)) |
1482 | |
{ |
1483 | |
colIterator = ((Collection) col).iterator(); |
1484 | |
} |
1485 | |
else if (type.isArray()) |
1486 | |
{ |
1487 | |
colIterator = new ArrayIterator(col); |
1488 | |
} |
1489 | |
else |
1490 | |
{ |
1491 | |
continue; |
1492 | |
} |
1493 | |
|
1494 | |
while (colIterator.hasNext()) |
1495 | |
{ |
1496 | |
|
1497 | |
countCascadeDeleted += |
1498 | |
markDelete(new Identity(colIterator.next(), _pb), oid, true); |
1499 | |
} |
1500 | |
} |
1501 | |
} |
1502 | |
} |
1503 | |
|
1504 | |
return countCascadeDeleted; |
1505 | |
} |
1506 | |
|
1507 | |
|
1508 | |
|
1509 | |
|
1510 | |
|
1511 | |
|
1512 | |
|
1513 | |
|
1514 | |
public void cache(Identity oid, Object obj) |
1515 | |
{ |
1516 | |
throw new UnsupportedOperationException(); |
1517 | |
} |
1518 | |
|
1519 | |
public boolean cacheIfNew(Identity oid, Object obj) |
1520 | |
{ |
1521 | |
|
1522 | |
throw new UnsupportedOperationException("Not implemented"); |
1523 | |
} |
1524 | |
|
1525 | |
public void clear() |
1526 | |
{ |
1527 | |
throw new UnsupportedOperationException(); |
1528 | |
} |
1529 | |
|
1530 | |
|
1531 | |
|
1532 | |
|
1533 | |
|
1534 | |
|
1535 | |
private static class ContextEntry |
1536 | |
{ |
1537 | |
Object userObject; |
1538 | |
Object cacheObject; |
1539 | |
State state = State.PERSISTENT_CLEAN; |
1540 | |
|
1541 | |
|
1542 | |
|
1543 | |
|
1544 | |
IndirectionHandler handler; |
1545 | |
|
1546 | |
|
1547 | |
|
1548 | |
|
1549 | |
boolean needsCacheSwizzle; |
1550 | |
|
1551 | |
ContextEntry(Object theUserObject) |
1552 | |
{ |
1553 | |
userObject = theUserObject; |
1554 | |
if (userObject != null) |
1555 | |
{ |
1556 | |
handler = ProxyHelper.getIndirectionHandler(userObject); |
1557 | |
if ((handler != null) && handler.alreadyMaterialized()) |
1558 | |
{ |
1559 | |
userObject = handler.getRealSubject(); |
1560 | |
handler = null; |
1561 | |
} |
1562 | |
} |
1563 | |
} |
1564 | |
} |
1565 | |
|
1566 | |
private class OTMCollectionProxyListener implements CollectionProxyListener |
1567 | |
{ |
1568 | |
private final CollectionDescriptor _cds; |
1569 | |
private final ArrayList[] _collections; |
1570 | |
private final int _index; |
1571 | |
private final int _lock; |
1572 | |
|
1573 | |
OTMCollectionProxyListener(CollectionDescriptor cds, |
1574 | |
ArrayList[] collections, int index, int lock) |
1575 | |
{ |
1576 | |
_cds = cds; |
1577 | |
_collections = collections; |
1578 | |
_index = index; |
1579 | |
_lock = lock; |
1580 | |
} |
1581 | |
|
1582 | |
public void beforeLoading(CollectionProxyDefaultImpl colProxy) |
1583 | |
{ |
1584 | |
|
1585 | |
} |
1586 | |
|
1587 | |
|
1588 | |
|
1589 | |
|
1590 | |
|
1591 | |
public void afterLoading(CollectionProxyDefaultImpl colProxy) |
1592 | |
{ |
1593 | |
ArrayList list = new ArrayList(); |
1594 | |
ArrayList newUserCol = new ArrayList(); |
1595 | |
LockManager lockManager = LockManager.getInstance(); |
1596 | |
_collections[_index] = list; |
1597 | |
|
1598 | |
for (Iterator it = colProxy.iterator(); it.hasNext(); ) |
1599 | |
{ |
1600 | |
Object relUserObj; |
1601 | |
Object relCacheObj = it.next(); |
1602 | |
Identity relOid = new Identity(relCacheObj, _pb); |
1603 | |
ContextEntry entry; |
1604 | |
|
1605 | |
list.add(relOid); |
1606 | |
entry = (ContextEntry) _objects.get(relOid); |
1607 | |
if (entry != null) |
1608 | |
{ |
1609 | |
relUserObj = entry.userObject; |
1610 | |
} |
1611 | |
else |
1612 | |
{ |
1613 | |
ObjectCopyStrategy copyStrategy; |
1614 | |
|
1615 | |
copyStrategy = _tx.getKit().getCopyStrategy(relOid); |
1616 | |
relUserObj = copyStrategy.copy(relCacheObj, _pb); |
1617 | |
try |
1618 | |
{ |
1619 | |
entry = insertInternal(relOid, relUserObj, _lock, |
1620 | |
_cds.getOtmDependent(), null, new Stack()); |
1621 | |
if (entry != null) |
1622 | |
{ |
1623 | |
relUserObj = entry.userObject; |
1624 | |
} |
1625 | |
} |
1626 | |
catch (LockingException ex) |
1627 | |
{ |
1628 | |
throw new LockingPassthruException(ex); |
1629 | |
} |
1630 | |
} |
1631 | |
newUserCol.add(relUserObj); |
1632 | |
} |
1633 | |
colProxy.clear(); |
1634 | |
colProxy.addAll(newUserCol); |
1635 | |
} |
1636 | |
} |
1637 | |
} |