KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > oracle > toplink > essentials > mappings > ObjectReferenceMapping


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.mappings;
23
24 import java.util.*;
25 import oracle.toplink.essentials.exceptions.*;
26 import oracle.toplink.essentials.indirection.ValueHolderInterface;
27 import oracle.toplink.essentials.internal.descriptors.*;
28 import oracle.toplink.essentials.internal.helper.*;
29 import oracle.toplink.essentials.internal.identitymaps.CacheKey;
30 import oracle.toplink.essentials.internal.indirection.*;
31 import oracle.toplink.essentials.internal.sessions.*;
32 import oracle.toplink.essentials.queryframework.*;
33 import oracle.toplink.essentials.sessions.ObjectCopyingPolicy;
34 import oracle.toplink.essentials.internal.sessions.AbstractRecord;
35 import oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl;
36 import oracle.toplink.essentials.internal.sessions.AbstractSession;
37 import oracle.toplink.essentials.descriptors.ClassDescriptor;
38
39 /**
40  * <p><b>Purpose</b>: Abstract class for 1:1, varibale 1:1 and reference mappings
41  */

42 public abstract class ObjectReferenceMapping extends ForeignReferenceMapping {
43
44     /** Keeps track if any of the fields are foreign keys. */
45     protected boolean isForeignKeyRelationship;
46
47     /** Keeps track of which fields are foreign keys on a per field basis (can have mixed foreign key relationships). */
48     protected Vector foreignKeyFields;
49
50     protected ObjectReferenceMapping() {
51         super();
52     }
53
54     /**
55      * INTERNAL:
56      * Used during building the backup shallow copy to copy the vector without re-registering the target objects.
57      * For 1-1 or ref the reference is from the clone so it is already registered.
58      */

59     public Object JavaDoc buildBackupCloneForPartObject(Object JavaDoc attributeValue, Object JavaDoc clone, Object JavaDoc backup, UnitOfWorkImpl unitOfWork) {
60         return attributeValue;
61     }
62
63     /**
64      * INTERNAL:
65      * Require for cloning, the part must be cloned.
66      * Ignore the objects, use the attribute value.
67      */

68     public Object JavaDoc buildCloneForPartObject(Object JavaDoc attributeValue, Object JavaDoc original, Object JavaDoc clone, UnitOfWorkImpl unitOfWork, boolean isExisting) {
69         // Optimize registration to knowledge of existence.
70
if (isExisting) {
71             return unitOfWork.registerExistingObject(attributeValue);
72         } else {
73             // Not known wether existing or not.
74
return unitOfWork.registerObject(attributeValue);
75         }
76     }
77
78     /**
79      * INTERNAL:
80      * Copy of the attribute of the object.
81      * This is NOT used for unit of work but for templatizing an object.
82      */

83     public void buildCopy(Object JavaDoc copy, Object JavaDoc original, ObjectCopyingPolicy policy) {
84         Object JavaDoc attributeValue = getRealAttributeValueFromObject(original, policy.getSession());
85         if ((attributeValue != null) && (policy.shouldCascadeAllParts() || (policy.shouldCascadePrivateParts() && isPrivateOwned()))) {
86             attributeValue = policy.getSession().copyObject(attributeValue, policy);
87         } else if (attributeValue != null) {
88             // Check for copy of part, i.e. back reference.
89
Object JavaDoc copyValue = policy.getCopies().get(attributeValue);
90             if (copyValue != null) {
91                 attributeValue = copyValue;
92             }
93         }
94         setRealAttributeValueInObject(copy, attributeValue);
95     }
96
97     /**
98      * INTERNAL:
99      * This method was created in VisualAge.
100      * @return prototype.changeset.ChangeRecord
101      */

102     public ChangeRecord compareForChange(Object JavaDoc clone, Object JavaDoc backUp, ObjectChangeSet owner, AbstractSession session) {
103         Object JavaDoc cloneAttribute = null;
104         Object JavaDoc backUpAttribute = null;
105
106         cloneAttribute = getAttributeValueFromObject(clone);
107
108         if (!owner.isNew()) {
109             backUpAttribute = getAttributeValueFromObject(backUp);
110             if ((backUpAttribute == null) && (cloneAttribute == null)) {
111                 return null;
112             }
113         }
114
115         if ((cloneAttribute != null) && (!getIndirectionPolicy().objectIsInstantiated(cloneAttribute))) {
116             //the clone's valueholder was never triggered so there will be no change
117
return null;
118         }
119         Object JavaDoc cloneAttributeValue = null;
120         Object JavaDoc backUpAttributeValue = null;
121
122         if (cloneAttribute != null) {
123             cloneAttributeValue = getRealAttributeValueFromObject(clone, session);
124         }
125         if (backUpAttribute != null) {
126             backUpAttributeValue = getRealAttributeValueFromObject(backUp, session);
127         }
128
129         if ((cloneAttributeValue == backUpAttributeValue) && (!owner.isNew())) {// if it is new record the value
130
return null;
131         }
132
133         ObjectReferenceChangeRecord record = internalBuildChangeRecord(cloneAttributeValue, owner, session);
134         if (!owner.isNew()) {
135             record.setOldValue(backUpAttributeValue);
136         }
137         return record;
138     }
139
140     /**
141      * INTERNAL:
142      * Directly build a change record based on the newValue without comparison
143      */

144     public ObjectReferenceChangeRecord internalBuildChangeRecord(Object JavaDoc newValue, ObjectChangeSet owner, AbstractSession session) {
145         ObjectReferenceChangeRecord changeRecord = new ObjectReferenceChangeRecord(owner);
146         changeRecord.setAttribute(getAttributeName());
147         changeRecord.setMapping(this);
148         setNewValueInChangeRecord(newValue, changeRecord, owner, session);
149         return changeRecord;
150     }
151
152     /**
153      * INTERNAL:
154      * Set the newValue in the change record
155      */

156     public void setNewValueInChangeRecord(Object JavaDoc newValue, ObjectReferenceChangeRecord changeRecord, ObjectChangeSet owner, AbstractSession session) {
157         if (newValue != null) {
158             // Bug 2612571 - added more flexible manner of getting descriptor
159
ObjectChangeSet newSet = getDescriptorForTarget(newValue, session).getObjectBuilder().createObjectChangeSet(newValue, (UnitOfWorkChangeSet)owner.getUOWChangeSet(), session);
160             changeRecord.setNewValue(newSet);
161         } else {
162             changeRecord.setNewValue(null);
163         }
164     }
165
166     /**
167      * INTERNAL:
168      * Compare the references of the two objects are the same, not the objects themselves.
169      * Used for independent relationships.
170      * This is used for testing and validation purposes.
171      */

172     protected boolean compareObjectsWithoutPrivateOwned(Object JavaDoc firstObject, Object JavaDoc secondObject, AbstractSession session) {
173         Object JavaDoc firstReferencedObject = getRealAttributeValueFromObject(firstObject, session);
174         Object JavaDoc secondReferencedObject = getRealAttributeValueFromObject(secondObject, session);
175
176         if ((firstReferencedObject == null) && (secondReferencedObject == null)) {
177             return true;
178         }
179
180         if ((firstReferencedObject == null) || (secondReferencedObject == null)) {
181             return false;
182         }
183
184         Vector firstKey = getReferenceDescriptor().getObjectBuilder().extractPrimaryKeyFromObject(firstReferencedObject, session);
185         Vector secondKey = getReferenceDescriptor().getObjectBuilder().extractPrimaryKeyFromObject(secondReferencedObject, session);
186
187         for (int index = 0; index < firstKey.size(); index++) {
188             Object JavaDoc firstValue = firstKey.elementAt(index);
189             Object JavaDoc secondValue = secondKey.elementAt(index);
190
191             if (!((firstValue == null) && (secondValue == null))) {
192                 if ((firstValue == null) || (secondValue == null)) {
193                     return false;
194                 }
195                 if (!firstValue.equals(secondValue)) {
196                     return false;
197                 }
198             }
199         }
200
201         return true;
202     }
203
204     /**
205      * INTERNAL:
206      * Compare the references of the two objects are the same, and the objects themselves are the same.
207      * Used for private relationships.
208      * This is used for testing and validation purposes.
209      */

210     protected boolean compareObjectsWithPrivateOwned(Object JavaDoc firstObject, Object JavaDoc secondObject, AbstractSession session) {
211         Object JavaDoc firstPrivateObject = getRealAttributeValueFromObject(firstObject, session);
212         Object JavaDoc secondPrivateObject = getRealAttributeValueFromObject(secondObject, session);
213
214         return session.compareObjects(firstPrivateObject, secondPrivateObject);
215     }
216
217     /**
218      * INTERNAL:
219      * Return a descriptor for the target of this mapping
220      * @see oracle.toplink.essentials.mappings.VariableOneToOneMapping
221      * Bug 2612571
222      */

223     public ClassDescriptor getDescriptorForTarget(Object JavaDoc object, AbstractSession session) {
224         return getReferenceDescriptor();
225     }
226
227     /**
228      * INTERNAL:
229      * Object reference must unwrap the reference object if required.
230      */

231     public Object JavaDoc getRealAttributeValueFromObject(Object JavaDoc object, AbstractSession session) {
232         Object JavaDoc value = super.getRealAttributeValueFromObject(object, session);
233         value = getReferenceDescriptor().getObjectBuilder().unwrapObject(value, session);
234
235         return value;
236     }
237
238     /**
239      * INTERNAL:
240      * Related mapping should implement this method to return true.
241      */

242     public boolean isObjectReferenceMapping() {
243         return true;
244     }
245
246     /**
247      * INTERNAL:
248      * Iterate on the attribute value.
249      * The value holder has already been processed.
250      */

251     public void iterateOnRealAttributeValue(DescriptorIterator iterator, Object JavaDoc realAttributeValue) {
252         // This may be wrapped as the caller in iterate on foreign reference does not unwrap as the type is generic.
253
Object JavaDoc unwrappedAttributeValue = getReferenceDescriptor().getObjectBuilder().unwrapObject(realAttributeValue, iterator.getSession());
254         iterator.iterateReferenceObjectForMapping(unwrappedAttributeValue, this);
255     }
256
257     /**
258      * INTERNAL:
259      * Merge changes from the source to the target object. Which is the original from the parent UnitOfWork
260      */

261     public void mergeChangesIntoObject(Object JavaDoc target, ChangeRecord changeRecord, Object JavaDoc source, MergeManager mergeManager) {
262         Object JavaDoc targetValueOfSource = null;
263
264         // The target object must be completely merged before setting it otherwise
265
// another thread can pick up the partial object.
266
if (shouldMergeCascadeParts(mergeManager)) {
267             ObjectChangeSet set = (ObjectChangeSet)((ObjectReferenceChangeRecord)changeRecord).getNewValue();
268             if (set != null) {
269                 if (mergeManager.shouldMergeChangesIntoDistributedCache()) {
270                     //Let's try and find it first. We may have merged it allready. In which case merge
271
//changes will stop the recursion
272
targetValueOfSource = set.getTargetVersionOfSourceObject(mergeManager.getSession(), false);
273                     if ((targetValueOfSource == null) && (set.isNew() || set.isAggregate()) && set.containsChangesFromSynchronization()) {
274                         if (!mergeManager.getObjectsAlreadyMerged().containsKey(set)) {
275                             // if we haven't merged this object allready then build a new object
276
// otherwise leave it as null which will stop the recursion
277
// CR 2855
278
// CR 3424 Need to build the right instance based on class type instead of refernceDescriptor
279
Class JavaDoc objectClass = set.getClassType(mergeManager.getSession());
280                             targetValueOfSource = mergeManager.getSession().getDescriptor(objectClass).getObjectBuilder().buildNewInstance();
281                             //Store the changeset to prevent us from creating this new object again
282
mergeManager.getObjectsAlreadyMerged().put(set, targetValueOfSource);
283                         } else {
284                             //CR 4012
285
//we have all ready created the object, must be in a cyclic
286
//merge on a new object so get it out of the allreadymerged collection
287
targetValueOfSource = mergeManager.getObjectsAlreadyMerged().get(set);
288                         }
289                     } else {
290                         // If We have not found it anywhere else load it from the database
291
targetValueOfSource = set.getTargetVersionOfSourceObject(mergeManager.getSession(), true);
292                     }
293                     if (set.containsChangesFromSynchronization()) {
294                         mergeManager.mergeChanges(targetValueOfSource, set);
295                     }
296                     //bug:3604593 - ensure reference not changed source is invalidated if target object not found
297
if (targetValueOfSource ==null)
298                     {
299                       mergeManager.getSession().getIdentityMapAccessorInstance().invalidateObject(target);
300                       return;
301                     }
302                 } else {
303                     mergeManager.mergeChanges(set.getUnitOfWorkClone(), set);
304                 }
305             }
306         }
307         if ((targetValueOfSource == null) && (((ObjectReferenceChangeRecord)changeRecord).getNewValue() != null)) {
308             targetValueOfSource = ((ObjectChangeSet)((ObjectReferenceChangeRecord)changeRecord).getNewValue()).getTargetVersionOfSourceObject(mergeManager.getSession());
309         }
310
311         // Register new object in nested units of work must not be registered into the parent,
312
// so this records them in the merge to parent case.
313
if (isPrivateOwned() && (source != null)) {
314             mergeManager.registerRemovedNewObjectIfRequired(getRealAttributeValueFromObject(source, mergeManager.getSession()));
315         }
316
317         targetValueOfSource = getReferenceDescriptor().getObjectBuilder().wrapObject(targetValueOfSource, mergeManager.getSession());
318         setRealAttributeValueInObject(target, targetValueOfSource);
319     }
320
321     /**
322      * INTERNAL:
323      * Merge changes from the source to the target object.
324      */

325     public void mergeIntoObject(Object JavaDoc target, boolean isTargetUnInitialized, Object JavaDoc source, MergeManager mergeManager) {
326         if (isTargetUnInitialized) {
327             // This will happen if the target object was removed from the cache before the commit was attempted
328
if (mergeManager.shouldMergeWorkingCopyIntoOriginal() && (!isAttributeValueInstantiated(source))) {
329                 setAttributeValueInObject(target, getIndirectionPolicy().getOriginalIndirectionObject(getAttributeValueFromObject(source), mergeManager.getSession()));
330                 return;
331             }
332         }
333         if (!shouldMergeCascadeReference(mergeManager)) {
334             // This is only going to happen on mergeClone, and we should not attempt to merge the reference
335
return;
336         }
337         if (mergeManager.shouldMergeOriginalIntoWorkingCopy()) {
338             if (!isAttributeValueInstantiated(target)) {
339                 // This will occur when the clone's value has not been instantiated yet and we do not need
340
// the refresh that attribute
341
return;
342             }
343         } else if (!isAttributeValueInstantiated(source)) {
344             // I am merging from a clone into an original. No need to do merge if the attribute was never
345
// modified
346
return;
347         }
348
349         Object JavaDoc valueOfSource = getRealAttributeValueFromObject(source, mergeManager.getSession());
350
351         Object JavaDoc targetValueOfSource = null;
352
353         // The target object must be completely merged before setting it otherwise
354
// another thread can pick up the partial object.
355
if (shouldMergeCascadeParts(mergeManager) && (valueOfSource != null)) {
356             if ((mergeManager.getSession().isUnitOfWork()) && (((UnitOfWorkImpl)mergeManager.getSession()).getUnitOfWorkChangeSet() != null)) {
357                 // If it is a unit of work, we have to check if I have a change Set fot this object
358
mergeManager.mergeChanges(mergeManager.getObjectToMerge(valueOfSource), (ObjectChangeSet)((UnitOfWorkChangeSet)((UnitOfWorkImpl)mergeManager.getSession()).getUnitOfWorkChangeSet()).getObjectChangeSetForClone(valueOfSource));
359             } else {
360                 mergeManager.mergeChanges(mergeManager.getObjectToMerge(valueOfSource), null);
361             }
362         }
363
364         if (valueOfSource != null) {
365             // Need to do this after merge so that an object exists in the database
366
targetValueOfSource = mergeManager.getTargetVersionOfSourceObject(valueOfSource);
367         }
368
369         if (this.getDescriptor().getObjectChangePolicy().isObjectChangeTrackingPolicy()) {
370             // Object level or attribute level so lets see if we need to raise the event?
371
Object JavaDoc valueOfTarget = getRealAttributeValueFromObject(target, mergeManager.getSession());
372             if ( valueOfTarget != targetValueOfSource ) { //equality comparison cause both are uow clones
373
this.getDescriptor().getObjectChangePolicy().raiseInternalPropertyChangeEvent(target, getAttributeName(), valueOfTarget, targetValueOfSource);
374             }
375         }
376  
377         targetValueOfSource = getReferenceDescriptor().getObjectBuilder().wrapObject(targetValueOfSource, mergeManager.getSession());
378         setRealAttributeValueInObject(target, targetValueOfSource);
379     }
380
381     /**
382      * INTERNAL:
383      * Return all the fields populated by this mapping, these are foreign keys only.
384      */

385     protected Vector collectFields() {
386         return getForeignKeyFields();
387     }
388
389     /**
390      * INTERNAL:
391      * Returns the foreign key names associated with the mapping.
392      * These are the fields that will be populated by the 1-1 mapping when writting.
393      */

394     public Vector getForeignKeyFields() {
395         return foreignKeyFields;
396     }
397
398     /**
399     * INTERNAL:
400     * Set the foreign key fields associated with the mapping.
401     * These are the fields that will be populated by the 1-1 mapping when writting.
402     */

403     protected void setForeignKeyFields(Vector foreignKeyFields) {
404         this.foreignKeyFields = foreignKeyFields;
405         if (!foreignKeyFields.isEmpty()) {
406             setIsForeignKeyRelationship(true);
407         }
408     }
409
410     /**
411      * INTERNAL:
412      * Return if the 1-1 mapping has a foreign key dependency to its target.
413      * This is true if any of the foreign key fields are true foreign keys,
414      * i.e. populated on write from the targets primary key.
415      */

416     public boolean isForeignKeyRelationship() {
417         return isForeignKeyRelationship;
418     }
419
420     /**
421      * INTERNAL:
422      * Set if the 1-1 mapping has a foreign key dependency to its target.
423      * This is true if any of the foreign key fields are true foreign keys,
424      * i.e. populated on write from the targets primary key.
425      */

426     public void setIsForeignKeyRelationship(boolean isForeignKeyRelationship) {
427         this.isForeignKeyRelationship = isForeignKeyRelationship;
428     }
429
430     /**
431      * INTERNAL:
432      * Insert privately owned parts
433      */

434     public void preInsert(WriteObjectQuery query) throws DatabaseException, OptimisticLockException {
435         if (isForeignKeyRelationship()) {
436             insert(query);
437         }
438     }
439
440     /**
441      * INTERNAL:
442      * Reads the private owned object.
443      */

444     protected Object JavaDoc readPrivateOwnedForObject(ObjectLevelModifyQuery modifyQuery) throws DatabaseException {
445         if (modifyQuery.getSession().isUnitOfWork()) {
446             if (modifyQuery.getObjectChangeSet() != null) {
447                 ObjectReferenceChangeRecord record = (ObjectReferenceChangeRecord) modifyQuery.getObjectChangeSet().getChangesForAttributeNamed(getAttributeName());
448                 if (record != null) {
449                     return record.getOldValue();
450                 }
451             } else { // Old commit.
452
return getRealAttributeValueFromObject(modifyQuery.getBackupClone(), modifyQuery.getSession());
453             }
454         }
455         
456         return null;
457     }
458
459     /**
460      * INTERNAL:
461      * Update privately owned parts
462      */

463     public void preUpdate(WriteObjectQuery query) throws DatabaseException, OptimisticLockException {
464         if (!isAttributeValueInstantiated(query.getObject())) {
465             return;
466         }
467
468         if (isPrivateOwned()) {
469             Object JavaDoc objectInDatabase = readPrivateOwnedForObject(query);
470             if (objectInDatabase != null) {
471                 query.setProperty(this, objectInDatabase);
472             }
473         }
474
475         if (!isForeignKeyRelationship()) {
476             return;
477         }
478
479         update(query);
480     }
481
482     /**
483      * INTERNAL:
484      * Delete privately owned parts
485      */

486     public void postDelete(DeleteObjectQuery query) throws DatabaseException, OptimisticLockException {
487         // Deletion takes place only if it has privately owned parts and mapping is not read only.
488
if (!shouldObjectModifyCascadeToParts(query)) {
489             return;
490         }
491
492         Object JavaDoc object = query.getProperty(this);
493
494         // The object is stored in the query by preDeleteForObjectUsing(...).
495
if (isForeignKeyRelationship()) {
496             if (object != null) {
497                 query.removeProperty(this);
498
499                 //if the query is being passed from an aggregate collection descriptor then
500
// The delete will have been cascaded at update time. This will cause sub objects
501
// to be ignored, and real only classes to throw exceptions.
502
// If it is an aggregate Collection then delay deletes until they should be deleted
503
//CR 2811
504
if (query.isCascadeOfAggregateDelete()) {
505                     query.getSession().getCommitManager().addObjectToDelete(object);
506                 } else {
507                     DeleteObjectQuery deleteQuery = new DeleteObjectQuery();
508                     deleteQuery.setObject(object);
509                     deleteQuery.setCascadePolicy(query.getCascadePolicy());
510                     query.getSession().executeQuery(deleteQuery);
511                 }
512             }
513         }
514     }
515
516     /**
517      * INTERNAL:
518      * Insert privately owned parts
519      */

520     public void postInsert(WriteObjectQuery query) throws DatabaseException, OptimisticLockException {
521         if (!isForeignKeyRelationship()) {
522             insert(query);
523         }
524     }
525
526     /**
527      * INTERNAL:
528      * Update privately owned parts
529      */

530     public void postUpdate(WriteObjectQuery query) throws DatabaseException, OptimisticLockException {
531         if (!isAttributeValueInstantiated(query.getObject())) {
532             return;
533         }
534
535         if (!isForeignKeyRelationship()) {
536             update(query);
537         }
538
539         // If a private owned reference was changed the old value will be set on the query as a property.
540
Object JavaDoc objectInDatabase = query.getProperty(this);
541         if (objectInDatabase != null) {
542             query.removeProperty(this);
543         } else {
544             return;
545         }
546
547         // If there is no change (old commit), it must be determined if the value changed.
548
if (query.getObjectChangeSet() == null) {
549             Object JavaDoc objectInMemory = getRealAttributeValueFromObject(query.getObject(), query.getSession());
550     
551             // delete the object in the database if it is no more a referenced object.
552
if (objectInDatabase != objectInMemory) {
553                 CacheKey cacheKeyForObjectInDatabase = null;
554                 CacheKey cacheKeyForObjectInMemory = new CacheKey(new Vector());
555     
556                 cacheKeyForObjectInDatabase = new CacheKey(getPrimaryKeyForObject(objectInDatabase, query.getSession()));
557     
558                 if (objectInMemory != null) {
559                     cacheKeyForObjectInMemory = new CacheKey(getPrimaryKeyForObject(objectInMemory, query.getSession()));
560                 }
561     
562                 if (cacheKeysAreEqual(cacheKeyForObjectInDatabase, cacheKeyForObjectInMemory)) {
563                     return;
564                 }
565             } else {
566                 return;
567             }
568         }
569             
570         if (query.shouldCascadeOnlyDependentParts()) {
571             query.getSession().getCommitManager().addObjectToDelete(objectInDatabase);
572         } else {
573             query.getSession().deleteObject(objectInDatabase);
574         }
575     }
576
577     /**
578      * INTERNAL:
579      * Delete privately owned parts
580      */

581     public void preDelete(DeleteObjectQuery query) throws DatabaseException, OptimisticLockException {
582         // Deletion takes place according the the cascading policy
583
if (!shouldObjectModifyCascadeToParts(query)) {
584             return;
585         }
586
587         // Get the privately owned parts.
588
Object JavaDoc objectInMemory = getRealAttributeValueFromObject(query.getObject(), query.getSession());
589         Object JavaDoc objectFromDatabase = null;
590
591         // Because the value in memory may have been changed we check the previous value or database value.
592
objectFromDatabase = readPrivateOwnedForObject(query);
593
594         // If the value was changed, both values must be deleted (uow will have inserted the new one).
595
if ((objectFromDatabase != null) && (objectFromDatabase != objectInMemory)) {
596             // Also check pk as may not be maintaining identity.
597
CacheKey cacheKeyForObjectInDatabase = null;
598             CacheKey cacheKeyForObjectInMemory = new CacheKey(new Vector());
599
600             cacheKeyForObjectInDatabase = new CacheKey(getPrimaryKeyForObject(objectFromDatabase, query.getSession()));
601
602             if (objectInMemory != null) {
603                 cacheKeyForObjectInMemory = new CacheKey(getPrimaryKeyForObject(objectInMemory, query.getSession()));
604             }
605             if (!cacheKeysAreEqual(cacheKeyForObjectInMemory, cacheKeyForObjectInDatabase)) {
606                 if (objectFromDatabase != null) {
607                     DeleteObjectQuery deleteQuery = new DeleteObjectQuery();
608                     deleteQuery.setObject(objectFromDatabase);
609                     deleteQuery.setCascadePolicy(query.getCascadePolicy());
610                     query.getSession().executeQuery(deleteQuery);
611                 }
612             }
613         }
614
615         if (!isForeignKeyRelationship()) {
616             if (objectInMemory != null) {
617                 DeleteObjectQuery deleteQuery = new DeleteObjectQuery();
618                 deleteQuery.setObject(objectInMemory);
619                 deleteQuery.setCascadePolicy(query.getCascadePolicy());
620                 query.getSession().executeQuery(deleteQuery);
621             }
622         } else {
623             // The actual deletion of part takes place in postDeleteForObjectUsing(...).
624
if (objectInMemory != null) {
625                 query.setProperty(this, objectInMemory);
626             }
627         }
628     }
629
630     /**
631      * INTERNAL:
632      * Cascade registerNew for Create through mappings that require the cascade
633      */

634     public void cascadePerformRemoveIfRequired(Object JavaDoc object, UnitOfWorkImpl uow, IdentityHashtable visitedObjects){
635         Object JavaDoc attributeValue = getAttributeValueFromObject(object);
636         if (attributeValue != null && this.isCascadeRemove() ){
637             Object JavaDoc reference = getIndirectionPolicy().getRealAttributeValueFromObject(attributeValue);
638             if (reference != null && (! visitedObjects.contains(reference)) ){
639                 visitedObjects.put(reference, reference);
640                 uow.performRemove(reference, visitedObjects);
641             }
642         }
643     }
644
645     /**
646      * INTERNAL:
647      * Cascade registerNew for Create through mappings that require the cascade
648      */

649     public void cascadeRegisterNewIfRequired(Object JavaDoc object, UnitOfWorkImpl uow, IdentityHashtable visitedObjects){
650         Object JavaDoc attributeValue = getAttributeValueFromObject(object);
651         if (attributeValue != null && this.isCascadePersist() && getIndirectionPolicy().objectIsInstantiated(attributeValue)){
652             Object JavaDoc reference = getIndirectionPolicy().getRealAttributeValueFromObject(attributeValue);
653             if (reference != null && (! visitedObjects.contains(reference)) ){
654                 visitedObjects.put(reference, reference);
655                 uow.registerNewObjectForPersist(reference, visitedObjects);
656             }
657         }
658     }
659
660     /**
661      * INTERNAL:
662      */

663     protected boolean cacheKeysAreEqual(CacheKey cacheKey1, CacheKey cacheKey2) {
664         return cacheKey1.equals(cacheKey2);
665     }
666
667     /**
668      * INTERNAL:
669      */

670     protected Vector getPrimaryKeyForObject(Object JavaDoc object, AbstractSession session) {
671         return getReferenceDescriptor().getObjectBuilder().extractPrimaryKeyFromObject(object, session);
672     }
673
674     /**
675      * INTERNAL:
676      * The returns if the mapping has any constraint dependencies, such as foreign keys and join tables.
677      */

678     public boolean hasConstraintDependency() {
679         return isForeignKeyRelationship();
680     }
681
682     /**
683      * INTERNAL:
684      * Builder the unit of work value holder.
685      * @param buildDirectlyFromRow indicates that we are building the clone directly
686      * from a row as opposed to building the original from the row, putting it in
687      * the shared cache, and then cloning the original.
688      */

689     public UnitOfWorkValueHolder createUnitOfWorkValueHolder(ValueHolderInterface attributeValue, Object JavaDoc original, Object JavaDoc clone, AbstractRecord row, UnitOfWorkImpl unitOfWork, boolean buildDirectlyFromRow) {
690         UnitOfWorkQueryValueHolder valueHolder = null;
691         if ((row == null) && (getDescriptor().getObjectBuilder().isPrimaryKeyMapping(this))) {
692             // The row must be built if a primary key mapping for remote case.
693
AbstractRecord rowFromTargetObject = extractPrimaryKeyRowForSourceObject(original, unitOfWork);
694             valueHolder = new UnitOfWorkQueryValueHolder(attributeValue, clone, this, rowFromTargetObject, unitOfWork);
695         } else {
696             valueHolder = new UnitOfWorkQueryValueHolder(attributeValue, clone, this, row, unitOfWork);
697         }
698
699         // In case of joined attributes it so happens that the attributeValue
700
// contains a registered clone, as valueFromRow was called with a
701
// UnitOfWork. So switch the values.
702
// Note that this UOW valueholder starts off as instantiated but that
703
// is fine, for the reality is that it is.
704
if (buildDirectlyFromRow && attributeValue.isInstantiated()) {
705             Object JavaDoc cloneAttributeValue = attributeValue.getValue();
706             valueHolder.privilegedSetValue(cloneAttributeValue);
707             valueHolder.setInstantiated();
708
709             // PERF: Do not modify the original value-holder, it is never used.
710
}
711         return valueHolder;
712     }
713
714     /**
715      * INTERNAL:
716      * Extract the reference pk for rvh usage in remote model.
717      */

718     public AbstractRecord extractPrimaryKeyRowForSourceObject(Object JavaDoc domainObject, AbstractSession session) {
719         AbstractRecord databaseRow = getDescriptor().getObjectBuilder().createRecord();
720         writeFromObjectIntoRow(domainObject, databaseRow, session);
721         return databaseRow;
722     }
723
724     /**
725      * INTERNAL:
726      * Extract the reference pk for rvh usage in remote model.
727      */

728     public Vector extractPrimaryKeysForReferenceObject(Object JavaDoc domainObject, AbstractSession session) {
729         return getIndirectionPolicy().extractPrimaryKeyForReferenceObject(getAttributeValueFromObject(domainObject), session);
730     }
731
732     /**
733      * INTERNAL:
734      * Return the primary key for the reference object (i.e. the object
735      * object referenced by domainObject and specified by mapping).
736      * This key will be used by a RemoteValueHolder.
737      */

738     public Vector extractPrimaryKeysForReferenceObjectFromRow(AbstractRecord row) {
739         return new Vector(1);
740     }
741
742     /**
743      * INTERNAL:
744      * Extract the reference pk for rvh usage in remote model.
745      */

746     public Vector extractPrimaryKeysFromRealReferenceObject(Object JavaDoc object, AbstractSession session) {
747         if (object == null) {
748             return new Vector(1);
749         } else {
750             Object JavaDoc implementation = getReferenceDescriptor().getObjectBuilder().unwrapObject(object, session);
751             return getReferenceDescriptor().getObjectBuilder().extractPrimaryKeyFromObject(implementation, session);
752         }
753     }
754
755     /**
756      * INTERNAL:
757       * Insert privately owned parts
758      */

759     protected void insert(WriteObjectQuery query) throws DatabaseException, OptimisticLockException {
760         // Checks if privately owned parts should be inserted or not.
761
if (!shouldObjectModifyCascadeToParts(query)) {
762             return;
763         }
764
765         // Get the privately owned parts
766
Object JavaDoc object = getRealAttributeValueFromObject(query.getObject(), query.getSession());
767
768         if (object == null) {
769             return;
770         }
771         ObjectChangeSet changeSet = query.getObjectChangeSet();
772         if (changeSet != null) {
773             ObjectReferenceChangeRecord changeRecord = (ObjectReferenceChangeRecord)query.getObjectChangeSet().getChangesForAttributeNamed(getAttributeName());
774             if (changeRecord != null) {
775                 changeSet = (ObjectChangeSet)changeRecord.getNewValue();
776             } else {
777                 // no changeRecord no reference.
778
return;
779             }
780         } else {
781             UnitOfWorkChangeSet uowChangeSet = null;
782
783             // get changeSet for referenced object. Could get it from the changeRecord but that would as much work
784
if (query.getSession().isUnitOfWork() && (((UnitOfWorkImpl)query.getSession()).getUnitOfWorkChangeSet() != null)) {
785                 uowChangeSet = (UnitOfWorkChangeSet)((UnitOfWorkImpl)query.getSession()).getUnitOfWorkChangeSet();
786                 changeSet = (ObjectChangeSet)uowChangeSet.getObjectChangeSetForClone(object);
787             }
788         }
789
790         WriteObjectQuery writeQuery = null;
791         if (isPrivateOwned()) {
792             // no identity check needed for private owned
793
writeQuery = new InsertObjectQuery();
794         } else {
795             writeQuery = new WriteObjectQuery();
796         }
797         writeQuery.setObject(object);
798         writeQuery.setObjectChangeSet(changeSet);
799         writeQuery.setCascadePolicy(query.getCascadePolicy());
800         query.getSession().executeQuery(writeQuery);
801     }
802
803     /**
804      * INTERNAL:
805      * Update the private owned part.
806      */

807     protected void update(WriteObjectQuery query) throws DatabaseException, OptimisticLockException {
808         if (!shouldObjectModifyCascadeToParts(query)) {
809             return;
810         }
811
812         // If objects are not instantiated that means they are not changed.
813
if (!isAttributeValueInstantiated(query.getObject())) {
814             return;
815         }
816
817         // Get the privately owned parts in the memory
818
Object JavaDoc object = getRealAttributeValueFromObject(query.getObject(), query.getSession());
819         if (object != null) {
820             ObjectChangeSet changeSet = query.getObjectChangeSet();
821             if (changeSet != null) {
822                 ObjectReferenceChangeRecord changeRecord = (ObjectReferenceChangeRecord)query.getObjectChangeSet().getChangesForAttributeNamed(getAttributeName());
823                 if (changeRecord != null) {
824                     changeSet = (ObjectChangeSet)changeRecord.getNewValue();
825                 } else {
826                     // no changeRecord no change to reference.
827
return;
828                 }
829             } else {
830                 UnitOfWorkChangeSet uowChangeSet = null;
831
832                 // get changeSet for referenced object. Could get it from the changeRecord but that would as much work
833
if (query.getSession().isUnitOfWork() && (((UnitOfWorkImpl)query.getSession()).getUnitOfWorkChangeSet() != null)) {
834                     uowChangeSet = (UnitOfWorkChangeSet)((UnitOfWorkImpl)query.getSession()).getUnitOfWorkChangeSet();
835                     changeSet = (ObjectChangeSet)uowChangeSet.getObjectChangeSetForClone(object);
836                 }
837             }
838             WriteObjectQuery writeQuery = new WriteObjectQuery();
839             writeQuery.setObject(object);
840             writeQuery.setObjectChangeSet(changeSet);
841             writeQuery.setCascadePolicy(query.getCascadePolicy());
842             query.getSession().executeQuery(writeQuery);
843         }
844     }
845
846     /**
847      * INTERNAL:
848      * To verify if the specified object is deleted or not.
849      */

850     public boolean verifyDelete(Object JavaDoc object, AbstractSession session) throws DatabaseException {
851         if (isPrivateOwned()) {
852             Object JavaDoc attributeValue = getRealAttributeValueFromObject(object, session);
853
854             if (attributeValue != null) {
855                 return session.verifyDelete(attributeValue);
856             }
857         }
858
859         return true;
860     }
861
862     /**
863      * INTERNAL:
864      * Get a value from the object and set that in the respective field of the row.
865      * But before that check if the reference object is instantiated or not.
866      */

867     public void writeFromObjectIntoRowForUpdate(WriteObjectQuery query, AbstractRecord databaseRow) {
868         Object JavaDoc object = query.getObject();
869         AbstractSession session = query.getSession();
870
871         if (!isAttributeValueInstantiated(object)) {
872             return;
873         }
874
875         if (session.isUnitOfWork()) {
876             if (compareObjectsWithoutPrivateOwned(query.getBackupClone(), object, session)) {
877                 return;
878             }
879         }
880
881         writeFromObjectIntoRow(object, databaseRow, session);
882     }
883
884     /**
885      * INTERNAL:
886      * Get a value from the object and set that in the respective field of the row.
887      */

888     public void writeFromObjectIntoRowForWhereClause(ObjectLevelModifyQuery query, AbstractRecord databaseRow) {
889         if (isReadOnly()) {
890             return;
891         }
892
893         if (query.isDeleteObjectQuery()) {
894             writeFromObjectIntoRow(query.getObject(), databaseRow, query.getSession());
895         } else {
896             // If the original was never instantiated the backup clone has a ValueHolder of null
897
// so for this case we must extract from the original object.
898
if (isAttributeValueInstantiated(query.getObject())) {
899                 writeFromObjectIntoRow(query.getBackupClone(), databaseRow, query.getSession());
900             } else {
901                 writeFromObjectIntoRow(query.getObject(), databaseRow, query.getSession());
902             }
903         }
904     }
905     
906     /**
907      * INTERNAL:
908      * Return if this mapping supports change tracking.
909      */

910     public boolean isChangeTrackingSupported() {
911         return true;
912     }
913     
914     /**
915      * INTERNAL:
916      * Either create a new change record or update the change record with the new value.
917      * This is used by attribute change tracking.
918      */

919     public void updateChangeRecord(Object JavaDoc clone, Object JavaDoc newValue, Object JavaDoc oldValue, ObjectChangeSet objectChangeSet, UnitOfWorkImpl uow) {
920         // Must ensure values are unwrapped.
921
Object JavaDoc unwrappedNewValue = newValue;
922         Object JavaDoc unwrappedOldValue = oldValue;
923         if (newValue != null) {
924             unwrappedNewValue = getReferenceDescriptor().getObjectBuilder().unwrapObject(newValue, uow);
925         }
926         if (oldValue != null) {
927             unwrappedOldValue = getReferenceDescriptor().getObjectBuilder().unwrapObject(oldValue, uow);
928         }
929         ObjectReferenceChangeRecord changeRecord = (ObjectReferenceChangeRecord)objectChangeSet.getChangesForAttributeNamed(this.getAttributeName());
930         if (changeRecord == null) {
931             changeRecord = internalBuildChangeRecord(unwrappedNewValue, objectChangeSet, uow);
932             changeRecord.setOldValue(unwrappedOldValue);
933             objectChangeSet.addChange(changeRecord);
934             
935         } else {
936             setNewValueInChangeRecord(unwrappedNewValue, changeRecord, objectChangeSet, uow);
937         }
938     }
939
940     /**
941      * INTERNAL:
942      * Directly build a change record without comparison
943      */

944     public ChangeRecord buildChangeRecord(Object JavaDoc clone, ObjectChangeSet owner, AbstractSession session) {
945         return internalBuildChangeRecord(getRealAttributeValueFromObject(clone, session), owner, session);
946     }
947 }
948
Popular Tags