KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > oracle > toplink > essentials > internal > ejb > cmp3 > base > RepeatableWriteUnitOfWork


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the "License"). You may not use this file except
5  * in compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * glassfish/bootstrap/legal/CDDLv1.0.txt or
9  * https://glassfish.dev.java.net/public/CDDLv1.0.html.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * HEADER in each file and include the License file at
15  * glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable,
16  * add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your
18  * own identifying information: Portions Copyright [yyyy]
19  * [name of copyright owner]
20  */

21 // Copyright (c) 1998, 2006, Oracle. All rights reserved.
22
package oracle.toplink.essentials.internal.ejb.cmp3.base;
23
24 import java.util.Enumeration JavaDoc;
25
26 import oracle.toplink.essentials.descriptors.ClassDescriptor;
27 import oracle.toplink.essentials.internal.descriptors.DescriptorIterator;
28 import oracle.toplink.essentials.internal.helper.IdentityHashtable;
29 import oracle.toplink.essentials.internal.localization.ExceptionLocalization;
30 import oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl;
31 import oracle.toplink.essentials.exceptions.DatabaseException;
32 import oracle.toplink.essentials.exceptions.OptimisticLockException;
33 import oracle.toplink.essentials.internal.sessions.UnitOfWorkChangeSet;
34 import oracle.toplink.essentials.internal.sessions.ObjectChangeSet;
35 import oracle.toplink.essentials.mappings.ForeignReferenceMapping;
36
37
38 public class RepeatableWriteUnitOfWork extends UnitOfWorkImpl {
39     
40     /** Used to store the final UnitOfWorkChangeSet for merge into the shared cache */
41     protected UnitOfWorkChangeSet cumulativeUOWChangeSet;
42     /** Used to store objects already deleted from the db and unregistered */
43     protected IdentityHashtable unregisteredDeletedObjectsCloneToBackupAndOriginal;
44     
45     /** Used to determine if UnitOfWork should commit and rollback transactions
46      * This is used when an EntityTransaction is controlling the transaction
47      */

48     protected boolean shouldTerminateTransaction;
49     
50     public RepeatableWriteUnitOfWork(oracle.toplink.essentials.internal.sessions.AbstractSession parentSession){
51         super(parentSession);
52         this.shouldTerminateTransaction = true;
53     }
54     
55     /**
56      * INTERNAL:
57      * This method will clear all registered objects from this UnitOfWork.
58      */

59     public void clear(){
60         this.getIdentityMapAccessor().initializeIdentityMaps();
61         this.cloneToOriginals = null;
62         this.cloneMapping = new IdentityHashtable();;
63         this.newObjectsCloneToOriginal = null;
64         this.newObjectsOriginalToClone = null;
65         this.deletedObjects = null;
66         this.allClones = null;
67         this.objectsDeletedDuringCommit = null;
68         this.removedObjects = null;
69         this.unregisteredNewObjects = null;
70         this.unregisteredExistingObjects = null;
71         this.newAggregates = null;
72         this.unitOfWorkChangeSet = null;
73         this.pessimisticLockedObjects = null;
74         this.optimisticReadLockObjects = null;
75     }
76     
77     /**
78      * INTERNAL:
79      * Commit the changes to any objects to the parent.
80      */

81     public void commitRootUnitOfWork() throws DatabaseException, OptimisticLockException {
82         commitToDatabaseWithChangeSet(false);
83         // unit of work has been committed so it's ok to set the cumulative into the UOW for merge
84
if(this.cumulativeUOWChangeSet != null) {
85             this.cumulativeUOWChangeSet.mergeUnitOfWorkChangeSet((UnitOfWorkChangeSet)this.getUnitOfWorkChangeSet(), this, true);
86             setUnitOfWorkChangeSet(this.cumulativeUOWChangeSet);
87         }
88
89         commitTransactionAfterWriteChanges(); // this method will commit the transaction
90
// and set the transaction flags appropriately
91

92         // Merge after commit
93
mergeChangesIntoParent();
94     }
95
96     /**
97      * INTERNAL:
98      * Traverse the object to find references to objects not registered in this unit of work.
99      */

100     public void discoverUnregisteredNewObjects(Object JavaDoc clone, IdentityHashtable knownNewObjects, IdentityHashtable unregisteredExistingObjects, IdentityHashtable visitedObjects) {
101         // This define an inner class for process the itteration operation, don't be scared, its just an inner class.
102
DescriptorIterator iterator = new DescriptorIterator() {
103             public void iterate(Object JavaDoc object) {
104                 // If the object is read-only the do not continue the traversal.
105
if (isClassReadOnly(object.getClass()) || isObjectDeleted(object)) {
106                     this.setShouldBreak(true);
107                     return;
108                 }
109                 //check for null mapping, this may be the first iteration
110
if ((getCurrentMapping() != null) && ((ForeignReferenceMapping)getCurrentMapping()).isCascadePersist() ){
111                     ((RepeatableWriteUnitOfWork)getSession()).registerNewObjectForPersist(object, new IdentityHashtable());
112                 }else{
113                     if (!getCloneMapping().containsKey(object)){
114                         if (! checkForUnregisteredExistingObject(object)){
115                             throw new IllegalStateException JavaDoc(ExceptionLocalization.buildMessage("new_object_found_during_commit", new Object JavaDoc[]{object}));
116                         }else{
117                             ((IdentityHashtable)getUnregisteredExistingObjects()).put(object, object);
118                             this.setShouldBreak(true);
119                             return;
120                         }
121                     }
122                 }
123             }
124         };
125
126         //set the collection in the UnitofWork to be this list
127
setUnregisteredExistingObjects(unregisteredExistingObjects);
128
129         iterator.setVisitedObjects(visitedObjects);
130         iterator.setResult(knownNewObjects);
131         iterator.setSession(this);
132         // When using wrapper policy in EJB the iteration should stop on beans,
133
// this is because EJB forces beans to be registered anyway and clone identity can be violated
134
// and the violated clones references to session objects should not be traversed.
135
iterator.setShouldIterateOverWrappedObjects(false);
136         iterator.startIterationOn(clone);
137     }
138     
139     /**
140      * INTERNAL:
141      * Has writeChanges() been attempted on this UnitOfWork? It may have
142      * either suceeded or failed but either way the UnitOfWork is in a highly
143      * restricted state.
144      */

145     public boolean isAfterWriteChangesButBeforeCommit() {
146         //dont' check for writechanges failure.
147
return (getLifecycle() == CommitTransactionPending);
148     }
149
150     /**
151      * INTERNAL:
152      * Return if the object has been deleted in this unit of work.
153      */

154     public boolean isObjectDeleted(Object JavaDoc object) {
155         if(super.isObjectDeleted(object)) {
156             return true;
157         } else {
158             if(unregisteredDeletedObjectsCloneToBackupAndOriginal != null) {
159                 if(unregisteredDeletedObjectsCloneToBackupAndOriginal.containsKey(object)) {
160                     return true;
161                 }
162             }
163             if (hasObjectsDeletedDuringCommit()) {
164                 return getObjectsDeletedDuringCommit().containsKey(object);
165             } else {
166                 return false;
167             }
168         }
169     }
170
171     /**
172      * INTERNAL:
173      * For synchronized units of work, dump SQL to database
174      */

175     public void issueSQLbeforeCompletion() {
176
177         super.issueSQLbeforeCompletion(false);
178
179         if (this.cumulativeUOWChangeSet != null && this.getUnitOfWorkChangeSet() != null){
180             // unit of work has been committed so it's ok to set the cumulative into the UOW for merge
181
this.cumulativeUOWChangeSet.mergeUnitOfWorkChangeSet((UnitOfWorkChangeSet)this.getUnitOfWorkChangeSet(), this, true);
182             setUnitOfWorkChangeSet(this.cumulativeUOWChangeSet);
183         }
184
185         commitTransactionAfterWriteChanges(); // this method will commit the transaction
186
// and set the transaction flags appropriately
187
}
188
189     /**
190      * INTERNAL:
191      * This method is used internally to update the tracked objects if required
192      */

193     public void updateChangeTrackersIfRequired(Object JavaDoc objectToWrite, ObjectChangeSet changeSetToWrite, UnitOfWorkImpl uow, ClassDescriptor descriptor) {
194         descriptor.getObjectChangePolicy().updateWithChanges(objectToWrite, changeSetToWrite, uow, descriptor);
195     }
196
197     /**
198      * INTERNAL:
199      * This method will cause the all of the tracked objects at this level to have
200      * their changes written to the database. It will then decrement the depth
201      * level.
202      */

203     public void writeChanges() {
204             if(unregisteredDeletedObjectsCloneToBackupAndOriginal == null) {
205                 unregisteredDeletedObjectsCloneToBackupAndOriginal = new IdentityHashtable(2);
206             }
207             IdentityHashtable allObjectsList = new IdentityHashtable();
208             IdentityHashtable visitedNodes = new IdentityHashtable(2);
209             IdentityHashtable newObjects = new IdentityHashtable(2);
210             IdentityHashtable existingObjects = new IdentityHashtable(2);
211             IdentityHashtable insertedNewObjects = new IdentityHashtable(2);
212             for (Enumeration JavaDoc clones = getCloneMapping().keys(); clones.hasMoreElements();){
213                 Object JavaDoc object = clones.nextElement();
214                 discoverUnregisteredNewObjects(object, newObjects, existingObjects, visitedNodes);
215                 allObjectsList.put(object, object);
216             }
217             for (Enumeration JavaDoc newClones = getNewObjectsCloneToOriginal().keys();newClones.hasMoreElements();){
218                 Object JavaDoc object = newClones.nextElement();
219                 assignSequenceNumber(object);
220                 insertedNewObjects.put(object, object);
221                 // add potentially newly discovered new objects
222
allObjectsList.put(object, object);
223             }
224
225             if (getUnitOfWorkChangeSet() == null) {
226                 setUnitOfWorkChangeSet(new UnitOfWorkChangeSet());
227             }
228             calculateChanges(allObjectsList, (UnitOfWorkChangeSet)getUnitOfWorkChangeSet());
229             // write those changes to the database.
230
UnitOfWorkChangeSet changeSet = (UnitOfWorkChangeSet)getUnitOfWorkChangeSet();
231             if (!changeSet.hasChanges() && !changeSet.hasForcedChanges() && ! this.hasDeletedObjects() && ! this.hasModifyAllQueries()){
232                 return;
233             }
234             try {
235                 commitToDatabaseWithPreBuiltChangeSet(changeSet, false);
236                 this.writesCompleted();
237             } catch (RuntimeException JavaDoc ex) {
238                 setLifecycle(WriteChangesFailed);
239                 throw ex;
240             }
241             //bug 4730595: fix puts deleted objects in the UnitOfWorkChangeSet as they are removed.
242
getDeletedObjects().clear();
243
244             // unregister all deleted objects,
245
// keep them along with their original and backup values in unregisteredDeletedObjectsCloneToBackupAndOriginal
246
Enumeration JavaDoc enumDeleted = getObjectsDeletedDuringCommit().keys();
247             while(enumDeleted.hasMoreElements()) {
248                 Object JavaDoc deletedObject = enumDeleted.nextElement();
249                 Object JavaDoc[] backupAndOriginal = {getCloneMapping().get(deletedObject), getCloneToOriginals().get(deletedObject)};
250                 unregisteredDeletedObjectsCloneToBackupAndOriginal.put(deletedObject, backupAndOriginal);
251                 unregisterObject(deletedObject);
252             }
253             getObjectsDeletedDuringCommit().clear();
254
255             if(this.cumulativeUOWChangeSet == null) {
256                 this.cumulativeUOWChangeSet = (UnitOfWorkChangeSet)getUnitOfWorkChangeSet();
257             } else {
258                 //merge those changes back into the backup clones and the final uowChangeSet
259
this.cumulativeUOWChangeSet.mergeUnitOfWorkChangeSet((UnitOfWorkChangeSet)getUnitOfWorkChangeSet(), this, true);
260             }
261             //clean up
262
setUnitOfWorkChangeSet(new UnitOfWorkChangeSet());
263             Enumeration JavaDoc enumtr = insertedNewObjects.elements();
264             while (enumtr.hasMoreElements()) {
265                 Object JavaDoc clone = enumtr.nextElement();
266                 Object JavaDoc original = getNewObjectsCloneToOriginal().remove(clone);
267                 if (original != null) {
268                     getNewObjectsOriginalToClone().remove(original);
269                     //no longer new to this unit of work
270
getCloneToOriginals().put(clone, original);
271                 }
272             }
273         }
274
275     /**
276      * INTERNAL:
277      * Called only by registerNewObjectForPersist method,
278      * and only if newObject is not already registered.
279      * If newObject is found in
280      * unregisteredDeletedObjectsCloneToBackupAndOriginal then it's re-registered,
281      * otherwise the superclass method called.
282      */

283     protected void registerNotRegisteredNewObjectForPersist(Object JavaDoc newObject, ClassDescriptor descriptor) {
284         if(unregisteredDeletedObjectsCloneToBackupAndOriginal != null) {
285             Object JavaDoc[] backupAndOriginal = (Object JavaDoc[])unregisteredDeletedObjectsCloneToBackupAndOriginal.remove(newObject);
286             if(backupAndOriginal != null) {
287                 // backup
288
getCloneMapping().put(newObject, backupAndOriginal[0]);
289                 // original
290
registerNewObjectClone(newObject, backupAndOriginal[1]);
291
292                 // Check if the new objects should be cached.
293
registerNewObjectInIdentityMap(newObject, newObject);
294                 
295                 return;
296             }
297         }
298         super.registerNotRegisteredNewObjectForPersist(newObject, descriptor);
299     }
300
301     /**
302      * INTERNAL:
303      * This is internal to the uow, transactions should not be used explictly in a uow.
304      * The uow shares its parents transactions.
305      */

306     public void rollbackTransaction() throws DatabaseException {
307         if (this.shouldTerminateTransaction || getParent().getTransactionMutex().isNested()){
308             super.rollbackTransaction();
309         }else{
310             //rollback called which means txn failed.
311
//but rollback was stopped by entitytransaction which means the
312
//transaction will want to call release later. Make sure release
313
//will rollback transaction.
314
setWasTransactionBegunPrematurely(true);
315         }
316     }
317
318     /**
319      * INTERNAL
320      * Synchronize the clones and update their backup copies.
321      * Called after commit and commit and resume.
322      */

323     public void synchronizeAndResume() {
324         this.cumulativeUOWChangeSet = null;
325         super.synchronizeAndResume();
326     }
327     
328     /**
329      * INTERNAL:
330      * Called only by UnitOfWorkIdentityMapAccessor.getAndCloneCacheKeyFromParent method.
331      * Return unregisteredDeletedClone corresponding to the passed original, or null
332      */

333     public Object JavaDoc getUnregisteredDeletedCloneForOriginal(Object JavaDoc original) {
334         if(unregisteredDeletedObjectsCloneToBackupAndOriginal != null) {
335             Enumeration JavaDoc keys = unregisteredDeletedObjectsCloneToBackupAndOriginal.keys();
336             Enumeration JavaDoc values = unregisteredDeletedObjectsCloneToBackupAndOriginal.elements();
337             while(keys.hasMoreElements()) {
338                 Object JavaDoc deletedObjectClone = keys.nextElement();
339                 Object JavaDoc[] backupAndOriginal = (Object JavaDoc[])values.nextElement();
340                 Object JavaDoc currentOriginal = backupAndOriginal[1];
341                 if(original == currentOriginal) {
342                     return deletedObjectClone;
343                 }
344             }
345         }
346         return null;
347     }
348     
349   /**
350    * INTERNAL:
351    * Wraps the oracle.toplink.essentials.exceptions.OptimisticLockException in a
352    * javax.persistence.OptimisticLockException. This conforms to the EJB3 specs
353    * @param commitTransaction
354    */

355     protected void commitToDatabase(boolean commitTransaction) {
356         try {
357             super.commitToDatabase(commitTransaction);
358         } catch (oracle.toplink.essentials.exceptions.OptimisticLockException ole) {
359             throw new javax.persistence.OptimisticLockException(ole);
360         }
361     }
362
363     /**
364      * INTERNAL:
365      * This is internal to the uow, transactions should not be used explictly in a uow.
366      * The uow shares its parents transactions.
367      */

368     public void commitTransaction() throws DatabaseException {
369         if (this.shouldTerminateTransaction || getParent().getTransactionMutex().isNested()){
370             super.commitTransaction();
371         }
372     }
373
374     public void setShouldTerminateTransaction(boolean shouldTerminateTransaction) {
375         this.shouldTerminateTransaction = shouldTerminateTransaction;
376     }
377 }
378
Popular Tags