KickJava   Java API By Example, From Geeks To Geeks.

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


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.mappings;
23
24 import java.security.AccessController JavaDoc;
25 import java.security.PrivilegedActionException JavaDoc;
26 import java.util.*;
27 import oracle.toplink.essentials.exceptions.*;
28 import oracle.toplink.essentials.expressions.*;
29 import oracle.toplink.essentials.indirection.*;
30 import oracle.toplink.essentials.internal.descriptors.*;
31 import oracle.toplink.essentials.internal.expressions.*;
32 import oracle.toplink.essentials.internal.indirection.*;
33 import oracle.toplink.essentials.internal.queryframework.JoinedAttributeManager;
34 import oracle.toplink.essentials.internal.security.PrivilegedAccessHelper;
35 import oracle.toplink.essentials.internal.security.PrivilegedClassForName;
36 import oracle.toplink.essentials.internal.sessions.*;
37 import oracle.toplink.essentials.queryframework.*;
38 import oracle.toplink.essentials.internal.sessions.AbstractRecord;
39 import oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl;
40 import oracle.toplink.essentials.internal.sessions.AbstractSession;
41 import oracle.toplink.essentials.descriptors.ClassDescriptor;
42 import oracle.toplink.essentials.internal.helper.Helper;
43 import oracle.toplink.essentials.sessions.DatabaseRecord;
44
45 /**
46  * <b>Purpose</b>: Abstract class for relationship mappings
47  */

