KickJava   Java API By Example, From Geeks To Geeks.

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


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.sessions;
23
24 import java.io.*;
25 import java.util.HashSet JavaDoc;
26 import java.util.Vector JavaDoc;
27 import java.util.Hashtable JavaDoc;
28 import java.util.Enumeration JavaDoc;
29 import oracle.toplink.essentials.queryframework.*;
30 import oracle.toplink.essentials.internal.helper.ConversionManager;
31 import oracle.toplink.essentials.internal.helper.ClassConstants;
32 import oracle.toplink.essentials.mappings.*;
33 import oracle.toplink.essentials.internal.identitymaps.CacheKey;
34 import oracle.toplink.essentials.descriptors.ClassDescriptor;
35 import oracle.toplink.essentials.internal.descriptors.OptimisticLockingPolicy;
36
37 /**
38  * <p>
39  * <b>Purpose</b>: Hold the Records of change for a particular instance of an object.
40  * <p>
41  * <b>Description</b>: This class uses the Primary Keys of the Object it represents,
42  * and the class.
43  * <p>
44  */

45 public class ObjectChangeSet implements Serializable, oracle.toplink.essentials.changesets.ObjectChangeSet {
46
47     /** This is the collection of changes */
48     protected java.util.Vector JavaDoc changes;
49     protected java.util.Hashtable JavaDoc attributesToChanges;
50     protected boolean shouldBeDeleted;
51     protected CacheKey cacheKey;
52     protected transient Class JavaDoc classType;
53     protected String JavaDoc className;
54     protected boolean isNew;
55     protected boolean isAggregate;
56     protected Object JavaDoc oldKey;
57     protected Object JavaDoc newKey;
58
59     /** This member variable holds the reference to the parent UnitOfWork Change Set **/
60     protected UnitOfWorkChangeSet unitOfWorkChangeSet;
61     /** Used in mergeObjectChanges method for writeLock and initialWriteLock comparison of the merged change sets **/
62     protected transient OptimisticLockingPolicy optimisticLockingPolicy;
63     protected Object JavaDoc initialWriteLockValue;
64     protected Object JavaDoc writeLockValue;
65     /** Invalid change set shouldn't be merged into object in cache, rather the object should be invalidated **/
66     protected boolean isInvalid;
67     protected transient Object JavaDoc cloneObject;
68     protected boolean hasVersionChange;
69     //** Contains optimisticReadLockObject corresponding to the clone, non-null indicates forced changes **/
70
protected Boolean JavaDoc shouldModifyVersionField;
71     //** For CMP only: indicates that the object should be force updated (whether it has OptimisticLocking or not): getCmpPolicy().getForcedUpdate()==true**/
72
protected boolean hasCmpPolicyForcedUpdate;
73     protected boolean hasChangesFromCascadeLocking;
74     
75     /** This is used during attribute level change tracking when a particular
76      * change was detected but that change can not be tracked (ie customer set
77      * entire collection in object).
78      */

79     protected transient HashSet JavaDoc deferredSet;
80
81     /**
82      * The default constructor is used only by SDK XML project for mapping ObjectChangeSet
83      */

84     public ObjectChangeSet() {
85         super();
86     }
87
88     /**
89      * This constructor is used to create an ObjectChangeSet that represents an aggregate object.
90      */

91     public ObjectChangeSet(Object JavaDoc cloneObject, UnitOfWorkChangeSet parent, boolean isNew) {
92         this.cloneObject = cloneObject;
93         this.shouldBeDeleted = false;
94         this.classType = cloneObject.getClass();
95         this.className = this.classType.getName();
96         this.unitOfWorkChangeSet = parent;
97         this.isNew = isNew;
98     }
99
100     /**
101      * This constructor is used to create an ObjectChangeSet that represents a regular object.
102      */

103     public ObjectChangeSet(Vector JavaDoc primaryKey, Object JavaDoc cloneObject, UnitOfWorkChangeSet parent, boolean isNew) {
104         super();
105         this.cloneObject = cloneObject;
106         this.isNew = isNew;
107         this.shouldBeDeleted = false;
108         if ((primaryKey != null) && !oracle.toplink.essentials.internal.helper.Helper.containsNull(primaryKey, 0)) {
109             this.cacheKey = new CacheKey(primaryKey);
110         }
111         this.classType = cloneObject.getClass();
112         this.className = this.classType.getName();
113         this.unitOfWorkChangeSet = parent;
114         this.isAggregate = false;
115     }
116
117     /**
118      * INTERNAL:
119      * This method will clear the changerecords from a changeSet
120      */

121     public void clear() {
122         this.shouldBeDeleted = false;
123         this.setOldKey(null);
124         this.setNewKey(null);
125         this.changes = null;
126         this.attributesToChanges = null;
127     }
128
129     /**
130      * @param changeRecord prototype.changeset.ChangeRecord
131      */

132     public void addChange(ChangeRecord changeRecord) {
133         if (changeRecord == null) {
134             return;
135         }
136         ChangeRecord existingChangeRecord = (ChangeRecord)getAttributesToChanges().get(changeRecord.getAttribute());
137         // change tracking may add a change to an existing attribute fix that here.
138
if ( existingChangeRecord != null){
139             getChanges().remove(existingChangeRecord);
140         }
141         getChanges().addElement(changeRecord);
142         getAttributesToChanges().put(changeRecord.getAttribute(), changeRecord);
143         updateUOWChangeSet();
144     }
145
146     /**
147      * INTERNAL:
148      * This method is used during attribute level change tracking when a particular
149      * change was detected but that change can not be tracked (ie customer set
150      * entire collection in object). In this case flag this attribute for
151      * deferred change detection at commit time.
152      */

153     public void deferredDetectionRequiredOn(String JavaDoc attributeName){
154         getDeferredSet().add(attributeName);
155     }
156     
157     /**
158      * INTERNAL:
159      * Convenience method used to query this change set after it has been sent by
160      * cache synchronization.
161      * @return true if this change set should contain all change information, false if only
162      * the identity information should be available.
163      */

164     public boolean containsChangesFromSynchronization() {
165         return false;
166     }
167
168     /**
169      * @return boolean
170      * @param objectChange prototype.changeset.ObjectChangeSet
171      */

172     public boolean equals(Object JavaDoc object) {
173         if (object instanceof ObjectChangeSet) {
174             return equals((ObjectChangeSet)object);
175         }
176         return false;
177     }
178
179     /**
180      * @return boolean
181      * @param objectChange prototype.changeset.ObjectChangeSet
182      */

183     public boolean equals(oracle.toplink.essentials.changesets.ObjectChangeSet objectChange) {
184         if (this == objectChange) {
185             return true;
186         } else if (getCacheKey() == null) {
187             //new objects are compared based on identity
188
return false;
189         }
190
191         return (getCacheKey().equals(((ObjectChangeSet)objectChange).getCacheKey()));
192     }
193
194     /**
195      * INTERNAL:
196      * stores the change records indexed by the attribute names
197      */

198     public Hashtable JavaDoc getAttributesToChanges() {
199         if (this.attributesToChanges == null) {
200             this.attributesToChanges = new Hashtable JavaDoc(2);
201         }
202         return this.attributesToChanges;
203     }
204
205     /**
206      * INTERNAL:
207      * returns the change record for the specified attribute name
208      */

209     public oracle.toplink.essentials.changesets.ChangeRecord getChangesForAttributeNamed(String JavaDoc attributeName) {
210         return (ChangeRecord)this.getAttributesToChanges().get(attributeName);
211     }
212
213     /**
214      * @return java.util.Vector
215      */

216     public CacheKey getCacheKey() {
217         // this must not be lazy initialized as newness of the ObjectChangeSet and
218
//equality are determined by the existence of a cachekey - GY
219
return cacheKey;
220     }
221
222     /**
223      * ADVANCED:
224      * This method will return a collection of the fieldnames of attributes changed in an object
225      *
226      */

227     public Vector JavaDoc getChangedAttributeNames() {
228         Vector JavaDoc names = new Vector JavaDoc();
229         Enumeration JavaDoc attributes = getChanges().elements();
230         while (attributes.hasMoreElements()) {
231             names.addElement(((ChangeRecord)attributes.nextElement()).getAttribute());
232         }
233         return names;
234     }
235
236     /**
237      * INTERNAL:
238      * This method returns a reference to the collection of changes within this changeSet
239      * @return java.util.Vector
240      */

241     public java.util.Vector JavaDoc getChanges() {
242         if (this.changes == null) {
243             this.changes = new Vector JavaDoc(1);
244         }
245         return changes;
246     }
247
248     /**
249      * ADVANCE:
250      * This method returns the class type that this changeSet Represents.
251      * This requires the session to reload the class on serialization.
252      * @return java.lang.Class
253      */

254     public Class JavaDoc getClassType(oracle.toplink.essentials.sessions.Session session) {
255         if (classType == null) {
256             classType = (Class JavaDoc)((AbstractSession)session).getDatasourcePlatform().getConversionManager().convertObject(getClassName(), ClassConstants.CLASS);
257         }
258         return classType;
259     }
260
261     /**
262      * ADVANCE:
263      * This method returns the class type that this changeSet Represents.
264      * The class type should be used if the class is desired.
265      * @return java.lang.Class
266      */

267     public String JavaDoc getClassName() {
268         return className;
269     }
270
271     /**
272      * INTERNAL:
273      * This method is used to return the initial lock value of the object this changeSet represents
274      * @return java.lang.Object
275      */

276     public java.lang.Object JavaDoc getInitialWriteLockValue() {
277         return initialWriteLockValue;
278     }
279
280     /**
281      * This method returns the key value that this object was stored under in it's
282      * Respective hashmap.
283      */

284     public Object JavaDoc getOldKey() {
285         return this.oldKey;
286     }
287
288     /**
289      * This method returns the key value that this object will be stored under in it's
290      * Respective hashmap.
291      */

292     public Object JavaDoc getNewKey() {
293         return this.newKey;
294     }
295
296     /**
297      * ADVANCED:
298      * This method returns the primary keys for the object that this change set represents
299      * @return java.util.Vector
300      */

301     public java.util.Vector JavaDoc getPrimaryKeys() {
302         if (getCacheKey() == null) {
303             return null;
304         }
305         return getCacheKey().getKey();
306     }
307
308     /**
309      * INTERNAL:
310      * This method is used to return the complex object specified within the change record.
311      * The object is collected from the session which, in this case, is the unit of work.
312      * The object's changed attributes will be merged and added to the identity map
313      * @param session oracle.toplink.essentials.publicinterface.Session
314      */

315     public Object JavaDoc getTargetVersionOfSourceObject(AbstractSession session) {
316         return getTargetVersionOfSourceObject(session, false);
317     }
318
319     /**
320      * INTERNAL:
321      * This method is used to return the complex object specified within the change record.
322      * The object is collected from the session which, in this case, is the unit of work.
323      * The object's changed attributes will be merged and added to the identity map
324      * @param shouldRead boolean if the object can not be found should it be read in from the database
325      * @param session oracle.toplink.essentials.publicinterface.Session
326      */

327     public Object JavaDoc getTargetVersionOfSourceObject(AbstractSession session, boolean shouldRead) {
328         Object JavaDoc attributeValue = null;
329         ClassDescriptor descriptor = session.getDescriptor(getClassType(session));
330
331         if (session.isUnitOfWork()) {// The unit of works will have a copy or a new instance must be made
332
if (((UnitOfWorkImpl)session).getLifecycle() == UnitOfWorkImpl.MergePending) {// we are merging the unit of work into the original
333
attributeValue = ((UnitOfWorkImpl)session).getOriginalVersionOfObjectOrNull(((UnitOfWorkChangeSet)getUOWChangeSet()).getObjectChangeSetToUOWClone().get(this));
334             } else {
335                 //we are merging something else within the unit of work.
336
// this is most likely because we are updating a backup clone and can retrieve
337
//the working clone as the result
338
attributeValue = ((UnitOfWorkChangeSet)getUOWChangeSet()).getObjectChangeSetToUOWClone().get(this);
339             }
340         } else {//It is not a unitOfWork so we must be merging into a distributed cache
341
attributeValue = session.getIdentityMapAccessorInstance().getIdentityMapManager().getFromIdentityMap(getPrimaryKeys(), getClassType(session), descriptor);
342
343         }
344         if ((attributeValue == null) && (shouldRead)) {
345             // If the cache does not have a copy and I should read it from the database
346
// Then load the object if possible
347
ReadObjectQuery query = new ReadObjectQuery();
348             query.setShouldUseWrapperPolicy(false);
349             query.setReferenceClass(getClassType(session));
350             query.setSelectionKey(getPrimaryKeys());
351             attributeValue = session.executeQuery(query);
352         }
353         return attributeValue;
354     }
355
356     /**
357      * INTERNAL:
358      * Returns the UnitOfWork Clone that this ChangeSet was built For
359      */

360     public Object JavaDoc getUnitOfWorkClone() {
361         return this.cloneObject;
362     }
363
364     /**
365      * ADVANCED:
366      * This method is used to return the parent ChangeSet
367      * @return prototype.changeset.UnitOfWorkChangeSet
368      */

369     public oracle.toplink.essentials.changesets.UnitOfWorkChangeSet getUOWChangeSet() {
370         return unitOfWorkChangeSet;
371     }
372
373     /**
374      * INTERNAL:
375      * This method is used to return the lock value of the object this changeSet represents
376      * @return java.lang.Object
377      */

378     public java.lang.Object JavaDoc getWriteLockValue() {
379         return writeLockValue;
380     }
381
382     /**
383      * ADVANCED:
384      * This method will return true if the specified attributue has been changed
385      *
386      * @param String the name of the attribute to search for
387      */

388     public boolean hasChangeFor(String JavaDoc attributeName) {
389         Enumeration JavaDoc attributes = getChanges().elements();
390         while (attributes.hasMoreElements()) {
391             if (((ChangeRecord)attributes.nextElement()).getAttribute().equals(attributeName)) {
392                 return true;
393             }
394         }
395         return false;
396     }
397
398     /**
399      * ADVANCED:
400      * Returns true if this particular changeSet has changes.
401      * @return boolean
402      */

403     public boolean hasChanges() {
404         // a change set must also be considered dirty if only the version number has been updated
405
// and the version is not a mapped field. This is required to propagate the change
406
// set via cache sync. to avoid opt. lock exceptions on the remote servers.
407
return this.hasVersionChange || !this.getChanges().isEmpty();
408     }
409
410     /**
411      * INTERNAL:
412      * Returns true if this particular changeSet has forced SQL changes. This is true whenever
413      * CMPPolicy.getForceUpdate() == true or if the object has been marked for opt. read
414      * lock (uow.forceUpdateToVersionField). Kept separate from 'hasChanges' because we don't
415      * want to merge or cache sync. a change set that has no 'real' changes.
416      * @return boolean
417      */

418     public boolean hasForcedChanges() {
419         return this.shouldModifyVersionField != null || this.hasCmpPolicyForcedUpdate;
420     }
421     
422     /**
423      * INTERNAL:
424      * Holds a Boolean indicating whether version field should be modified.
425      * This Boolean is set by forcedUpdate into uow.getOptimisticReadLockObjects()
426      * for the clone object and copied here (so don't need to search for it again
427      * in uow.getOptimisticReadLockObjects()).
428      */

429     public void setShouldModifyVersionField(Boolean JavaDoc shouldModifyVersionField) {
430         this.shouldModifyVersionField = shouldModifyVersionField;
431         if(shouldModifyVersionField != null && shouldModifyVersionField.booleanValue()) {
432             // mark the version number as 'dirty'
433
// Note that at this point there is no newWriteLockValue - it will be set later.
434
// This flag is set to indicate that the change set WILL have changes.
435
this.hasVersionChange = true;
436         }
437     }
438     
439     /**
440      * INTERNAL:
441      * Holds a Boolean indicating whether version field should be modified.
442      */

443     public Boolean JavaDoc shouldModifyVersionField() {
444         return this.shouldModifyVersionField;
445     }
446     
447     /**
448      * INTERNAL:
449      */

450     public void setHasCmpPolicyForcedUpdate(boolean hasCmpPolicyForcedUpdate) {
451         this.hasCmpPolicyForcedUpdate = hasCmpPolicyForcedUpdate;
452     }
453     
454     /**
455      * INTERNAL:
456      */

457     public boolean hasCmpPolicyForcedUpdate() {
458         return this.hasCmpPolicyForcedUpdate;
459     }
460     
461     /**
462      * INTERNAL:
463      * Returns true if this particular changeSet has forced SQL changes because
464      * of a cascade optimistic locking policy.
465      * @return boolean
466      */

467     public boolean hasForcedChangesFromCascadeLocking() {
468         return this.hasChangesFromCascadeLocking;
469     }
470
471     /**
472      * INTERNAL:
473      * * Used by calculateChanges to mark this ObjectChangeSet as having to be
474      * flushed to the db steming from a cascade optimistic locking policy.
475      */

476     public void setHasForcedChangesFromCascadeLocking(boolean newValue) {
477         this.setShouldModifyVersionField(Boolean.TRUE);
478         this.hasChangesFromCascadeLocking = newValue;
479     }
480
481     /**
482      * This method overrides the hashcode method. If this set has a cacheKey then return the hashcode of the
483      * cache key, otherwise return the identity hashcode of this object.
484      * @return int
485      */

486     public int hashCode() {
487         if (getCacheKey() == null) {
488             //new objects are compared based on identity
489
return System.identityHashCode(this);
490         }
491         return getCacheKey().hashCode();
492     }
493
494     /**
495      * INTERNAL:
496      * Returns true if this particular changeSet has a Key.
497      * @return boolean
498      */

499     public boolean hasKeys() {
500         return (this.newKey != null) || (this.oldKey != null);
501     }
502
503     /**
504      * INTERNAL:
505      * Used to determine if the object change set represents an aggregate object
506      * @return boolean
507      */

508     public boolean isAggregate() {
509         return isAggregate;
510     }
511
512     /**
513      * ADVANCED:
514      * Returns true if this ObjectChangeSet represents a new object
515      * @return boolean
516      */

517     public boolean isNew() {
518         return isNew;
519     }
520
521     /**
522      * INTERNAL:
523      * Indicates whether the change set is invalid.
524      * @return boolean
525      */

526     public boolean isInvalid() {
527         return isInvalid;
528     }
529
530     /**
531      * INTERNAL:
532      * This method will be used to merge changes from a supplied ObjectChangeSet
533      * into this changeSet.
534      */

535     public void mergeObjectChanges(ObjectChangeSet changeSetToMergeFrom, UnitOfWorkChangeSet mergeToChangeSet, UnitOfWorkChangeSet mergeFromChangeSet) {
536         if (this == changeSetToMergeFrom || this.isInvalid()) {
537             return;
538         }
539         if(changeSetToMergeFrom.optimisticLockingPolicy != null) {
540             // optimisticLockingPolicy != null guarantees initialWriteLockValue != null
541
if(this.optimisticLockingPolicy == null) {
542                 this.optimisticLockingPolicy = changeSetToMergeFrom.optimisticLockingPolicy;
543                 this.initialWriteLockValue = changeSetToMergeFrom.initialWriteLockValue;
544                 this.writeLockValue = changeSetToMergeFrom.writeLockValue;
545             } else {
546                 // optimisticLockingPolicy != null guarantees initialWriteLockValue != null
547
Object JavaDoc writeLockValueToCompare = this.writeLockValue;
548                 if(writeLockValueToCompare == null) {
549                     writeLockValueToCompare = this.initialWriteLockValue;
550                 }
551                 // In this merge initialWriteLockValue of this changeSet differes from
552
// writeLockValue of the changeSetToMergeFrom into which the merge was performed.
553
// Example:
554
// Original registered with version 1, the clone changed to version 2, uow.writeChanges is called:
555
// the corresponding "this" changeSet has initialWriteLockValue = 1 and writeLockValue = 2;
556
// custom update performed next changing the version of the object in the db to 3;
557
// the clone is refreshed in the uow - not it's version is 3;
558
// the cloned is changed to version 4, uow.commit is called:
559
// the corresponding changeSetToMergeFrom has initialWriteLockValue = 3 and writeLockValue = 4.
560
// This change set should be invalidated - the custom update would not be reflected after merge,
561
// therefore nor merge into cache should be performed but rather the object in the cache should be invalidated.
562
if(this.optimisticLockingPolicy.compareWriteLockValues(writeLockValueToCompare, changeSetToMergeFrom.initialWriteLockValue) != 0) {
563                     this.isInvalid = true;
564                     return;
565                 }
566                 this.writeLockValue = changeSetToMergeFrom.writeLockValue;
567             }
568         }
569         for (int index = 0; index < changeSetToMergeFrom.getChanges().size(); ++index) {
570             ChangeRecord record = (ChangeRecord)changeSetToMergeFrom.getChanges().get(index);
571             ChangeRecord thisRecord = (ChangeRecord) this.getChangesForAttributeNamed(record.getAttribute());
572             if (thisRecord == null) {
573                 record.updateReferences(mergeToChangeSet, mergeFromChangeSet);
574                 this.addChange(record);
575             } else {
576                 thisRecord.mergeRecord(record, mergeToChangeSet, mergeFromChangeSet);
577             }
578         }
579         this.shouldBeDeleted = changeSetToMergeFrom.shouldBeDeleted;
580         this.setOldKey(changeSetToMergeFrom.oldKey);
581         this.setNewKey(changeSetToMergeFrom.newKey);
582         this.hasVersionChange = changeSetToMergeFrom.hasVersionChange;
583         this.shouldModifyVersionField = changeSetToMergeFrom.shouldModifyVersionField;
584         this.hasCmpPolicyForcedUpdate = changeSetToMergeFrom.hasCmpPolicyForcedUpdate;
585         this.hasChangesFromCascadeLocking = changeSetToMergeFrom.hasChangesFromCascadeLocking;
586     }
587
588     /**
589      * INTERNAL:
590      * Iterate through the change records and ensure the cache synchronization types
591      * are set on the change sets associated with those records.
592      */

593     public void prepareChangeRecordsForSynchronization(AbstractSession session) {
594         Enumeration JavaDoc records = getChanges().elements();
595         while (records.hasMoreElements()) {
596             ((ChangeRecord)records.nextElement()).prepareForSynchronization(session);
597         }
598     }
599
600     /**
601      * INTERNAL:
602      * Helper method used by readObject to read a completely serialized change set from
603      * the stream
604      */

605     public void readCompleteChangeSet(java.io.ObjectInputStream JavaDoc stream) throws java.io.IOException JavaDoc, ClassNotFoundException JavaDoc {
606         readIdentityInformation(stream);
607         // bug 3526981 - avoid side effects of setter methods by directly assigning variables
608
// still calling setOldKey to avoid duplicating the code in that method
609
changes = (Vector JavaDoc)stream.readObject();
610         setOldKey(stream.readObject());
611         newKey = stream.readObject();
612     }
613
614     /**
615      * INTERNAL:
616      * Helper method used by readObject to read just the information about object identity
617      * from a serialized stream.
618      */

619     public void readIdentityInformation(java.io.ObjectInputStream JavaDoc stream) throws java.io.IOException JavaDoc, ClassNotFoundException JavaDoc {
620         // bug 3526981 - avoid side effects of setter methods by directly assigning variables
621
cacheKey = (CacheKey)stream.readObject();
622         className = (String JavaDoc)stream.readObject();
623         writeLockValue = stream.readObject();
624     }
625
626     /**
627      * @return java.util.Vector
628      */

629     public void setCacheKey(CacheKey cacheKey) {
630         this.cacheKey = cacheKey;
631     }
632
633     /**
634      * @param newValue java.util.Vector
635      */

636     public void setChanges(java.util.Vector JavaDoc changesList) {
637         this.changes = changesList;
638         updateUOWChangeSet();
639     }
640
641     /**
642      * @param newValue java.lang.Class
643      */

644     public void setClassType(Class JavaDoc newValue) {
645         this.classType = newValue;
646     }
647
648     /**
649      * INTERNAL:
650      * @param newValue java.lang.String
651      */

652     public void setClassName(String JavaDoc newValue) {
653         this.className = newValue;
654     }
655      
656     /**
657      * INTERNAL:
658      * Set if this object change Set represents an aggregate
659      * @param isAggregate boolean true if the ChangeSet represents an aggregate
660      */

661     public void setIsAggregate(boolean isAggregate) {
662         this.isAggregate = isAggregate;
663     }
664
665     /**
666      * INTERNAL:
667      * Set whether this ObjectChanges represents a new Object
668      * @param newIsNew boolean true if this ChangeSet represents a new object
669      */

670     protected void setIsNew(boolean newIsNew) {
671         isNew = newIsNew;
672     }
673
674     /**
675      * This method is used to set the value that this object was stored under in its respected
676      * map collection
677      */

678     public void setOldKey(Object JavaDoc key) {
679         //may be merging changeSets lets make sure that we can remove based on the
680
//old key when we finally merge.
681
if ((key == null) || (this.oldKey == null)) {
682             this.oldKey = key;
683         }
684     }
685
686     /**
687      * This method is used to set the value that this object will be stored under in its respected
688      * map collection
689      */

690     public void setNewKey(Object JavaDoc key) {
691         this.newKey = key;
692     }
693
694     /**
695      * This method was created in VisualAge.
696      * @param newValue boolean
697      */

698     public void setShouldBeDeleted(boolean newValue) {
699         this.shouldBeDeleted = newValue;
700     }
701
702     /**
703      * INTERNAL:
704      * Used to set the parent change Set
705      * @param newUnitOfWorkChangeSet prototype.changeset.UnitOfWorkChangeSet
706      */

707     public void setUOWChangeSet(UnitOfWorkChangeSet newUnitOfWorkChangeSet) {
708         unitOfWorkChangeSet = newUnitOfWorkChangeSet;
709     }
710
711     /**
712      * INTERNAL:
713      * This method should ONLY be used to set the initial writeLock value for
714      * an ObjectChangeSet when it is first built.
715      * @param newWriteLockValue java.lang.Object
716      */

717     public void setOptimisticLockingPolicyAndInitialWriteLockValue(OptimisticLockingPolicy optimisticLockingPolicy, AbstractSession session) {
718         this.optimisticLockingPolicy = optimisticLockingPolicy;
719         this.initialWriteLockValue = optimisticLockingPolicy.getWriteLockValue(cloneObject, getPrimaryKeys(), session);
720     }
721
722     /**
723      * ADVANCED:
724      * This method is used to set the writeLock value for an ObjectChangeSet
725      * Any changes to the write lock value
726      * should to through setWriteLockValue(Object obj) so that th change set is
727      * marked as being dirty.
728      * @param newWriteLockValue java.lang.Object
729      */

730     public void setWriteLockValue(java.lang.Object JavaDoc newWriteLockValue) {
731         this.writeLockValue = newWriteLockValue;
732
733         // mark the version number as 'dirty'
734
this.hasVersionChange = true;
735         updateUOWChangeSet();
736     }
737
738     /**
739      * ADVANCED:
740      * This method is used to set the initial writeLock value for an ObjectChangeSet.
741      * The initial value will only be set once, and can not be overwritten.
742      * @param initialWriteLockValue java.lang.Object
743      */

744     public void setInitialWriteLockValue(java.lang.Object JavaDoc initialWriteLockValue) {
745         if (this.initialWriteLockValue == null) {
746             this.initialWriteLockValue = initialWriteLockValue;
747         }
748     }
749
750     /**
751      * This method was created in VisualAge.
752      * @return boolean
753      */

754     public boolean shouldBeDeleted() {
755         return shouldBeDeleted;
756     }
757
758     public String JavaDoc toString() {
759         return this.getClass().getName() + "(" + this.getClassName() + ")" + getChanges().toString();
760     }
761
762     /**
763      * INTERNAL:
764      * Used to update a changeRecord that is stored in the CHangeSet with a new value.
765      */

766     public void updateChangeRecordForAttribute(String JavaDoc attributeName, Object JavaDoc value) {
767         ChangeRecord changeRecord = (ChangeRecord)getChangesForAttributeNamed(attributeName);
768         if (changeRecord != null) {
769             changeRecord.updateChangeRecordWithNewValue(value);
770         }
771     }
772
773     /**
774      * ADVANCED:
775      * Used to update a changeRecord that is stored in the CHangeSet with a new value.
776      * Used when the new value is a mapped object.
777      */

778     public void updateChangeRecordForAttributeWithMappedObject(String JavaDoc attributeName, Object JavaDoc value, AbstractSession session) {
779         ObjectChangeSet referenceChangeSet = (ObjectChangeSet)this.getUOWChangeSet().getObjectChangeSetForClone(value);
780         if (referenceChangeSet == null) {
781             ClassDescriptor descriptor = session.getDescriptor(value.getClass());
782             if (descriptor != null) {
783                 referenceChangeSet = descriptor.getObjectBuilder().createObjectChangeSet(value, (UnitOfWorkChangeSet)this.getUOWChangeSet(), false, session);
784             }
785         }
786         updateChangeRecordForAttribute(attributeName, referenceChangeSet);
787     }
788
789     /**
790      * INTERNAL:
791      * Used to update a changeRecord that is stored in the CHangeSet with a new value.
792      */

793     public void updateChangeRecordForAttribute(DatabaseMapping mapping, Object JavaDoc value) {
794         String JavaDoc attributeName = mapping.getAttributeName();
795         ChangeRecord changeRecord = (ChangeRecord)getChangesForAttributeNamed(attributeName);
796
797         // bug 2641228 always ensure that we convert the value to the correct type
798
value = ConversionManager.getDefaultManager().convertObject(value, mapping.getAttributeClassification());
799         if (changeRecord != null) {
800             changeRecord.updateChangeRecordWithNewValue(value);
801         } else if (mapping.isDirectToFieldMapping()) {
802             //if it is direct to field then this is most likely the result of a forced update and
803
// we will need to merge this object
804
changeRecord = new DirectToFieldChangeRecord(this);
805             changeRecord.setAttribute(attributeName);
806             changeRecord.setMapping(mapping);
807             ((DirectToFieldChangeRecord)changeRecord).setNewValue(value);
808             this.addChange(changeRecord);
809         }
810     }
811
812     /**
813      * INTERNAL:
814      * This method will be used when merging changesets into other changesets.
815      * It will fix references within a changeSet so that it's records point to
816      * changesets within this UOWChangeSet.
817      */

818     public void updateReferences(UnitOfWorkChangeSet localChangeSet, UnitOfWorkChangeSet mergingChangeSet) {
819         for (int index = 0; index < this.getChanges().size(); ++index) {
820             ((ChangeRecord)this.getChanges().get(index)).updateReferences(localChangeSet, mergingChangeSet);
821         }
822     }
823
824     /**
825      * INTERNAL:
826      * Helper method to writeObject. Write only the information necessary to identify this
827      * ObjectChangeSet to the stream
828      */

829     public void writeIdentityInformation(java.io.ObjectOutputStream JavaDoc stream) throws java.io.IOException JavaDoc {
830         stream.writeObject(cacheKey);
831         stream.writeObject(className);
832         stream.writeObject(writeLockValue);
833     }
834
835     /**
836      * INTERNAL:
837      * Helper method to readObject. Completely write this ObjectChangeSet to the stream
838      */

839     public void writeCompleteChangeSet(java.io.ObjectOutputStream JavaDoc stream) throws java.io.IOException JavaDoc {
840         writeIdentityInformation(stream);
841         stream.writeObject(changes);
842         stream.writeObject(oldKey);
843         stream.writeObject(newKey);
844     }
845
846     /**
847      * INTERNAL:
848      */

849     public void setPrimaryKeys(Vector JavaDoc key) {
850         if (key == null) {
851             return;
852         }
853         if (getCacheKey() == null) {
854             setCacheKey(new CacheKey(key));
855         } else {
856             getCacheKey().setKey(key);
857         }
858     }
859
860     /**
861      * This set contains the list of attributes that must be calculated at commit time.
862      */

863     public HashSet JavaDoc getDeferredSet() {
864         if (deferredSet == null){
865             this.deferredSet = new HashSet JavaDoc();
866         }
867         return deferredSet;
868     }
869     
870     /**
871      * Check to see if there are any attributes that must be calculated at commit time.
872      */

873     public boolean hasDeferredAttributes() {
874         return ! (deferredSet == null || this.deferredSet.isEmpty());
875     }
876
877     protected void updateUOWChangeSet() {
878         // needed to explicitly mark parent uow as having changes. This is needed in the
879
// case of Optimistic read locking and ForceUpdate. In these scenarios, the object
880
// change set can be modified to contain 'real' changes after the uow change set has
881
// computed its 'hasChanges' flag. If not done, the change set will not be merged.
882
if (this.getUOWChangeSet() != null) {
883             ((oracle.toplink.essentials.internal.sessions.UnitOfWorkChangeSet)this.getUOWChangeSet()).setHasChanges(this.hasChanges());
884         }
885     }
886
887     /**
888      * INTERNAL:
889      * Remove change. Used by the event mechanism to reset changes after client has
890      * updated the object within an event;
891      */

892     public void removeChange(String JavaDoc attributeName){
893         Object JavaDoc record = getChangesForAttributeNamed(attributeName);
894         if (record != null){
895             getChanges().removeElement(record);
896         }
897     }
898
899     /**
900      * Remove object represent this change set from identity map. If change set is in XML format, rebuild pk to the correct class type from String
901      */

902     protected void removeFromIdentityMap(AbstractSession session) {
903         session.getIdentityMapAccessor().removeFromIdentityMap(getPrimaryKeys(), getClassType(session));
904     }
905
906     /**
907      * INTERNAL:
908      * Indicates whether the object in session cache should be invalidated.
909      * @param original Object is from session's cache into which the changes are about to be merged, non null.
910      * @param session AbstractSession into which the changes are about to be merged;
911      */

912     public boolean shouldInvalidateObject(Object JavaDoc original, AbstractSession session) {
913         // Either no optimistic locking or no version change.
914
if (optimisticLockingPolicy == null) {
915             return false;
916         }
917         
918         if(isInvalid()) {
919             return true;
920         }
921         
922         Object JavaDoc originalWriteLockValue = optimisticLockingPolicy.getWriteLockValue(original, getPrimaryKeys(), session);
923         // initialWriteLockValue and originalWriteLockValue are not equal.
924
// Example:
925
// original registered in uow with version 1 (originalWriteLockValue);
926
// uow.beginEarlyTransaction();
927
// custom update run through the uow changes the version on the object in the db to 2;
928
// the clone is refreshed - now it has version 2;
929
// on uow.commit or uow.writeChanges changeSet is created with initialWriteLockValue = 2;
930
// The original in the cache should be invalidated - the custom update would not be reflected after merge.
931
if (optimisticLockingPolicy.compareWriteLockValues(initialWriteLockValue, originalWriteLockValue) != 0) {
932             return true;
933         } else {
934             return false;
935         }
936     }
937 }
938
Popular Tags