KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > oracle > toplink > essentials > internal > sessions > UnitOfWorkChangeSet


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, 2005, Oracle. All rights reserved.
22
package oracle.toplink.essentials.internal.sessions;
23
24 import java.util.*;
25 import java.io.*;
26 import oracle.toplink.essentials.internal.helper.*;
27 import oracle.toplink.essentials.descriptors.ClassDescriptor;
28
29 /**
30  * <p>
31  * <b>Purpose</b>: This is the overall collection of changes.
32  * <p>
33  * <b>Description</b>: It holds all of the object changes and
34  * all ObjectChanges, with the same classType and primary keys, referenced in a changeSet should be
35  * the same object.
36  * <p>
37  */

38 public class UnitOfWorkChangeSet implements Serializable, oracle.toplink.essentials.changesets.UnitOfWorkChangeSet {
39
40     /** This is the collection of ObjectChanges held by this ChangeSet */
41
42     // Holds a hashtable of objectChageSets keyed on class
43
transient protected java.util.Hashtable JavaDoc objectChanges;
44
45     //This collection holds the new objects which will have no real identity until inserted
46
transient protected java.util.Hashtable JavaDoc newObjectChangeSets;
47     transient protected oracle.toplink.essentials.internal.helper.IdentityHashtable cloneToObjectChangeSet;
48     transient protected oracle.toplink.essentials.internal.helper.IdentityHashtable objectChangeSetToUOWClone;
49     protected IdentityHashtable aggregateList;
50     protected IdentityHashtable allChangeSets;
51     protected IdentityHashtable deletedObjects;
52
53     /** This attribute is set to true if a changeSet with changes has been added */
54     protected boolean hasChanges;
55     protected boolean hasForcedChanges;
56
57     /* Collection of ObjectChangeSets that is built from other collections and mapped with SDK */
58     private transient Vector sdkAllChangeSets;
59     private transient int objectChangeSetCounter = 0;
60
61     /**
62      * INTERNAL:
63      * Create a ChangeSet
64      */

65     public UnitOfWorkChangeSet() {
66         super();
67         this.setHasChanges(false);
68     }
69
70     /**
71      * INTERNAL:
72      * Recreate a UnitOfWorkChangeSet that has been converted to a byte array with the
73      * getByteArrayRepresentation() method.
74      */

75     public UnitOfWorkChangeSet(byte[] bytes) throws java.io.IOException JavaDoc, ClassNotFoundException JavaDoc {
76         java.io.ByteArrayInputStream JavaDoc byteIn = new java.io.ByteArrayInputStream JavaDoc(bytes);
77         ObjectInputStream objectIn = new ObjectInputStream(byteIn);
78         //bug 4416412: allChangeSets set directly instead of using setInternalAllChangeSets
79
allChangeSets = (IdentityHashtable)objectIn.readObject();
80         deletedObjects = (IdentityHashtable)objectIn.readObject();
81     }
82
83     /**
84      * INTERNAL:
85      * Add the Deleted objects to the changeSet
86      * @param objectChanges prototype.changeset.ObjectChanges
87      */

88     public void addDeletedObjects(IdentityHashtable deletedObjects, AbstractSession session) {
89         Enumeration enumtr = deletedObjects.keys();
90         while (enumtr.hasMoreElements()) {
91             Object JavaDoc object = enumtr.nextElement();
92
93             this.addDeletedObject(object, session);
94         }
95     }
96     
97     /**
98      * INTERNAL:
99      * Add the Deleted object to the changeSet
100      * @param objectChanges prototype.changeset.ObjectChanges
101      */

102     public void addDeletedObject(Object JavaDoc object, AbstractSession session) {
103         //CR 4080 - must prevent aggregate objects added to DeletedObjects list
104
ClassDescriptor descriptor = session.getDescriptor(object);
105         if (!descriptor.isAggregateCollectionDescriptor()) {
106             ObjectChangeSet set = descriptor.getObjectBuilder().createObjectChangeSet(object, this, false, session);
107
108             // needed for xml change set
109
set.setShouldBeDeleted(true);
110             getDeletedObjects().put(set, set);
111         }
112     }
113
114     /**
115      * INTERNAL:
116      * Add to the changes for 'object' object to this changeSet. This method will not
117      * add to the lists that are used for identity lookups.
118      * The passed change set *must* either have changes or forced changes.
119      * @see addObjectChangeSetForIdentity()
120      * @param objectChanges prototype.changeset.ObjectChanges
121      * @param object java.lang.Object
122      */

123     public void addObjectChangeSet(ObjectChangeSet objectChanges) {
124         if ((objectChanges == null)) {
125             return;
126         }
127
128         // If this object change set has changes or forced changes then record this. Must
129
// be done for each change set added because some may not contain 'real' changes. This
130
// is the case for opt. read lock and forceUdpate. Keep the flags separate because
131
// we don't want to cache sync. a change set with no 'real' changes.
132
boolean objectChangeSetHasChanges = objectChanges.hasChanges();
133         if (objectChangeSetHasChanges) {
134             this.setHasChanges(true);
135             this.hasForcedChanges = this.hasForcedChanges || objectChanges.hasForcedChanges();
136         } else {
137             // object change set doesn't have changes so it has to have forced changes.
138
this.hasForcedChanges = true;
139         }
140
141         if (!objectChanges.isAggregate()) {
142             if (objectChangeSetHasChanges) {
143                 // Each time I create a changeSet it is added to this list and when I compute a changeSet for this
144
// object I again add it to these lists so that before this UOWChangeSet is
145
// Serialised there is a copy of every changeSet which has changes affecting cache
146
// in allChangeSets
147
getAllChangeSets().put(objectChanges, objectChanges);
148             }
149             
150             if (objectChanges.getCacheKey() != null) {
151                 Hashtable table = (Hashtable)getObjectChanges().get(objectChanges.getClassName());
152
153                 if (table == null) {
154                     table = new Hashtable(2);
155                     getObjectChanges().put(objectChanges.getClassName(), table);
156                     table.put(objectChanges, objectChanges);
157                 } else {
158                     table.put(objectChanges, objectChanges);
159                 }
160             }
161         }
162     }
163
164     /**
165      * INTERNAL:
166      * Add to the changes for 'object' object to this changeSet. This method will not
167      * add to the lists that are used for identity lookups. It is called specifically
168      * for new objects, and new object will be moved to the standard changes list by
169      * the QueryMechanism after insert.
170      * @see addObjectChangeSetForIdentity()
171      * @param objectChanges the new object change set
172      */

173     public void addNewObjectChangeSet(ObjectChangeSet objectChanges, AbstractSession session) {
174         if ((objectChanges == null)) {
175             return;
176         }
177         IdentityHashtable changeSetTable = (IdentityHashtable)getNewObjectChangeSets().get(objectChanges.getClassType(session));
178         if (changeSetTable == null) {
179             // 2612538 - the default size of IdentityHashtable (32) is appropriate
180
changeSetTable = new IdentityHashtable();
181             getNewObjectChangeSets().put(objectChanges.getClassType(session), changeSetTable);
182         }
183         changeSetTable.put(objectChanges, objectChanges);
184     }
185
186     /**
187      * INTERNAL:
188      * This method can be used find the equivalent changeset within this UnitOfWorkChangeSet
189      * Aggregates, and new objects without primaryKeys from serialized ChangeSets will not be found
190      * Which may result in duplicates, in the UnitOfWorkChangeSet.
191      */

192     public ObjectChangeSet findObjectChangeSet(ObjectChangeSet changeSet, UnitOfWorkChangeSet mergeFromChangeSet) {
193         Hashtable changes = (Hashtable)getObjectChanges().get(changeSet.getClassName());
194         ObjectChangeSet potential = null;
195         if (changes != null) {
196             potential = (ObjectChangeSet)changes.get(changeSet);
197         }
198         if (potential == null) {
199             potential = (ObjectChangeSet)this.getObjectChangeSetForClone(changeSet.getUnitOfWorkClone());
200         }
201         return potential;
202     }
203
204     /**
205      * INTERNAL:
206      * This method will be used during the merge process to either find an equivalent change set
207      * within this UnitOfWorkChangeSet or integrate that changeset into this UOW ChangeSet
208      */

209     public ObjectChangeSet findOrIntegrateObjectChangeSet(ObjectChangeSet tofind, UnitOfWorkChangeSet mergeFromChangeSet) {
210         if (tofind == null) {
211             return tofind;
212         }
213         ObjectChangeSet localChangeSet = this.findObjectChangeSet(tofind, mergeFromChangeSet);
214         if (localChangeSet == null) {//not found locally then replace it with the one from the merging changeset
215
localChangeSet = new ObjectChangeSet(tofind.getPrimaryKeys(), tofind.getUnitOfWorkClone(), this, tofind.isNew());
216             this.addObjectChangeSetForIdentity(localChangeSet, localChangeSet.getUnitOfWorkClone());
217         }
218         return localChangeSet;
219     }
220
221     /**
222      * INTERNAL:
223      * Add change records to the lists used to maintain identity. This will not actually
224      * add the changes to 'object' to the change set.
225      * @see addObjectChangeSet()
226      * @param objectChanges prototype.changeset.ObjectChanges
227      */

228     public void addObjectChangeSetForIdentity(ObjectChangeSet objectChanges, Object JavaDoc object) {
229         if ((objectChanges == null) || (object == null)) {
230             return;
231         }
232
233         if (objectChanges.isAggregate()) {
234             getAggregateList().put(objectChanges, objectChanges);
235         }
236
237         getObjectChangeSetToUOWClone().put(objectChanges, object);
238         getCloneToObjectChangeSet().put(object, objectChanges);
239
240     }
241
242     /**
243      * INTERNAL:
244      * Get the Aggregate list. Lazy initialises the hashtable if required
245      * @return oracle.toplink.essentials.internal.helper.IdentityHashtable
246      */

247     protected IdentityHashtable getAggregateList() {
248         if (aggregateList == null) {
249             aggregateList = new IdentityHashtable();
250         }
251         return aggregateList;
252     }
253
254     /**
255      * INTERNAL:
256      * This method returns a reference to the collection
257      * @return oracle.toplink.essentials.internal.helper.IdentityHashtable
258      */

259     public oracle.toplink.essentials.internal.helper.IdentityHashtable getAllChangeSets() {
260         if (this.allChangeSets == null) {
261             // 2612538 - the default size of IdentityHashtable (32) is appropriate
262
this.allChangeSets = new IdentityHashtable();
263         }
264         return allChangeSets;
265     }
266
267     /**
268      * INTERNAL:
269      * Get the clone to object change hash table. Lazy initialises the hashtable if required
270      * @return oracle.toplink.essentials.internal.helper.IdentityHashtable
271      */

272     public oracle.toplink.essentials.internal.helper.IdentityHashtable getCloneToObjectChangeSet() {
273         if (cloneToObjectChangeSet == null) {
274             cloneToObjectChangeSet = new IdentityHashtable();
275         }
276         return cloneToObjectChangeSet;
277     }
278
279     /**
280      * INTERNAL:
281      * This method returns the reference to the deleted objects from the changeSet
282      * @return oracle.toplink.essentials.internal.helper.IdentityHashtable
283      */

284     public oracle.toplink.essentials.internal.helper.IdentityHashtable getDeletedObjects() {
285         if (this.deletedObjects == null) {
286             // 2612538 - the default size of IdentityHashtable (32) is appropriate
287
this.deletedObjects = new IdentityHashtable();
288         }
289         return deletedObjects;
290     }
291
292     /**
293      * INTERNAL:
294      * Returns the ObjectChanges held by this ChangeSet.
295      * @return prototype.changeset.ObjectChanges
296      */

297     public Hashtable getObjectChanges() {
298         if (objectChanges == null) {
299             objectChanges = new Hashtable(2);
300         }
301         return objectChanges;
302     }
303
304     /**
305      * ADVANCED:
306      * Get ChangeSet for a particular clone
307      * @return ObjectChangeSet the changeSet that represents a particular clone
308      */

309     public oracle.toplink.essentials.changesets.ObjectChangeSet getObjectChangeSetForClone(Object JavaDoc clone) {
310         if ((clone == null) || (getCloneToObjectChangeSet() == null)) {
311             return null;
312         }
313         return (oracle.toplink.essentials.changesets.ObjectChangeSet)getCloneToObjectChangeSet().get(clone);
314     }
315
316     /**
317      * INTERNAL:
318      * This method returns a reference to the collection
319      * @return oracle.toplink.essentials.internal.helper.IdentityHashtable
320      */

321     protected oracle.toplink.essentials.internal.helper.IdentityHashtable getObjectChangeSetToUOWClone() {
322         if (this.objectChangeSetToUOWClone == null) {
323             // 2612538 - the default size of IdentityHashtable (32) is appropriate
324
this.objectChangeSetToUOWClone = new IdentityHashtable();
325         }
326         return objectChangeSetToUOWClone;
327     }
328
329     /**
330      * ADVANCED:
331      * This method returns the Clone for a particular changeSet
332      * @return Object the clone represented by the changeSet
333      */

334     public Object JavaDoc getUOWCloneForObjectChangeSet(oracle.toplink.essentials.changesets.ObjectChangeSet changeSet) {
335         if ((changeSet == null) || (getObjectChangeSetToUOWClone() == null)) {
336             return null;
337         }
338         return getObjectChangeSetToUOWClone().get(changeSet);
339     }
340
341     /**
342      * INTERNAL:
343      * Returns true if the Unit Of Work change Set has changes
344      */

345     public boolean hasChanges() {
346         // All of the object change sets were empty (none contained changes)
347
// The this.hasChanges variable is set in addObjectChangeSet
348
return (this.hasChanges || (!getDeletedObjects().isEmpty()));
349     }
350
351     /**
352      * INTERNAL:
353      * Set whether the Unit Of Work change Set has changes
354      */

355     public void setHasChanges(boolean flag) {
356         this.hasChanges = flag;
357     }
358
359     /**
360      * INTERNAL:
361      * Returns true if this uowChangeSet contains an objectChangeSet that has forced
362      * SQL changes. This is true whenever CMPPolicy.getForceUpdate() == true.
363      * @return boolean
364      */

365     public boolean hasForcedChanges() {
366         return this.hasForcedChanges;
367     }
368
369     /**
370      * INTERNAL:
371      * This method will be used to merge a change set into an UnitOfWorkChangeSet
372      * This method returns the local instance of the changeset
373      */

374     public ObjectChangeSet mergeObjectChanges(ObjectChangeSet objectChangeSet, UnitOfWorkChangeSet mergeFromChangeSet) {
375         ObjectChangeSet localChangeSet = this.findOrIntegrateObjectChangeSet(objectChangeSet, mergeFromChangeSet);
376         if (localChangeSet != null) {
377             localChangeSet.mergeObjectChanges(objectChangeSet, this, mergeFromChangeSet);
378         }
379         return localChangeSet;
380     }
381
382     /**
383     * INTERNAL:
384     * THis method will be used to merge another changeset into this changeset. The
385     * Main use of this method is for non-deferred writes and checkpointing so that
386     * the acumulated changes are collected and merged at the end of the transaction
387     *
388     */

389     public void mergeUnitOfWorkChangeSet(UnitOfWorkChangeSet mergeFromChangeSet, AbstractSession session, boolean postCommit) {
390         Iterator iterator = mergeFromChangeSet.getObjectChanges().values().iterator();
391         while (iterator.hasNext()) {
392             //iterate over the classes
393
Hashtable table = (Hashtable)iterator.next();
394             Iterator changes = table.values().iterator();
395             while (changes.hasNext()) {
396                 ObjectChangeSet objectChangeSet = (ObjectChangeSet)changes.next();
397                 objectChangeSet = mergeObjectChanges(objectChangeSet, mergeFromChangeSet);
398                 if (objectChangeSet.isNew() && !postCommit) {// if it is post commit then we can trust the cache key
399
this.addNewObjectChangeSet(objectChangeSet, session);
400                 } else {
401                     this.addObjectChangeSet(objectChangeSet);
402                 }
403             }
404         }
405
406         //merging a serialized UnitOfWorkChangeSet can result in duplicate deletes
407
//if a delete for the same object already exists in this UOWChangeSet.
408
Enumeration deletedEnum = mergeFromChangeSet.getDeletedObjects().elements();
409         while (deletedEnum.hasMoreElements()) {
410             ObjectChangeSet objectChangeSet = (ObjectChangeSet)deletedEnum.nextElement();
411             ObjectChangeSet localObjectChangeSet = findObjectChangeSet(objectChangeSet, mergeFromChangeSet);
412             if (localObjectChangeSet == null) {
413                 localObjectChangeSet = objectChangeSet;
414             }
415             this.getDeletedObjects().put(localObjectChangeSet, localObjectChangeSet);
416         }
417     }
418
419     /**
420      * INTERNAL:
421      * Used to rehash the new objects back into the objectChanges list for serialization
422      */

423     public void putNewObjectInChangesList(ObjectChangeSet objectChangeSet, AbstractSession session) {
424         this.addObjectChangeSet(objectChangeSet);
425         removeObjectChangeSetFromNewList(objectChangeSet, session);
426     }
427
428     /**
429      * INTERNAL:
430      * Used to remove a new object from the new objects list once it has been
431      * inserted and added to the objectChangesList
432      */

433     public void removeObjectChangeSetFromNewList(ObjectChangeSet objectChangeSet, AbstractSession session) {
434         IdentityHashtable table = (IdentityHashtable)getNewObjectChangeSets().get(objectChangeSet.getClassType(session));
435         if (table != null) {
436             table.remove(objectChangeSet);
437         }
438     }
439
440     /**
441      * INTERNAL:
442      * Add the changed Object's records to the ChangeSet
443      * @param objectChanges prototype.changeset.ObjectChanges
444      */

445     public void removeObjectChangeSet(ObjectChangeSet objectChanges) {
446         if (objectChanges == null) {
447             return;
448         }
449         Object JavaDoc object = getObjectChangeSetToUOWClone().get(objectChanges);
450         if (objectChanges.isAggregate()) {
451             getAggregateList().remove(objectChanges);
452         } else {
453             // Bug 3294426 - index object changes by classname instead of class for remote classloader issues
454
Hashtable table = (Hashtable)getObjectChanges().get(object.getClass().getName());
455             if (table != null) {
456                 table.remove(objectChanges);
457             }
458         }
459         getObjectChangeSetToUOWClone().remove(objectChanges);
460         if (object != null) {
461             getCloneToObjectChangeSet().remove(object);
462         }
463         getAllChangeSets().remove(objectChanges);
464     }
465
466     /**
467      * INTERNAL:
468      * This method is used to set the hashtable for cloneToObject reference
469      * @param newCloneToObjectChangeSet oracle.toplink.essentials.internal.helper.IdentityHashtable
470      */

471     protected void setCloneToObjectChangeSet(oracle.toplink.essentials.internal.helper.IdentityHashtable newCloneToObjectChangeSet) {
472         cloneToObjectChangeSet = newCloneToObjectChangeSet;
473     }
474
475     /**
476      * INTERNAL:
477      * Sets the collection of ObjectChanges in the change Set
478      * @param newValue prototype.changeset.ObjectChanges
479      */

480     protected void setObjectChanges(Hashtable objectChanges) {
481         this.objectChanges = objectChanges;
482     }
483
484     /**
485      * INTERNAL:
486      * This method is used to insert a new collection into the UOWChangeSet.
487      * @param newObjectChangeSetToUOWClone oracle.toplink.essentials.internal.helper.IdentityHashtable
488      */

489     protected void setObjectChangeSetToUOWClone(oracle.toplink.essentials.internal.helper.IdentityHashtable newObjectChangeSetToUOWClone) {
490         objectChangeSetToUOWClone = newObjectChangeSetToUOWClone;
491     }
492
493     /**
494      * INTERNAL:
495      * This method will return a reference to the new object change set collections
496      */

497     public java.util.Hashtable JavaDoc getNewObjectChangeSets() {
498         if (this.newObjectChangeSets == null) {
499             this.newObjectChangeSets = new java.util.Hashtable JavaDoc();
500         }
501         return this.newObjectChangeSets;
502     }
503
504     /**
505      * INTERNAL:
506      * This method take a collection of ObjectChangeSet rebuilds this UOW change set to a ready to merge stage
507      */

508     public void setInternalAllChangeSets(Vector objectChangeSets) {
509         if (objectChangeSets == null) {
510             return;
511         }
512         sdkAllChangeSets = objectChangeSets;
513
514         for (int i = 0; i < objectChangeSets.size(); i++) {
515             ObjectChangeSet objChangeSet = (ObjectChangeSet)objectChangeSets.elementAt(i);
516             objChangeSet.setUOWChangeSet(this);
517
518             if (objChangeSet.isAggregate()) {
519                 getAggregateList().put(objChangeSet, objChangeSet);
520
521             } else if (objChangeSet.shouldBeDeleted()) {
522                 getDeletedObjects().put(objChangeSet, objChangeSet);
523             } else {
524                 getAllChangeSets().put(objChangeSet, objChangeSet);
525             }
526             if (objChangeSet.getCacheKey() != null) {
527                 Hashtable table = (Hashtable)getObjectChanges().get(objChangeSet.getClassName());
528                 if (table == null) {
529                     table = new Hashtable(2);
530                     getObjectChanges().put(objChangeSet.getClassName(), table);
531                 }
532                 table.put(objChangeSet, objChangeSet);
533             }
534         }
535     }
536 }
537
Popular Tags