48 public abstract class ForeignReferenceMapping extends DatabaseMapping {
49
50     /** This is used only in descriptor proxy in remote session */
51     protected Class JavaDoc referenceClass;
52     protected String JavaDoc referenceClassName;
53
54     /** The session is temporarily used for initialization. Once used, it is set to null */
55     protected transient AbstractSession tempInitSession;
56
57     /** The descriptor of the reference class. */
58     protected transient ClassDescriptor referenceDescriptor;
59
60     /** This query is used to read referenced objects for this mapping. */
61     protected transient ReadQuery selectionQuery;
62
63     /** Indicates whether the referenced object is privately owned or not. */
64     protected boolean isPrivateOwned;
65
66     /** Implements indirection behavior */
67     protected IndirectionPolicy indirectionPolicy;
68
69     /** Indicates whether the selection query is TopLink generated or defined by the user. */
70     protected transient boolean hasCustomSelectionQuery;
71
72     /** Used to reference the other half of a bi-directional relationship. */
73     protected DatabaseMapping relationshipPartner;
74
75     /** Set by users, used to retreive the backpointer for this mapping */
76     protected String JavaDoc relationshipPartnerAttributeName;
77
78     /** Cascading flags used by the EntityManager */
79     protected boolean cascadePersist;
80     protected boolean cascadeMerge;
81     protected boolean cascadeRefresh;
82     protected boolean cascadeRemove;
83     
84     protected ForeignReferenceMapping() {
85         this.isPrivateOwned = false;
86         this.hasCustomSelectionQuery = false;
87         this.useBasicIndirection();
88         this.cascadePersist = false;
89         this.cascadeMerge = false;
90         this.cascadeRefresh = false;
91         this.cascadeRemove = false;
92     }
93
94     /**
95      * INTERNAL:
96      * Clone the attribute from the clone and assign it to the backup.
97      */

98     public void buildBackupClone(Object JavaDoc clone, Object JavaDoc backup, UnitOfWorkImpl unitOfWork) {
99         Object JavaDoc attributeValue = getAttributeValueFromObject(clone);
100         Object JavaDoc clonedAttributeValue = getIndirectionPolicy().backupCloneAttribute(attributeValue, clone, backup, unitOfWork);
101         setAttributeValueInObject(backup, clonedAttributeValue);
102     }
103
104     /**
105      * INTERNAL:
106      * Used during building the backup shallow copy to copy the
107      * target object without re-registering it.
108      */

109     public abstract Object JavaDoc buildBackupCloneForPartObject(Object JavaDoc attributeValue, Object JavaDoc clone, Object JavaDoc backup, UnitOfWorkImpl unitOfWork);
110
111     /**
112      * INTERNAL:
113      * Clone the attribute from the original and assign it to the clone.
114      */

115     public void buildClone(Object JavaDoc original, Object JavaDoc clone, UnitOfWorkImpl unitOfWork, JoinedAttributeManager joinedAttributeManager) {
116         Object JavaDoc attributeValue = getAttributeValueFromObject(original);
117         Object JavaDoc clonedAttributeValue = getIndirectionPolicy().cloneAttribute(attributeValue, original, clone, unitOfWork, false);// building clone from an original not a row.
118
//GFBug#404 Trigger the value holder of the joined attribute if shouldCascadeCloneToJoinedRelationship (joinedAttributeManager != null)
119
if (joinedAttributeManager != null) {
120             if (joinedAttributeManager.hasJoinedAttributes()) {
121                 if (joinedAttributeManager.getJoinedAttributes().contains(getAttributeName())) {
122                      if (IndirectContainer.class.isAssignableFrom(clonedAttributeValue.getClass())) {
123                          ((IndirectContainer)clonedAttributeValue).getValueHolder().getValue();
124                      } else if (ValueHolderInterface.class.isAssignableFrom(clonedAttributeValue.getClass())) {
125                          ((ValueHolderInterface)clonedAttributeValue).getValue();
126                      }
127                 }
128             }
129         }
130         setAttributeValueInObject(clone, clonedAttributeValue);
131     }
132
133     /**
134      * INTERNAL:
135      * A combination of readFromRowIntoObject and buildClone.
136      * <p>
137      * buildClone assumes the attribute value exists on the original and can
138      * simply be copied.
139      * <p>
140      * readFromRowIntoObject assumes that one is building an original.
141      * <p>
142      * Both of the above assumptions are false in this method, and actually
143      * attempts to do both at the same time.
144      * <p>
145      * Extract value from the row and set the attribute to this value in the
146      * working copy clone.
147      * In order to bypass the shared cache when in transaction a UnitOfWork must
148      * be able to populate working copies directly from the row.
149      */

150     public void buildCloneFromRow(AbstractRecord databaseRow, JoinedAttributeManager joinManager, Object JavaDoc clone, ObjectBuildingQuery sourceQuery, UnitOfWorkImpl unitOfWork, AbstractSession executionSession) {
151         Object JavaDoc attributeValue = valueFromRow(databaseRow, joinManager, sourceQuery, executionSession);
152         Object JavaDoc clonedAttributeValue = getIndirectionPolicy().cloneAttribute(attributeValue, null,// no original
153
clone, unitOfWork, true);// building clone directly from row.
154
setAttributeValueInObject(clone, clonedAttributeValue);
155     }
156
157     /**
158      * INTERNAL:
159      * Require for cloning, the part must be cloned.
160      */

161     public abstract Object JavaDoc buildCloneForPartObject(Object JavaDoc attributeValue, Object JavaDoc original, Object JavaDoc clone, UnitOfWorkImpl unitOfWork, boolean isExisting);
162
163     /**
164      * INTERNAL:
165      * The mapping clones itself to create deep copy.
166      */

167     public Object JavaDoc clone() {
168         ForeignReferenceMapping clone = (ForeignReferenceMapping)super.clone();
169
170         clone.setIndirectionPolicy((IndirectionPolicy)indirectionPolicy.clone());
171         clone.setSelectionQuery((ReadQuery)getSelectionQuery().clone());
172
173         return clone;
174     }
175
176     /**
177      * INTERNAL:
178      * Compare the attributes belonging to this mapping for the objects.
179      */

180     public boolean compareObjects(Object JavaDoc firstObject, Object JavaDoc secondObject, AbstractSession session) {
181         if (isPrivateOwned()) {
182             return compareObjectsWithPrivateOwned(firstObject, secondObject, session);
183         } else {
184             return compareObjectsWithoutPrivateOwned(firstObject, secondObject, session);
185         }
186     }
187
188     /**
189      * Compare two objects if their parts are not private owned
190      */

191     protected abstract boolean compareObjectsWithoutPrivateOwned(Object JavaDoc first, Object JavaDoc second, AbstractSession session);
192
193     /**
194      * Compare two objects if their parts are private owned
195      */

196     protected abstract boolean compareObjectsWithPrivateOwned(Object JavaDoc first, Object JavaDoc second, AbstractSession session);
197
198     /**
199      * INTERNAL:
200      * Convert all the class-name-based settings in this mapping to actual class-based
201      * settings. This method is used when converting a project that has been built
202      * with class names to a project with classes.
203      * @param classLoader
204      */

205     public void convertClassNamesToClasses(ClassLoader JavaDoc classLoader){
206         super.convertClassNamesToClasses(classLoader);
207         Class JavaDoc referenceClass = null;
208         try{
209             if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
210                 try {
211                     referenceClass = (Class JavaDoc)AccessController.doPrivileged(new PrivilegedClassForName(getReferenceClassName(), true, classLoader));
212                 } catch (PrivilegedActionException JavaDoc exception) {
213                     throw ValidationException.classNotFoundWhileConvertingClassNames(getReferenceClassName(), exception.getException());
214                 }
215             } else {
216                 referenceClass = oracle.toplink.essentials.internal.security.PrivilegedAccessHelper.getClassForName(getReferenceClassName(), true, classLoader);
217             }
218         } catch (ClassNotFoundException JavaDoc exc){
219             throw ValidationException.classNotFoundWhileConvertingClassNames(getReferenceClassName(), exc);
220         }
221         setReferenceClass(referenceClass);
222     };
223
224     /**
225      * INTERNAL:
226      * Builder the unit of work value holder.
227      * Ignore the original object.
228      * @param buildDirectlyFromRow indicates that we are building the clone directly
229      * from a row as opposed to building the original from the row, putting it in
230      * the shared cache, and then cloning the original.
231      */

