KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > ojb > otm > core > ConcreteEditingContext


1 package org.apache.ojb.otm.core;
2
3 /* Copyright 2003-2005 The Apache Software Foundation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18 import java.lang.reflect.Array JavaDoc;
19 import java.math.BigDecimal JavaDoc;
20 import java.util.ArrayList JavaDoc;
21 import java.util.Arrays JavaDoc;
22 import java.util.Collection JavaDoc;
23 import java.util.Comparator JavaDoc;
24 import java.util.Iterator JavaDoc;
25 import java.util.HashMap JavaDoc;
26 import java.util.HashSet JavaDoc;
27 import java.util.Date JavaDoc;
28 import java.util.List JavaDoc;
29 import java.util.Set JavaDoc;
30 import java.util.Stack JavaDoc;
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  * Concrete implementation of EditingContext.
64  *
65  * @author <a HREF="mailto:rraghuram@hotmail.com">Raghu Rajah</a>
66  * @see org.apache.ojb.otm.EditingContext
67  *
68  */

69 public class ConcreteEditingContext
70         implements EditingContext, MaterializationListener, ObjectCache
71 {
72     // for hasBidirectionalAssociation method
73
// Maps PBKeys to the sets of classes with/without
74
// bidirectional associations
75
private static HashMap JavaDoc _withBidirAsscMap = new HashMap JavaDoc();
76     private static HashMap JavaDoc _withoutBidirAsscMap = new HashMap JavaDoc();
77
78     private HashSet JavaDoc _withBidirAssc;
79     private HashSet JavaDoc _withoutBidirAssc;
80
81     private HashMap JavaDoc _objects;
82     private ArrayList JavaDoc _order;
83     private Transaction _tx;
84     private PersistenceBroker _pb;
85     private HashMap JavaDoc _original;
86     private HashMap JavaDoc _checkpointed;
87     private HashMap JavaDoc _colProxyListeners;
88
89     //////////////////////////////////////////
90
// Constructor
91
//////////////////////////////////////////
92

93     public ConcreteEditingContext(Transaction tx, PersistenceBroker pb)
94     {
95         PBKey pbkey;
96
97         _tx = tx;
98         _pb = pb;
99         _objects = new HashMap JavaDoc();
100         _order = new ArrayList JavaDoc();
101         _original = new HashMap JavaDoc();
102         _checkpointed = _original;
103         pbkey = _pb.getPBKey();
104         _withoutBidirAssc = (HashSet JavaDoc) _withoutBidirAsscMap.get(pbkey);
105         if (_withoutBidirAssc != null)
106         {
107             _withBidirAssc = (HashSet JavaDoc) _withBidirAsscMap.get(pbkey);
108         }
109         else
110         {
111             _withoutBidirAssc = new HashSet JavaDoc();
112             _withoutBidirAsscMap.put(pbkey, _withoutBidirAssc);
113             _withBidirAssc = new HashSet JavaDoc();
114             _withBidirAsscMap.put(pbkey, _withBidirAssc);
115         }
116     }
117
118     //////////////////////////////////////////
119
// EditingContext operations
120
//////////////////////////////////////////
121

122     /**
123      * @see org.apache.ojb.otm.EditingContext#insert(Identity, Object, int)
124      */

125     public void insert(Identity oid, Object JavaDoc userObject, int lock)
126             throws LockingException
127     {
128         ContextEntry entry;
129
130         entry = insertInternal(oid, userObject, lock, true, null, new Stack JavaDoc());
131         if ((entry != null) && entry.state.needsDelete()) {
132             // Undelete it
133
entry.state = State.PERSISTENT_CLEAN;
134         }
135     }
136
137     private ContextEntry insertInternal(Identity oid, Object JavaDoc userObject,
138             int lock, boolean canCreate, Identity insertBeforeThis, Stack JavaDoc stack)
139             throws LockingException
140     {
141         ContextEntry entry;
142         LockManager lockManager;
143         Swizzling swizzlingStrategy;
144         IndirectionHandler handler = null;
145         OTMKit kit = _tx.getKit();
146         // Are we building object's relations for the userObject in the transaction?
147
// Otherwise we just get data from the "userObject" and put it into
148
// the previously loaded/created object in the transaction
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             // invalidating object...
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             // first insertion of the userObject into editing context
185
Object JavaDoc 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                 // Assume that object exists, otherwise were the proxy came from?
192
_objects.put(oid, entry);
193                 lockManager.ensureLock(oid, _tx, lock, _pb); // lock after _objects.put to avoid hanged locks
194
entry.handler.addListener(this);
195             }
196             else
197             {
198                 Object JavaDoc origCacheObj = _pb.getObjectByIdentity(oid);
199
200                 if ((origCacheObj == null) && !canCreate)
201                 {
202                     // we don't create the objects by reachability
203
throw new IllegalStateException JavaDoc("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); // lock after _objects.put to avoid hanged locks
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             // The object in context is the same object attempted an insert on
248
// Ensure we have the correct lock level
249
lockManager.ensureLock(oid, _tx, lock, _pb);
250
251             if (handler == null)
252             {
253                 if (!swizzlingStrategy.isSameInstance(entry.userObject, userObject))
254                 {
255                     // the new object contains data to deal with
256
if (entry.handler != null)
257                     {
258                         // materialize old object even if it is not
259
// materialized yet, because we need a place
260
// to copy the data from the new object
261
entry.userObject = entry.handler.getRealSubject();
262                         entry.handler = null;
263                     }
264                     // swizzle after lockReachableObjects(), when all related objects
265
// will be in the editing context
266
lazySwizzle = true;
267                 }
268             }
269         }
270
271         // perform automatic read lock for all reachable objects
272
// if the inserted object is materialized
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      * Lock all objects reachable via 1:N and N:1 relations,
289      * @param lock The lock type to use
290      */

291     private void lockReachableObjects(Identity oid, Object JavaDoc userObject,
292             Object JavaDoc cacheObject, int lock, Stack JavaDoc 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         // N:1 relations
300
Iterator JavaDoc iter = mif.getObjectReferenceDescriptors().iterator();
301         ObjectReferenceDescriptor rds = null;
302         PersistentField f;
303         Object JavaDoc 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         // 1:N relations
335
Iterator JavaDoc collections = mif.getCollectionDescriptors().iterator();
336         CollectionDescriptor cds;
337         Object JavaDoc userCol;
338         Iterator JavaDoc userColIterator;
339         Class JavaDoc type;
340         ArrayList JavaDoc newUserCol = null;
341         ArrayList JavaDoc 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 JavaDoc();
365                     newCacheCol = new ArrayList JavaDoc();
366                 }
367
368                 if (Collection JavaDoc.class.isAssignableFrom(type))
369                 {
370                     userColIterator = ((Collection JavaDoc) 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      * @see org.apache.ojb.otm.EditingContext#remove(Identity)
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 JavaDoc userObject)
420             throws LockingException
421     {
422         ContextEntry entry;
423
424         entry = insertInternal(oid, userObject, LockType.WRITE_LOCK, true, null,
425                                new Stack JavaDoc());
426         if (entry != null)
427         {
428             entry.state = entry.state.deletePersistent();
429         }
430         _order.remove(oid);
431         _order.add(oid);
432     }
433
434     /**
435      * @see org.apache.ojb.otm.EditingContext#lookup(Identity)
436      */

437     public Object JavaDoc 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      * @see org.apache.ojb.otm.EditingContext#lookupState(Identity)
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              * possibly return a clone so we don't allow people to tweak states.
460              */

461             retval = entry.state;
462         }
463         return retval;
464     }
465
466     /**
467      * @see org.apache.ojb.otm.EditingContext#setState(Identity, State)
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 JavaDoc getAllObjectsInContext()
476     {
477         return _objects.values();
478     }
479
480     //////////////////////////////////////////
481
// MaterializationListener interface
482
//////////////////////////////////////////
483

484     public void beforeMaterialization(IndirectionHandler handler, Identity oid)
485     {
486         //noop
487
}
488
489     public void afterMaterialization(IndirectionHandler handler, Object JavaDoc 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 JavaDoc userObject = copyStrategy.copy(cacheObject, _pb);
502         handler.setRealSubject(userObject);
503         _original.put(oid, getFields(userObject, false, true));
504
505         // replace the proxy object with the real one
506
entry.userObject = userObject;
507         entry.cacheObject = cacheObject;
508         entry.handler.removeListener(this);
509         entry.handler = null;
510
511         // perform automatic lock for all reachable objects
512
// if the inserted object is materialized
513
try
514         {
515             lockReachableObjects(oid, userObject, cacheObject, lock, new Stack JavaDoc(), true);
516         }
517         catch (LockingException ex)
518         {
519             throw new LockingPassthruException(ex);
520         }
521     }
522
523
524
525     //////////////////////////////////////////
526
// Other operations
527
//////////////////////////////////////////
528

529     /**
530      *
531      * Commit this context into the persistent store.
532      * The EditingContext is not usable after a commit.
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      * Writes all changes in this context into the persistent store.
557      *
558      */

559     public void checkpoint() throws TransactionAbortedException
560     {
561         checkpointInternal(false);
562         _checkpointed = new HashMap JavaDoc();
563         for (Iterator JavaDoc 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      * Writes all changes in this context into the persistent store.
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 JavaDoc changedCollections = new ArrayList JavaDoc();
597
598         // sort objects in the order of oid.hashCode to avoid deadlocks
599
Arrays.sort(lockOrder, new Comparator JavaDoc()
600         {
601             public int compare(Object JavaDoc o1, Object JavaDoc o2)
602             {
603                 return o1.hashCode() - o2.hashCode();
604             }
605
606             public boolean equals(Object JavaDoc obj)
607             {
608                 return false;
609             }
610         });
611
612         try {
613             // mark dirty objects and lock them for write
614
// also handle dependent objects and if there were inserted once,
615
// repeat this process for their dependants ("cascade create")
616
ArrayList JavaDoc newObjects = new ArrayList JavaDoc();
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) // invalidated
629
{
630                         continue;
631                     }
632
633                     if (entry.handler == null) // materialized
634
{
635                         if (!state.isDeleted())
636                         {
637                             Object JavaDoc[][] origFields = (Object JavaDoc[][]) _checkpointed.get(oid);
638                             Object JavaDoc[][] 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                                     // there are modified collections,
665
// so we need to lock the object and to swizzle it to cache
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                     // new objects are not locked, so we don't need to ensure the order
681
lockOrder = (Identity[]) newObjects.toArray(
682                             new Identity[countNewObjects]);
683                 }
684             }
685             while (countNewObjects > 0);
686
687             // Swizzle the context objects and the cache objects
688
for (Iterator JavaDoc 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                     // we create the special ObjectCache implememntation
698
// that returns cacheObject, not userObject
699
entry.userObject, entry.cacheObject, _pb, new ObjectCache()
700                             {
701                                 public Object JavaDoc 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 JavaDoc obj)
713                                 {
714                                     // do nothing
715
}
716
717                                 public boolean cacheIfNew(Identity oid, Object JavaDoc obj)
718                                 {
719                                     return false;
720                                 }
721
722                                 public void clear()
723                                 {
724                                     // do nothing
725
}
726
727                                 public void remove(Identity anOid)
728                                 {
729                                     // do nothing
730
}
731                             });
732                 }
733             }
734
735             // Cascade delete for dependent objects
736
int countCascadeDeleted;
737             do
738             {
739                 countCascadeDeleted = 0;
740                 // Use intermediate new ArrayList(_order) because _order
741
// may be changed during cascade delete
742
for (Iterator JavaDoc it = (new ArrayList JavaDoc(_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             // perform database operations
756
connMan.setBatchMode(true);
757             try
758             {
759                 for (Iterator JavaDoc 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                             // PB verifies object existence by default
779
_pb.store(entry.cacheObject);
780                         }
781                         else
782                         {
783                             // PB migth already created the object by auto-update
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 JavaDoc ex) {
807             ex.printStackTrace();
808             throw new TransactionAbortedException(ex);
809         }
810     }
811
812     /**
813      *
814      * Rollback all changes made during this transaction. The EditingContext is not usable after
815      * a rollback.
816      *
817      */

818     public void rollback()
819     {
820         for (Iterator JavaDoc 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 JavaDoc[][] origFields = (Object JavaDoc[][]) _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      * Rollback all changes made during this transaction to the given object.
838      *
839      */

840     public void refresh(Identity oid, Object JavaDoc object)
841     {
842         ContextEntry entry = (ContextEntry) _objects.get(oid);
843         Object JavaDoc[][] origFields = (Object JavaDoc[][]) _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 JavaDoc 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 JavaDoc 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 JavaDoc 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      * This method compared simple field values:
896      * there are some tricks...
897      */

898     private boolean isEqual(Object JavaDoc fld1, Object JavaDoc fld2)
899     {
900         if (fld1 == null || fld2 == null)
901         {
902             return (fld1 == fld2);
903         }
904         else if ((fld1 instanceof BigDecimal JavaDoc) && (fld2 instanceof BigDecimal JavaDoc))
905         {
906             return (((BigDecimal JavaDoc) fld1).compareTo((BigDecimal JavaDoc) fld2) == 0);
907         }
908         else if ((fld1 instanceof Date JavaDoc) && (fld2 instanceof Date JavaDoc))
909         {
910             return (((Date JavaDoc) fld1).getTime() == ((Date JavaDoc) fld2).getTime());
911         }
912         else
913         {
914             return fld1.equals(fld2);
915         }
916     }
917
918     private boolean isModified(Object JavaDoc[] newFields, Object JavaDoc[] 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      * @param addListeners Whether to add CollectionProxy listeners
938      * @return four arrays of field values:
939      * 1) The class, simple fields, identities of references
940      * 2) collections of identities
941      * 3) references (parallel to identities of references in 1)
942      * 4) collections of objects (parallel to collections of identities in 2)
943      * if "withObjects" parameter is "false", then returns nulls
944      * in places of 3) and 4)
945      */

946     private Object JavaDoc[][] getFields(Object JavaDoc obj, boolean withObjects, boolean addListeners)
947     {
948         ClassDescriptor mif = _pb.getClassDescriptor(obj.getClass());
949         FieldDescriptor[] fieldDescs = mif.getFieldDescriptions();
950         Collection JavaDoc refDescs = mif.getObjectReferenceDescriptors();
951         Collection JavaDoc colDescs = mif.getCollectionDescriptors();
952         int count = 0;
953         Object JavaDoc[] fields = new Object JavaDoc[1 + fieldDescs.length + refDescs.size()];
954         ArrayList JavaDoc[] collections = new ArrayList JavaDoc[colDescs.size()];
955         Object JavaDoc[] references = null;
956         ArrayList JavaDoc[] collectionsOfObjects = null;
957         int lockForListeners = LockType.NO_LOCK;
958
959         if (withObjects)
960         {
961             references = new Object JavaDoc[refDescs.size()];
962             collectionsOfObjects = new ArrayList JavaDoc[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(); // we must notice if the object class changes
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 JavaDoc it = refDescs.iterator(); it.hasNext(); count++, countRefs++)
984         {
985             ObjectReferenceDescriptor rds = (ObjectReferenceDescriptor) it.next();
986             PersistentField f = rds.getPersistentField();
987             Object JavaDoc 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 JavaDoc it = colDescs.iterator(); it.hasNext(); count++)
1000        {
1001            CollectionDescriptor cds = (CollectionDescriptor) it.next();
1002            PersistentField f = cds.getPersistentField();
1003            Class JavaDoc type = f.getType();
1004            Object JavaDoc 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 JavaDoc();
1019                    }
1020                    _colProxyListeners.put(listener, col);
1021                }
1022                continue;
1023            }
1024
1025            if (col != null)
1026            {
1027                ArrayList JavaDoc list = new ArrayList JavaDoc();
1028                ArrayList JavaDoc listOfObjects = null;
1029                Iterator JavaDoc colIterator;
1030
1031                collections[count] = list;
1032                if (withObjects)
1033                {
1034                    listOfObjects = new ArrayList JavaDoc();
1035                    collectionsOfObjects[count] = listOfObjects;
1036                }
1037
1038                if (Collection JavaDoc.class.isAssignableFrom(type))
1039                {
1040                    colIterator = ((Collection JavaDoc) 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 JavaDoc 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 JavaDoc[][] {fields, collections, references, collectionsOfObjects};
1064    }
1065
1066    private void setFields(Object JavaDoc obj, Object JavaDoc[][] fieldsAndCollections)
1067    {
1068        ClassDescriptor mif = _pb.getClassDescriptor(obj.getClass());
1069        FieldDescriptor[] fieldDescs = mif.getFieldDescriptions();
1070        Collection JavaDoc refDescs = mif.getObjectReferenceDescriptors();
1071        Collection JavaDoc colDescs = mif.getCollectionDescriptors();
1072        Object JavaDoc[] fields = fieldsAndCollections[0];
1073        ArrayList JavaDoc[] collections = (ArrayList JavaDoc[]) 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 JavaDoc 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 JavaDoc 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 JavaDoc it = colDescs.iterator(); it.hasNext(); count++)
1112        {
1113            CollectionDescriptor cds = (CollectionDescriptor) it.next();
1114            PersistentField f = cds.getPersistentField();
1115            ArrayList JavaDoc list = collections[count];
1116            ArrayList JavaDoc newCol;
1117
1118            if (list == null)
1119            {
1120                f.set(obj, null);
1121            }
1122            else
1123            {
1124                newCol = new ArrayList JavaDoc();
1125                for (Iterator JavaDoc it2 = list.iterator(); it2.hasNext(); )
1126                {
1127                    Identity relOid = (Identity) it2.next();
1128                    Object JavaDoc 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 JavaDoc obj, PersistentField f, List JavaDoc newCol)
1141    {
1142        Class JavaDoc type = f.getType();
1143
1144        if (Collection JavaDoc.class.isAssignableFrom(type))
1145        {
1146            Collection JavaDoc col = (Collection JavaDoc) f.get(obj);
1147
1148            if (col == null)
1149            {
1150                if (type == List JavaDoc.class || type == Collection JavaDoc.class)
1151                {
1152                    col = new ArrayList JavaDoc();
1153                }
1154                else if (type == Set JavaDoc.class)
1155                {
1156                    col = new HashSet JavaDoc();
1157                }
1158                else
1159                {
1160                    try
1161                    {
1162                        col = (Collection JavaDoc) type.newInstance();
1163                    }
1164                    catch (Throwable JavaDoc 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 JavaDoc)
1178                    {
1179                        col = new ListProxyDefaultImpl(_pb.getPBKey(), cp.getData().getClass(), null);
1180                    }
1181                    else if (col instanceof Set JavaDoc)
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 JavaDoc) col.getClass().newInstance();
1196                    }
1197                    catch (Exception JavaDoc 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 JavaDoc 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     * Does the given class has bidirectional assiciation
1223     * with some other class?
1224     */

1225    private boolean hasBidirectionalAssociation(Class JavaDoc clazz)
1226    {
1227        ClassDescriptor cdesc;
1228        Collection JavaDoc 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        // first time we meet this class, let's look at metadata
1242
cdesc = _pb.getClassDescriptor(clazz);
1243        refs = cdesc.getObjectReferenceDescriptors();
1244        hasBidirAssc = false;
1245        REFS_CYCLE:
1246        for (Iterator JavaDoc it = refs.iterator(); it.hasNext(); )
1247        {
1248            ObjectReferenceDescriptor ord;
1249            ClassDescriptor relCDesc;
1250            Collection JavaDoc relRefs;
1251
1252            ord = (ObjectReferenceDescriptor) it.next();
1253            relCDesc = _pb.getClassDescriptor(ord.getItemClass());
1254            relRefs = relCDesc.getObjectReferenceDescriptors();
1255            for (Iterator JavaDoc 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     * @return number of deleted objects: 1 or 0 (if the object is already deleted)
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 JavaDoc("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) // remove collection item before main obj
1305
{
1306                    if (dependentIndex > mainIndex)
1307                    {
1308                        _order.remove(dependentIndex);
1309                        _order.add(mainIndex, oid);
1310                    }
1311                }
1312                else // remove reference after main obj
1313
{
1314                    if (dependentIndex < mainIndex)
1315                    {
1316                        _order.remove(dependentIndex); // this causes mainIndex--
1317
_order.add(mainIndex, oid);
1318                    }
1319                }
1320
1321            }
1322            return 1;
1323        }
1324    }
1325
1326    /**
1327     * Mark for creation all newly introduced dependent references.
1328     * Mark for deletion all nullified dependent references.
1329     * @return the list of created objects
1330     */

1331    private ArrayList JavaDoc handleDependentReferences(Identity oid, Object JavaDoc userObject,
1332            Object JavaDoc[] origFields, Object JavaDoc[] newFields, Object JavaDoc[] newRefs)
1333            throws LockingException
1334    {
1335        ClassDescriptor mif = _pb.getClassDescriptor(userObject.getClass());
1336        FieldDescriptor[] fieldDescs = mif.getFieldDescriptions();
1337        Collection JavaDoc refDescs = mif.getObjectReferenceDescriptors();
1338        int count = 1 + fieldDescs.length;
1339        ArrayList JavaDoc newObjects = new ArrayList JavaDoc();
1340        int countRefs = 0;
1341
1342        for (Iterator JavaDoc 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 JavaDoc relObj = newRefs[countRefs];
1357                        insertInternal(newOid, relObj, LockType.WRITE_LOCK,
1358                                       true, oid, new Stack JavaDoc());
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     * Mark for creation all objects that were included into dependent collections.
1375     * Mark for deletion all objects that were excluded from dependent collections.
1376     */

1377    private ArrayList JavaDoc handleDependentCollections(Identity oid, Object JavaDoc obj,
1378            Object JavaDoc[] origCollections, Object JavaDoc[] newCollections,
1379            Object JavaDoc[] newCollectionsOfObjects)
1380            throws LockingException
1381    {
1382        ClassDescriptor mif = _pb.getClassDescriptor(obj.getClass());
1383        Collection JavaDoc colDescs = mif.getCollectionDescriptors();
1384        ArrayList JavaDoc newObjects = new ArrayList JavaDoc();
1385        int count = 0;
1386
1387        for (Iterator JavaDoc it = colDescs.iterator(); it.hasNext(); count++)
1388        {
1389            CollectionDescriptor cds = (CollectionDescriptor) it.next();
1390
1391            if (cds.getOtmDependent())
1392            {
1393                ArrayList JavaDoc origList = (origCollections == null ? null
1394                                        : (ArrayList JavaDoc) origCollections[count]);
1395                ArrayList JavaDoc newList = (ArrayList JavaDoc) newCollections[count];
1396
1397                if (origList != null)
1398                {
1399                    for (Iterator JavaDoc 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 JavaDoc 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 JavaDoc relCol = (ArrayList JavaDoc)
1424                                        newCollectionsOfObjects[count];
1425                                Object JavaDoc relObj = relCol.get(countElem);
1426                                insertInternal(newOid, relObj, LockType.WRITE_LOCK,
1427                                               true, null, new Stack JavaDoc());
1428                                newObjects.add(newOid);
1429                            }
1430                        }
1431                    }
1432                }
1433            }
1434        }
1435
1436        return newObjects;
1437    }
1438
1439    /**
1440     * Mark for deletion all dependent objects (via references and collections).
1441     * @return the number of deleted objects
1442     */

1443    private int doCascadeDelete(Identity oid, Object JavaDoc obj)
1444    {
1445        ClassDescriptor mif = _pb.getClassDescriptor(ProxyHelper.getRealClass(obj));
1446        Collection JavaDoc refDescs = mif.getObjectReferenceDescriptors();
1447        Collection JavaDoc colDescs = mif.getCollectionDescriptors();
1448        int countCascadeDeleted = 0;
1449
1450        for (Iterator JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc type = f.getType();
1475                Object JavaDoc col = f.get(obj);
1476
1477                if (col != null)
1478                {
1479                    Iterator JavaDoc colIterator;
1480
1481                    if (Collection JavaDoc.class.isAssignableFrom(type))
1482                    {
1483                        colIterator = ((Collection JavaDoc) 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     * The rest of ObjectCache implementation for swizling
1509     * All methods except lookup() are never used by swizzling,
1510     * remove() appeared to already exist in this class
1511     * with the same signature as in ObjectCache interface,
1512     * other methods are unsupported.
1513     */

1514    public void cache(Identity oid, Object JavaDoc obj)
1515    {
1516        throw new UnsupportedOperationException JavaDoc();
1517    }
1518
1519    public boolean cacheIfNew(Identity oid, Object JavaDoc obj)
1520    {
1521        // not implemented
1522
throw new UnsupportedOperationException JavaDoc("Not implemented");
1523    }
1524
1525    public void clear()
1526    {
1527        throw new UnsupportedOperationException JavaDoc();
1528    }
1529
1530
1531    //////////////////////////////////////////
1532
// Inner classes
1533
//////////////////////////////////////////
1534

1535    private static class ContextEntry
1536    {
1537        Object JavaDoc userObject;
1538        Object JavaDoc cacheObject;
1539        State state = State.PERSISTENT_CLEAN;
1540
1541        /**
1542         * Handler the proxy object, null if the object is real
1543         */

1544        IndirectionHandler handler;
1545
1546        /**
1547         * This flag is used during commit/checkpoint
1548         */

1549        boolean needsCacheSwizzle;
1550
1551        ContextEntry(Object JavaDoc 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 JavaDoc[] _collections;
1570        private final int _index;
1571        private final int _lock;
1572
1573        OTMCollectionProxyListener(CollectionDescriptor cds,
1574                ArrayList JavaDoc[] 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            // do nothing
1585
}
1586
1587        /**
1588         * The collection proxy contains PB cache objects. We have to replace it
1589         * with a collection of user objects.
1590         */

1591        public void afterLoading(CollectionProxyDefaultImpl colProxy)
1592        {
1593            ArrayList JavaDoc list = new ArrayList JavaDoc();
1594            ArrayList JavaDoc newUserCol = new ArrayList JavaDoc();
1595            LockManager lockManager = LockManager.getInstance();
1596            _collections[_index] = list;
1597
1598            for (Iterator JavaDoc it = colProxy.iterator(); it.hasNext(); )
1599            {
1600                Object JavaDoc relUserObj;
1601                Object JavaDoc 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 JavaDoc());
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}
1638
Popular Tags