232     public UnitOfWorkValueHolder createUnitOfWorkValueHolder(ValueHolderInterface attributeValue, Object JavaDoc original, Object JavaDoc clone, AbstractRecord row, UnitOfWorkImpl unitOfWork, boolean buildDirectlyFromRow) {
233         return new UnitOfWorkQueryValueHolder(attributeValue, clone, this, row, unitOfWork);
234     }
235
236     /**
237      * INTERNAL:
238      * Return true if the merge should be bypassed. This would be the case for several reasons, depending on
239      * the kind of merge taking place.
240      */

241     protected boolean dontDoMerge(Object JavaDoc target, Object JavaDoc source, MergeManager mergeManager) {
242         if (!shouldMergeCascadeReference(mergeManager)) {
243             return true;
244         }
245         if (mergeManager.shouldMergeOriginalIntoWorkingCopy()) {
246             // For reverts we are more concerned about the target than the source.
247
if (!isAttributeValueInstantiated(target)) {
248                 return true;
249             }
250         } else {
251             if (mergeManager.shouldRefreshRemoteObject() && shouldMergeCascadeParts(mergeManager) && usesIndirection()) {
252                 return true;
253             } else {
254                 if (!isAttributeValueInstantiated(source)) {
255                     return true;
256                 }
257             }
258         }
259         return false;
260     }
261
262     /**
263      * PUBLIC:
264      * Indirection means that a ValueHolder will be put in-between the attribute and the real object.
265      * This allows for the reading of the target from the database to be delayed until accessed.
266      * This defaults to true and is strongly suggested as it give a huge performance gain.
267      */

268     public void dontUseIndirection() {
269         setIndirectionPolicy(new NoIndirectionPolicy());
270     }
271
272     /**
273      * INTERNAL:
274      * Clone and prepare the JoinedAttributeManager nested JoinedAttributeManager.
275      * This is used for nested joining as the JoinedAttributeManager passed to the joined build object.
276      */

277     public ObjectLevelReadQuery prepareNestedJoins(JoinedAttributeManager joinManager, AbstractSession session) {
278         // A nested query must be built to pass to the descriptor that looks like the real query execution would.
279
ObjectLevelReadQuery nestedQuery = (ObjectLevelReadQuery)((ObjectLevelReadQuery)getSelectionQuery()).deepClone();
280         //set session to be the session on which the query is being executed
281
nestedQuery.setSession(session);
282         // Recompute the joined indexes based on the nested join expressions.
283
nestedQuery.getJoinedAttributeManager().setJoinedMappingIndexes_(null);
284         nestedQuery.getJoinedAttributeManager().setJoinedMappingExpressions_(new ArrayList(1));
285         nestedQuery.getJoinedAttributeManager().setJoinedAttributeExpressions_(extractNestedExpressions(joinManager.getJoinedAttributeExpressions(), nestedQuery.getExpressionBuilder(), false));
286         // the next line sets isToManyJoinQuery flag
287
nestedQuery.getJoinedAttributeManager().prepareJoinExpressions(session);
288         nestedQuery.getJoinedAttributeManager().computeJoiningMappingIndexes(true, session, 0);
289         if (joinManager.getBaseQuery().isLockQuery()) {
290             ObjectLevelReadQuery baseQuery = ((ObjectLevelReadQuery)joinManager.getBaseQuery());
291             if (baseQuery.getLockingClause().isForUpdateOfClause()) {
292                 ForUpdateOfClause clause = (ForUpdateOfClause)baseQuery.getLockingClause().clone();
293                 clause.setLockedExpressions(extractNestedExpressions(clause.getLockedExpressions(), nestedQuery.getExpressionBuilder(), true));
294                 nestedQuery.setLockingClause(clause);
295             } else {
296                 nestedQuery.setLockingClause(baseQuery.getLockingClause());
297             }
298         }
299         nestedQuery.setShouldMaintainCache(joinManager.getBaseQuery().shouldMaintainCache());
300         nestedQuery.setShouldRefreshIdentityMapResult(joinManager.getBaseQuery().shouldRefreshIdentityMapResult());
301         nestedQuery.setCascadePolicy(joinManager.getBaseQuery().getCascadePolicy());
302         nestedQuery.setSession(null);
303
304         return nestedQuery;
305
306     }
307
308     /**
309      * INTERNAL:
310      * Return the value of an attribute which this mapping represents for an object.
311      */

312     public Object JavaDoc getAttributeValueFromObject(Object JavaDoc object) throws DescriptorException {
313         Object JavaDoc attributeValue = super.getAttributeValueFromObject(object);
314         Object JavaDoc indirectionValue = getIndirectionPolicy().validateAttributeOfInstantiatedObject(attributeValue);
315
316         // PERF: Allow the indirection policy to initialize null attribute values,
317
// this allows the indirection objects to not be initialized in the constructor.
318
if (indirectionValue != attributeValue) {
319             setAttributeValueInObject(object, indirectionValue);
320             attributeValue = indirectionValue;
321         }
322         return attributeValue;
323     }
324
325     /**
326      * INTERNAL:
327      * Return the mapping's indirection policy.
328      */

329     public IndirectionPolicy getIndirectionPolicy() {
330         return indirectionPolicy;
331     }
332
333     /**
334      * INTERNAL:
335      * Returns the join criteria stored in the mapping selection query. This criteria
336      * is used to read reference objects across the tables from the database.
337      */

338     public Expression getJoinCriteria(QueryKeyExpression exp) {
339         Expression selectionCriteria = getSelectionCriteria();
340         return exp.getBaseExpression().twist(selectionCriteria, exp);
341     }
342
343     /**
344      * INTERNAL:
345      * Returns the attribute value from the reference object.
346      * If the attribute is using indirection the value of the value-holder is returned.
347      * If the value holder is not instantiated then it is instantiated.
348      */

349     public Object JavaDoc getRealAttributeValueFromObject(Object JavaDoc object, AbstractSession session) {
350         return getIndirectionPolicy().getRealAttributeValueFromObject(getAttributeValueFromObject(object));
351     }
352
353     /**
354      * PUBLIC:
355      * Returns the reference class.
356      */

357     public Class JavaDoc getReferenceClass() {
358         return referenceClass;
359     }
360
361     /**
362      * INTERNAL:
363      * Returns the reference class name.
364      */

365     public String JavaDoc getReferenceClassName() {
366         if ((referenceClassName == null) && (referenceClass != null)) {
367             referenceClassName = referenceClass.getName();
368         }
369         return referenceClassName;
370     }
371
372     /**
373      * INTERNAL:
374      * Return the referenceDescriptor. This is a descriptor which is associated with
375      * the reference class.
376      */

377     public ClassDescriptor getReferenceDescriptor() {
378         if (referenceDescriptor == null) {
379             if (getTempSession() == null) {
380                 return null;
381             } else {
382                 referenceDescriptor = getTempSession().getDescriptor(getReferenceClass());
383             }
384         }
385
386         return referenceDescriptor;
387     }
388
389     /**
390      * INTERNAL:
391      * Return the relationshipPartner mapping for this bi-directional mapping. If the relationshipPartner is null then
392      * this is a uni-directional mapping.
393      */

394     public DatabaseMapping getRelationshipPartner() {
395         if ((this.relationshipPartner == null) && (this.relationshipPartnerAttributeName != null)) {
396             setRelationshipPartner(getReferenceDescriptor().getMappingForAttributeName(getRelationshipPartnerAttributeName()));
397         }
398         return this.relationshipPartner;
399     }
400
401     /**
402      * PUBLIC:
403      * Use this method retreive the relationship partner attribute name of this bidirectional Mapping.
404      */

405     public String JavaDoc getRelationshipPartnerAttributeName() {
406         return this.relationshipPartnerAttributeName;
407     }
408
409     /**
410      * INTERNAL:
411      * Returns the selection criteria stored in the mapping selection query. This criteria
412      * is used to read reference objects from the database.
413      */

414     public Expression getSelectionCriteria() {
415         return getSelectionQuery().getSelectionCriteria();
416     }
417
418     /**
419      * INTERNAL:
420      * Returns the read query assoicated with the mapping.
421      */

422     public ReadQuery getSelectionQuery() {
423         return selectionQuery;
424     }
425
426     protected AbstractSession getTempSession() {
427         return tempInitSession;
428     }
429
430     /**
431      * INTERNAL:
432      * Indicates whether the selection query is TopLink generated or defined by
433      * the user.
434      */

435     public boolean hasCustomSelectionQuery() {
436         return hasCustomSelectionQuery;
437     }
438
439     /**
440      * INTERNAL:
441      * Initialize the state of mapping.
442      */

443     public void initialize(AbstractSession session) throws DescriptorException {
444         super.initialize(session);
445         initializeReferenceDescriptor(session);
446         initializeSelectionQuery(session);
447         getIndirectionPolicy().initialize();
448     }
449
450     /**
451      * Initialize and set the descriptor for the referenced class in this mapping.
452      */

453     protected void initializeReferenceDescriptor(AbstractSession session) throws DescriptorException {
454         if (getReferenceClass() == null) {
455             throw DescriptorException.referenceClassNotSpecified(this);
456         }
457
458         ClassDescriptor refDescriptor = session.getDescriptor(getReferenceClass());
459
460         if (refDescriptor == null) {
461             throw DescriptorException.descriptorIsMissing(getReferenceClass().getName(), this);
462         }
463
464         if (refDescriptor.isAggregateDescriptor() && (!isAggregateCollectionMapping())) {
465             throw DescriptorException.referenceDescriptorCannotBeAggregate(this);
466         }
467
468         // can not be isolated if it is null. Seems that only aggregates do not set
469
// the owning descriptor on the mapping.
470
if ((!((this.getDescriptor() != null) && this.getDescriptor().isIsolated())) && refDescriptor.isIsolated()) {
471             throw DescriptorException.isolateDescriptorReferencedBySharedDescriptor(refDescriptor.getJavaClassName(), this.getDescriptor().getJavaClassName(), this);
472         }
473
474         setReferenceDescriptor(refDescriptor);
475     }
476
477     /**
478      * A subclass should implement this method if it wants non default behaviour.
479      */

480     protected void initializeSelectionQuery(AbstractSession session) throws DescriptorException {
481         if (((ObjectLevelReadQuery)getSelectionQuery()).getReferenceClass() == null) {
482             throw DescriptorException.referenceClassNotSpecified(this);
483         }
484
485         getSelectionQuery().setDescriptor(getReferenceDescriptor());
486     }
487
488     /**
489      * INTERNAL:
490      * The referenced object is checked if it is instantiated or not
491      */

492     public boolean isAttributeValueInstantiated(Object JavaDoc object) {
493         return getIndirectionPolicy().objectIsInstantiated(getAttributeValueFromObject(object));
494     }
495
496     /**
497      * PUBLIC:
498      * Check cascading value for the CREATE operation.
499      */

500     public boolean isCascadePersist() {
501         return this.cascadePersist;
502     }
503
504     /**
505      * PUBLIC:
506      * Check cascading value for the MERGE operation.
507      */

508     public boolean isCascadeMerge() {
509         return this.cascadeMerge;
510     }
511
512     /**
513      * PUBLIC:
514      * Check cascading value for the REFRESH operation.
515      */

516     public boolean isCascadeRefresh() {
517         return this.cascadeRefresh;
518     }
519
520     /**
521      * PUBLIC:
522      * Check cascading value for the REMOVE operation.
523      */

524     public boolean isCascadeRemove() {
525         return this.cascadeRemove;
526     }
527
528     /**
529      * INTERNAL:
530      */

531     public boolean isForeignReferenceMapping() {
532         return true;
533     }
534     
535     /**
536      * INTERNAL:
537      * Return true if referenced objects are provately owned else false.
538      */

539     public boolean isPrivateOwned() {
540         return isPrivateOwned;
541     }
542
543     /**
544      * INTERNAL:
545      * Iterate on the iterator's current object's attribute defined by this mapping.
546      * The iterator's settings for cascading and value holders determine how the
547      * iteration continues from here.
548      */

549     public void iterate(DescriptorIterator iterator) {
550         Object JavaDoc attributeValue = this.getAttributeValueFromObject(iterator.getVisitedParent());
551         this.getIndirectionPolicy().iterateOnAttributeValue(iterator, attributeValue);
552     }
553
554     /**
555      * INTERNAL:
556      * Iterate on the attribute value.
557      * The value holder has already been processed.
558      */

559     public abstract void iterateOnRealAttributeValue(DescriptorIterator iterator, Object JavaDoc realAttributeValue);
560
561     /**
562      * PUBLIC:
563      * Sets the reference object to be a private owned. The default behaviour is non
564      * private owned.
565      */

566     public void privateOwnedRelationship() {
567         setIsPrivateOwned(true);
568     }
569
570     /**
571      * PUBLIC:
572      * Sets the cascading for all operations.
573      */

574     public void setCascadeAll(boolean value) {
575         setCascadePersist(value);
576         setCascadeMerge(value);
577         setCascadeRefresh(value);
578         setCascadeRemove(value);
579     }
580
581     /**
582      * PUBLIC:
583      * Sets the cascading for the CREATE operation.
584      */

585     public void setCascadePersist(boolean value) {
586         this.cascadePersist = value;
587     }
588
589     /**
590      * PUBLIC:
591      * Sets the cascading for the MERGE operation.
592      */

593     public void setCascadeMerge(boolean value) {
594         this.cascadeMerge = value;
595     }
596
597     /**
598      * PUBLIC:
599      * Sets the cascading for the REFRESH operation.
600      */

601     public void setCascadeRefresh(boolean value) {
602         this.cascadeRefresh = value;
603     }
604
605     /**
606      * PUBLIC:
607      * Sets the cascading for the REMOVE operation.
608      */

609     public void setCascadeRemove(boolean value) {
610         this.cascadeRemove = value;
611     }
612
613     /**
614      * PUBLIC:
615      * Relationship mappings creates a read query to read reference objects. If this default
616      * query needs to be customize then user can specify its own read query to do the reading
617      * of reference objects. One must instance of ReadQuery or subclasses of the ReadQuery.
618      */

619     public void setCustomSelectionQuery(ReadQuery query) {
620         setSelectionQuery(query);
621         setHasCustomSelectionQuery(true);
622     }
623
624     protected void setHasCustomSelectionQuery(boolean bool) {
625         hasCustomSelectionQuery = bool;
626     }
627
628     /**
629      * ADVANCED:
630      * Set the indirection policy.
631      */

632     public void setIndirectionPolicy(IndirectionPolicy indirectionPolicy) {
633         this.indirectionPolicy = indirectionPolicy;
634         indirectionPolicy.setMapping(this);
635     }
636
637     /**
638      * INTERNAL:
639      * Used by Gromit
640      */

641     public void setIsPrivateOwned(boolean isPrivateOwned) {
642         this.isPrivateOwned = isPrivateOwned;
643     }
644
645     /**
646      * INTERNAL:
647      * Set the value of the attribute mapped by this mapping,
648      * placing it inside a value holder if necessary.
649      * If the value holder is not instantiated then it is instantiated.
650      */

651     public void setRealAttributeValueInObject(Object JavaDoc object, Object JavaDoc value) throws DescriptorException {
652         this.getIndirectionPolicy().setRealAttributeValueInObject(object, value);
653     }
654
655     /**
656      * PUBLIC:
657      * Set the referenced class.
658      */

659     public void setReferenceClass(Class JavaDoc referenceClass) {
660         this.referenceClass = referenceClass;
661         if (referenceClass != null) {
662             setReferenceClassName(referenceClass.getName());
663             // Make sure the reference class of the selectionQuery is set.
664
setSelectionQuery(getSelectionQuery());
665         }
666     }
667
668     /**
669      * INTERNAL:
670      * Used by MW.
671      */

672     public void setReferenceClassName(String JavaDoc referenceClassName) {
673         this.referenceClassName = referenceClassName;
674     }
675
676     /**
677      * Set the referenceDescriptor. This is a descriptor which is associated with
678      * the reference class.
679      */

680     protected void setReferenceDescriptor(ClassDescriptor aDescriptor) {
681         referenceDescriptor = aDescriptor;
682     }
683
684     /**
685      * INTERNAL:
686      * Sets the relationshipPartner mapping for this bi-directional mapping. If the relationshipPartner is null then
687      * this is a uni-directional mapping.
688      */

689     public void setRelationshipPartner(DatabaseMapping mapping) {
690         this.relationshipPartner = mapping;
691     }
692
693     /**
694     * PUBLIC:
695     * Use this method to specify the relationship partner attribute name of a bidirectional Mapping.
696     * TopLink will use the attribute name to find the back pointer mapping to maintain referential integrity of
697     * the bi-directional mappings.
698     */

699     public void setRelationshipPartnerAttributeName(String JavaDoc attributeName) {
700         this.relationshipPartnerAttributeName = attributeName;
701     }
702
703     /**
704      * PUBLIC:
705      * Sets the selection criteria to be used as a where clause to read
706      * reference objects. This criteria is automatically generated by the
707      * TopLink if not explicitly specified by the user.
708      */

709     public void setSelectionCriteria(Expression anExpression) {
710         getSelectionQuery().setSelectionCriteria(anExpression);
711     }
712
713     /**
714      * Sets the query
715      */

716     protected void setSelectionQuery(ReadQuery aQuery) {
717         selectionQuery = aQuery;
718         // Make sure the reference class of the selectionQuery is set.
719
if ((selectionQuery != null) && selectionQuery.isObjectLevelReadQuery() && (selectionQuery.getReferenceClassName() == null)) {
720             ((ObjectLevelReadQuery)selectionQuery).setReferenceClass(getReferenceClass());
721         }
722     }
723
724     /**
725      * PUBLIC:
726      * This is a property on the mapping which will allow custom SQL to be
727      * substituted for reading a reference object.
728      */

729     public void setSelectionSQLString(String JavaDoc sqlString) {
730         getSelectionQuery().setSQLString(sqlString);
731         setCustomSelectionQuery(getSelectionQuery());
732     }
733
734     /**
735      * PUBLIC:
736      * This is a property on the mapping which will allow custom call to be
737      * substituted for reading a reference object.
738      */

739     public void setSelectionCall(Call call) {
740         getSelectionQuery().setCall(call);
741         setCustomSelectionQuery(getSelectionQuery());
742     }
743
744     protected void setTempSession(AbstractSession session) {
745         this.tempInitSession = session;
746     }
747
748     /**
749      * PUBLIC:
750      * Indirection means that a ValueHolder will be put in-between the attribute and the real object.
751      * This allows for the reading of the target from the database to be delayed until accessed.
752      * This defaults to true and is strongly suggested as it give a huge performance gain.
753      * @see #useBasicIndirection()
754      * @see #dontUseIndirection()
755      */

756     public void setUsesIndirection(boolean usesIndirection) {
757         if (usesIndirection) {
758             useBasicIndirection();
759         } else {
760             dontUseIndirection();
761         }
762     }
763
764     protected boolean shouldInitializeSelectionCriteria() {
765         if (hasCustomSelectionQuery()) {
766             return false;
767         }
768
769         if (getSelectionCriteria() == null) {
770             return true;
771         }
772
773         return false;
774     }
775
776     /**
777      * INTERNAL:
778      * Returns true if the merge should cascade to the mappings reference's parts.
779      */

780     public boolean shouldMergeCascadeParts(MergeManager mergeManager) {
781         return ((mergeManager.shouldCascadeByMapping() && this.isCascadeMerge()) || (mergeManager.shouldCascadeAllParts()) || (mergeManager.shouldCascadePrivateParts() && isPrivateOwned()));
782     }
783
784     /**
785      * Returns true if the merge should cascade to the mappings reference.
786      */

787     protected boolean shouldMergeCascadeReference(MergeManager mergeManager) {
788         if (mergeManager.shouldCascadeReferences()) {
789             return true;
790         }
791
792         // P2.0.1.3: Was merging references on non-privately owned parts
793
// Same logic in:
794
return shouldMergeCascadeParts(mergeManager);
795     }
796
797     /**
798      * Returns true if any process leading to object modification should also affect its parts
799      * Usually used by write, insert, update and delete.
800      */

801     protected boolean shouldObjectModifyCascadeToParts(ObjectLevelModifyQuery query) {
802         if (isReadOnly()) {
803             return false;
804         }
805
806         // Only cascade dependents writes in uow.
807
if (query.shouldCascadeOnlyDependentParts()) {
808             return hasConstraintDependency();
809         }
810
811         if (isPrivateOwned()) {
812             return true;
813         }
814
815         return query.shouldCascadeAllParts();
816     }
817
818     /**
819      * PUBLIC:
820      * Indirection means that a ValueHolder will be put in-between the attribute and the real object.
821      * This allows for the reading of the target from the database to be delayed until accessed.
822      * This defaults to true and is strongly suggested as it give a huge performance gain.
823      */

824     public void useBasicIndirection() {
825         setIndirectionPolicy(new BasicIndirectionPolicy());
826     }
827
828     /**
829      * PUBLIC:
830      * Indirection means that some sort of indirection object will be put in-between the attribute and the real object.
831      * This allows for the reading of the target from the database to be delayed until accessed.
832      * This defaults to true and is strongly suggested as it give a huge performance gain.
833      */

834     public boolean usesIndirection() {
835         return getIndirectionPolicy().usesIndirection();
836     }
837
838     /**
839      * INTERNAL:
840      * To validate mappings decleration
841      */

842     public void validateBeforeInitialization(AbstractSession session) throws DescriptorException {
843         super.validateBeforeInitialization(session);
844
845         if (getAttributeAccessor() instanceof InstanceVariableAttributeAccessor) {
846             Class JavaDoc attributeType = ((InstanceVariableAttributeAccessor)getAttributeAccessor()).getAttributeType();
847             getIndirectionPolicy().validateDeclaredAttributeType(attributeType, session.getIntegrityChecker());
848         } else if (getAttributeAccessor() instanceof MethodAttributeAccessor) {
849             Class JavaDoc returnType = ((MethodAttributeAccessor)getAttributeAccessor()).getGetMethodReturnType();
850             getIndirectionPolicy().validateGetMethodReturnType(returnType, session.getIntegrityChecker());
851
852             Class JavaDoc parameterType = ((MethodAttributeAccessor)getAttributeAccessor()).getSetMethodParameterType();
853             getIndirectionPolicy().validateSetMethodParameterType(parameterType, session.getIntegrityChecker());
854         }
855     }
856
857     /**
858      * INTERNAL:
859      * Return the value of the reference attribute or a value holder.
860      * Check whether the mapping's attribute should be optimized through batch and joining.
861      */

862     public Object JavaDoc valueFromRow(AbstractRecord row, JoinedAttributeManager joinManager, ObjectBuildingQuery query, AbstractSession executionSession) throws DatabaseException {
863         if(shouldUseValueFromRowWithJoin(joinManager)) {
864             return valueFromRowInternalWithJoin(row, joinManager, executionSession);
865         } else {
866             return valueFromRowInternal(row, joinManager, executionSession);
867         }
868     }
869     
870     /**
871      * INTERNAL:
872      * Indicates whether valueFromRow should call valueFromRowInternalWithJoin (true)
873      * or valueFromRowInternal (false)
874      */

875     protected boolean shouldUseValueFromRowWithJoin(JoinedAttributeManager joinManager) {
876         return isJoiningSupported() && (
877                 joinManager.isAttributeJoined(getDescriptor(), getAttributeName()) ||
878                 joinManager.getBaseQuery().hasPartialAttributeExpressions()); // only true on OLRQ and above
879
}
880     
881     /**
882      * INTERNAL:
883      * If the query used joining or partial attributes, build the target object directly.
884      * If isJoiningSupported()==true then this method must be overridden.
885      * Currently only 1-1, 1-m and m-m support joining.
886      * Potentially agg-col, dc, dm may support it too (agg-col and dc by just implementing
887      * isJoiningSupported(){return true;} - but that should be tested).
888      */

889     protected Object JavaDoc valueFromRowInternalWithJoin(AbstractRecord row, JoinedAttributeManager joinManager, AbstractSession executionSession) throws DatabaseException {
890         throw ValidationException.mappingDoesNotOverrideValueFromRowInternalWithJoin(Helper.getShortClassName(this.getClass()));
891     }
892     
893     /**
894      * INTERNAL:
895      * Return the value of the reference attribute or a value holder.
896      * Check whether the mapping's attribute should be optimized through batch and joining.
897      */

898     protected Object JavaDoc valueFromRowInternal(AbstractRecord row, JoinedAttributeManager joinManager, AbstractSession executionSession) throws DatabaseException {
899         // PERF: Direct variable access.
900
ReadQuery targetQuery = this.selectionQuery;
901
902         //CR #4365, 3610825 - moved up from the block below, needs to be set with
903
// indirection off. Clone the query and set its id.
904
if (!this.indirectionPolicy.usesIndirection()) {
905             targetQuery = (ReadQuery)targetQuery.clone();
906             targetQuery.setQueryId(joinManager.getBaseQuery().getQueryId());
907         }
908
909         // if the source query is cascading then the target query must use the same settings
910
if (targetQuery.isObjectLevelReadQuery() && (joinManager.getBaseQuery().shouldCascadeAllParts() || (this.isPrivateOwned && joinManager.getBaseQuery().shouldCascadePrivateParts()) || (this.cascadeRefresh && joinManager.getBaseQuery().shouldCascadeByMapping()))) {
911             // If the target query has already been cloned (we're refreshing) avoid
912
// re-cloning the query again.
913
if (targetQuery == this.selectionQuery) {
914                 targetQuery = (ObjectLevelReadQuery)targetQuery.clone();
915             }
916
917             ((ObjectLevelReadQuery)targetQuery).setShouldRefreshIdentityMapResult(joinManager.getBaseQuery().shouldRefreshIdentityMapResult());
918             targetQuery.setCascadePolicy(joinManager.getBaseQuery().getCascadePolicy());
919
920             // For queries that have turned caching off, such as aggregate collection, leave it off.
921
if (targetQuery.shouldMaintainCache()) {
922                 targetQuery.setShouldMaintainCache(joinManager.getBaseQuery().shouldMaintainCache());
923             }
924         }
925         if (joinManager.getBaseQuery().isObjectLevelReadQuery()){
926             targetQuery = prepareHistoricalQuery(targetQuery, (ObjectLevelReadQuery)joinManager.getBaseQuery(), executionSession);
927         }
928
929         return this.indirectionPolicy.valueFromQuery(targetQuery, row, executionSession);
930     }
931     
932     /**
933      * INTERNAL:
934      * Allow for the mapping to perform any historical query additions.
935      * Return the new target query.
936      */

937     protected ReadQuery prepareHistoricalQuery(ReadQuery targetQuery, ObjectLevelReadQuery sourceQuery, AbstractSession executionSession) {
938         return targetQuery;
939     }
940
941     /**
942      * INTERNAL:
943      */

944     public AbstractRecord trimRowForJoin(AbstractRecord row, JoinedAttributeManager joinManager, AbstractSession executionSession) {
945         // CR #... the field for many objects may be in the row,
946
// so build the subpartion of the row through the computed values in the query,
947
// this also helps the field indexing match.
948
if (joinManager.getJoinedMappingIndexes_() != null) {
949             Object JavaDoc value = joinManager.getJoinedMappingIndexes_().get(this);
950             if(value != null) {
951                 return trimRowForJoin(row, value, executionSession);
952             }
953         }
954         return row;
955     }
956
957     /**
958      * INTERNAL:
959      */

960     public AbstractRecord trimRowForJoin(AbstractRecord row, Object JavaDoc value, AbstractSession executionSession) {
961         // CR #... the field for many objects may be in the row,
962
// so build the subpartion of the row through the computed values in the query,
963
// this also helps the field indexing match.
964
int fieldStartIndex;
965         if(value instanceof Integer JavaDoc) {
966             fieldStartIndex = ((Integer JavaDoc)value).intValue();
967         } else {
968             // must be Map of classes to Integers
969
Map map = (Map)value;
970             Class JavaDoc cls;
971             if (getDescriptor().hasInheritance() && getDescriptor().getInheritancePolicy().shouldReadSubclasses()) {
972                 cls = getDescriptor().getInheritancePolicy().classFromRow(row, executionSession);
973             } else {
974                 cls = getDescriptor().getJavaClass();
975             }
976             fieldStartIndex = ((Integer JavaDoc)map.get(cls)).intValue();
977         }
978         Vector trimedFields = Helper.copyVector(row.getFields(), fieldStartIndex, row.size());
979         Vector trimedValues = Helper.copyVector(row.getValues(), fieldStartIndex, row.size());
980         return new DatabaseRecord(trimedFields, trimedValues);
981     }
982 }
983
Popular Tags