KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > oracle > toplink > essentials > internal > indirection > TransparentIndirectionPolicy


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

21 // Copyright (c) 1998, 2005, Oracle. All rights reserved.
22
package oracle.toplink.essentials.internal.indirection;
23
24 import java.util.*;
25 import oracle.toplink.essentials.mappings.*;
26 import oracle.toplink.essentials.queryframework.*;
27 import oracle.toplink.essentials.indirection.*;
28 import oracle.toplink.essentials.exceptions.*;
29 import oracle.toplink.essentials.internal.descriptors.*;
30 import oracle.toplink.essentials.internal.queryframework.*;
31 import oracle.toplink.essentials.internal.helper.*;
32 import oracle.toplink.essentials.internal.sessions.AbstractRecord;
33 import oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl;
34 import oracle.toplink.essentials.internal.sessions.AbstractSession;
35
36 /**
37  * <h2>Purpose</h2>:
38  * TransparentIndirectionPolicy implements the behavior necessary for a
39  * a CollectionMapping to use
40  * IndirectContainers to delay the reading of objects from the database
41  * until they are actually needed.
42  *
43  * @see CollectionMapping
44  * @see IndirectContainer
45  * @author Big Country
46  * @since TOPLink/Java 2.5
47  */

48 public class TransparentIndirectionPolicy extends IndirectionPolicy {
49     //3732
50
protected static Integer JavaDoc defaultContainerSize;
51
52     /**
53      * INTERNAL:
54      * Construct a new indirection policy.
55      */

56     public TransparentIndirectionPolicy() {
57         super();
58     }
59
60     /**
61      * INTERNAL:
62      * Return a backup clone of the attribute.
63      */

64     public Object JavaDoc backupCloneAttribute(Object JavaDoc attributeValue, Object JavaDoc clone, Object JavaDoc backup, UnitOfWorkImpl unitOfWork) {
65         // delay instantiation until absolutely necessary
66
if ((!(attributeValue instanceof IndirectContainer)) || objectIsInstantiated(attributeValue)) {
67             return super.backupCloneAttribute(attributeValue, clone, backup, unitOfWork);
68         } else {
69             return buildBackupClone((IndirectContainer)attributeValue);
70         }
71     }
72
73     /**
74      * INTERNAL:
75      * Return a backup clone of a clone container that has not been
76      * read from the database yet.
77      * This is used by the indirection policy to hook together a UOW
78      * clone with its backup clone - only when the clone (the working
79      * copy returned to the user) instantiates its contents from the
80      * database will these contents be copied to the backup clone.
81      */

82     protected Object JavaDoc buildBackupClone(IndirectContainer container) {
83         UnitOfWorkValueHolder containerValueHolder = (UnitOfWorkValueHolder)container.getValueHolder();
84         // CR#2852176 Use a BackupValueHolder to handle replacing of the original.
85
BackupValueHolder backupValueHolder = new BackupValueHolder(containerValueHolder);
86         containerValueHolder.setBackupValueHolder(backupValueHolder);
87         return this.buildIndirectContainer(backupValueHolder);
88     }
89
90     /**
91      * Construct and return an instance of the specified
92      * indirect container class.
93      */

94     protected IndirectContainer buildIndirectContainer() {
95         //3732
96
if (defaultContainerSize != null) {
97             return (IndirectContainer)getContainerPolicy().containerInstance(getDefaultContainerSize());
98         } else {
99             return (IndirectContainer)getContainerPolicy().containerInstance();
100         }
101     }
102
103     /**
104      * Return a new IndirectContainer with the specified value holder.
105      */

106     protected Object JavaDoc buildIndirectContainer(ValueHolderInterface valueHolder) {
107         IndirectContainer result = buildIndirectContainer();
108         result.setValueHolder(valueHolder);
109         return result;
110     }
111
112     /**
113      * Return a clone of the attribute.
114      * @param buildDirectlyFromRow indicates that we are building the clone directly
115      * from a row as opposed to building the original from the row, putting it in
116      * the shared cache, and then cloning the original.
117      */

118     public Object JavaDoc cloneAttribute(Object JavaDoc attributeValue, Object JavaDoc original, Object JavaDoc clone, UnitOfWorkImpl unitOfWork, boolean buildDirectlyFromRow) {
119         ValueHolderInterface valueHolder = null;
120         Object JavaDoc container = null;
121         if (attributeValue instanceof IndirectContainer) {
122             valueHolder = ((IndirectContainer)attributeValue).getValueHolder();
123         }
124         if (!buildDirectlyFromRow && unitOfWork.isOriginalNewObject(original)) {
125             // CR#3156435 Throw a meaningful exception if a serialized/dead value holder is detected.
126
// This can occur if an existing serialized object is attempt to be registered as new.
127
if ((valueHolder instanceof DatabaseValueHolder)
128                     && (! ((DatabaseValueHolder) valueHolder).isInstantiated())
129                     && (((DatabaseValueHolder) valueHolder).getSession() == null)
130                     && (! ((DatabaseValueHolder) valueHolder).isSerializedRemoteUnitOfWorkValueHolder())) {
131                 throw DescriptorException.attemptToRegisterDeadIndirection(original, getMapping());
132             }
133             if (getMapping().getRelationshipPartner() == null) {
134                 container = getMapping().buildCloneForPartObject(attributeValue, original, clone, unitOfWork, false);
135             } else {
136                 if (!(attributeValue instanceof IndirectContainer)) {
137                     valueHolder = new ValueHolder(attributeValue);
138                 }
139                 AbstractRecord row = null;
140                 if (valueHolder instanceof DatabaseValueHolder) {
141                     row = ((DatabaseValueHolder)valueHolder).getRow();
142                 }
143
144                 //If a new object is being cloned then we must build a new UOWValueHolder
145
// this is so that new clones can also have their relationships managed
146
// here the code instantiates the valueholder in a privledged manner because a
147
// UOWValueHolder will assume the objects in the collection are existing if the valueholder
148
// Goes through it's own instantiation process.
149
UnitOfWorkValueHolder newValueHolder = this.getMapping().createUnitOfWorkValueHolder(valueHolder, original, clone, row, unitOfWork, buildDirectlyFromRow);
150                 container = buildIndirectContainer(newValueHolder);
151                 Object JavaDoc cloneCollection = getMapping().buildCloneForPartObject(attributeValue, original, clone, unitOfWork, false);
152                 newValueHolder.privilegedSetValue(cloneCollection);
153                 newValueHolder.setInstantiated();
154             }
155         } else {
156             if (!(attributeValue instanceof IndirectContainer)) {
157                 valueHolder = new ValueHolder(attributeValue);
158             }
159             AbstractRecord row = null;
160             if (valueHolder instanceof DatabaseValueHolder) {
161                 row = ((DatabaseValueHolder)valueHolder).getRow();
162             }
163             container = buildIndirectContainer(getMapping().createUnitOfWorkValueHolder(valueHolder, original, clone, row, unitOfWork, buildDirectlyFromRow));
164         }
165         return container;
166     }
167
168     /**
169      * INTERNAL:
170      * Return whether the container policy is valid for the indirection policy.
171      * In this case, the container policy MUST be configured
172      * for an IndirectContainer.
173      */

174     protected boolean containerPolicyIsValid() {
175         if (Helper.classImplementsInterface(this.getContainerClass(), ClassConstants.IndirectContainer_Class)) {
176             return true;
177         }
178         return false;
179     }
180
181     /**
182      * INTERNAL:
183      * Return the primary key for the reference object (i.e. the object
184      * object referenced by domainObject and specified by mapping).
185      * This key will be used by a RemoteValueHolder.
186      * OneToOneMappings should not be using transparent direction.
187      */

188     public Vector extractPrimaryKeyForReferenceObject(Object JavaDoc referenceObject, AbstractSession session) {
189         throw DescriptorException.invalidUseOfTransparentIndirection(this.getMapping());
190     }
191
192     /**
193      * INTERNAL:
194      * Return the reference row for the reference object.
195      * This allows the new row to be built without instantiating
196      * the reference object.
197      * Return null if the object has already been instantiated.
198      */

199     public AbstractRecord extractReferenceRow(Object JavaDoc referenceObject) {
200         if (this.objectIsInstantiated(referenceObject)) {
201             return null;
202         } else {
203             return ((DatabaseValueHolder)((IndirectContainer)referenceObject).getValueHolder()).getRow();
204         }
205     }
206
207     /**
208      * INTERNAL:
209      * Return the container class for the mapping.
210      */

211     protected Class JavaDoc getContainerClass() {
212         return this.getContainerPolicy().getContainerClass();
213     }
214
215     /**
216      * INTERNAL:
217      * Return the container policy for the mapping.
218      */

219     protected ContainerPolicy getContainerPolicy() {
220         return this.getCollectionMapping().getContainerPolicy();
221     }
222
223     /**
224      * INTERNAL:
225      * Return the the size to of container to create. Default to using default constructor.
226      */

227     protected static int getDefaultContainerSize() {
228         //3732
229
return defaultContainerSize.intValue();
230     }
231
232     /**
233      * INTERNAL:
234      * Return the original indirection object for a unit of work indirection object.
235      */

236     public Object JavaDoc getOriginalIndirectionObject(Object JavaDoc unitOfWorkIndirectionObject, AbstractSession session) {
237         IndirectContainer container = (IndirectContainer)unitOfWorkIndirectionObject;
238         if (container.getValueHolder() instanceof UnitOfWorkValueHolder) {
239             ValueHolderInterface valueHolder = ((UnitOfWorkValueHolder)container.getValueHolder()).getWrappedValueHolder();
240             return buildIndirectContainer(valueHolder);
241         } else {
242             return container;
243         }
244     }
245
246     /**
247      * INTERNAL:
248      * Return the "real" attribute value, as opposed to any wrapper.
249      * This will trigger the wrapper to instantiate the value.
250      */

251     public Object JavaDoc getRealAttributeValueFromObject(Object JavaDoc object) {
252         this.getContainerPolicy().sizeFor(object);// forgive me for this hack: but we have to do something to trigger the database read
253
return object;
254     }
255
256     /**
257      * INTERNAL:
258      * Set the value of the appropriate attribute of target to attributeValue.
259      * If the Target has yet to be instantiated then we need to instantiate the target to ensure that
260      * the backup clone is instantiated for comparison.
261      */

262     public void setRealAttributeValueInObject(Object JavaDoc target, Object JavaDoc attributeValue) {
263
264         /*
265            Bug 3573808 - do NOT trigger the valueholder; SPECj benchmark
266            deadlocks in this method.
267            Re-ran the original testcase IndirectContainerTestDatabase
268             testMergeCloneWithSerializedTransparentIndirection
269            and it passes without triggering the valueholder. MWN
270
271         //cr 3788
272         // Trigger the valueholder when setting the value in an object
273         Object object = this.getMapping().getAttributeValueFromObject(target);
274         if (object instanceof IndirectContainer){
275             ((IndirectContainer)object).getValueHolder().getValue();
276         }
277         */

278         super.setRealAttributeValueInObject(target, attributeValue);
279     }
280
281     /**
282      * INTERNAL:
283      * Iterate over the specified attribute value.
284      */

285     public void iterateOnAttributeValue(DescriptorIterator iterator, Object JavaDoc attributeValue) {
286         if (attributeValue instanceof IndirectContainer) {
287             iterator.iterateIndirectContainerForMapping((IndirectContainer)attributeValue, this.getMapping());
288         } else {// it must be a "real" collection
289
super.iterateOnAttributeValue(iterator, attributeValue);
290         }
291     }
292
293     /**
294      * INTERNAL:
295      * Return the null value of the appropriate attribute. That is, the
296      * field from the database is NULL, return what should be
297      * placed in the object's attribute as a result.
298      * OneToOneMappings should not be using transparent direction.
299      */

300     public Object JavaDoc nullValueFromRow() {
301         throw DescriptorException.invalidUseOfTransparentIndirection(this.getMapping());
302     }
303
304     /**
305      * INTERNAL:
306      * Return whether the specified object is instantiated.
307      */

308     public boolean objectIsInstantiated(Object JavaDoc object) {
309         if (object instanceof IndirectContainer) {
310             return ((IndirectContainer)object).isInstantiated();
311         } else {
312             return true;// it must be a "real" collection
313
}
314     }
315
316     /**
317      * ADVANCED:
318      * Set the size to of container to create. Default to using default constructor.
319      */

320     public static void setDefaultContainerSize(int defaultSize) {
321         //3732
322
defaultContainerSize = new Integer JavaDoc(defaultSize);
323     }
324
325     /**
326      * INTERNAL:
327      * Return whether the type is appropriate for the indirection policy.
328      * In this case, the attribute type MUST be
329      * compatible with the one specified by the ContainerPolicy
330      * (i.e. either the container policy class is a subclass of the
331      * declared type [jdk1.1] or the container policy class implements
332      * the declared interface [jdk1.2]).
333      */

334     protected boolean typeIsValid(Class JavaDoc declaredType) {
335         if (Helper.classIsSubclass(this.getContainerClass(), declaredType)) {
336             return true;
337         }
338         if (Helper.classImplementsInterface(this.getContainerClass(), declaredType)) {
339             return true;
340         }
341         return false;
342     }
343
344     /**
345      * INTERNAL:
346      * Return whether the indirection policy uses transparent indirection.
347      */

348     public boolean usesTransparentIndirection(){
349         return true;
350     }
351
352     /**
353      * INTERNAL:
354      * Verify that the value of the attribute within an instantiated object
355      * is of the appropriate type for the indirection policy.
356      * In this case, the attribute must be non-null and it must be at least a
357      * subclass or implementor of the container type.
358      * If the value is null return a new indirection object to be used for the attribute.
359      */

360     public Object JavaDoc validateAttributeOfInstantiatedObject(Object JavaDoc attributeValue) {
361         // PERF: If the value is null, create a new value holder instance for the attribute value,
362
// this allows for indirection attributes to not be instantiated in the constructor as they
363
// are typically replaced when reading or cloning so is very inefficent to initialize.
364
if (attributeValue == null) {
365             return buildIndirectContainer();
366         }
367         if (!(this.getContainerPolicy().isValidContainer(attributeValue))) {
368             throw DescriptorException.indirectContainerInstantiationMismatch(attributeValue, this.getMapping());
369         }
370         return attributeValue;
371     }
372
373     /**
374      * INTERNAL:
375      * Verify that the container policy is compatible with the
376      * indirection policy. If it is incorrect, add an exception to the
377      * integrity checker.
378      */

379     public void validateContainerPolicy(IntegrityChecker checker) throws DescriptorException {
380         super.validateContainerPolicy(checker);
381         if (!this.containerPolicyIsValid()) {
382             checker.handleError(DescriptorException.invalidContainerPolicyWithTransparentIndirection(this.getMapping(), this.getContainerPolicy()));
383         }
384
385         // Bug 2618982
386
if (getContainerPolicy().isMapPolicy() && ((((ForeignReferenceMapping)getMapping()).getRelationshipPartnerAttributeName() != null) || (getMapping().getRelationshipPartner() != null))) {
387             checker.handleError(DescriptorException.unsupportedTypeForBidirectionalRelationshipMaintenance(this.getMapping(), this.getContainerPolicy()));
388         }
389     }
390
391     /**
392      * INTERNAL:
393      * Verify that attributeType is correct for the
394      * indirection policy. If it is incorrect, add an exception to the
395      * integrity checker.
396      * In this case, the attribute type MUST be
397      * compatible with the one specified by the ContainerPolicy.
398      */

399     public void validateDeclaredAttributeType(Class JavaDoc attributeType, IntegrityChecker checker) throws DescriptorException {
400         super.validateDeclaredAttributeType(attributeType, checker);
401         if (!this.typeIsValid(attributeType)) {
402             checker.handleError(DescriptorException.attributeAndMappingWithTransparentIndirectionMismatch(this.getMapping(), this.validTypeName()));
403         }
404     }
405
406     /**
407      * INTERNAL:
408      * Verify that getter returnType is correct for the
409      * indirection policy. If it is incorrect, add an exception
410      * to the integrity checker.
411      * In this case, the attribute type MUST be
412      * compatible with the one specified by the ContainerPolicy.
413      */

414     public void validateGetMethodReturnType(Class JavaDoc returnType, IntegrityChecker checker) throws DescriptorException {
415         super.validateGetMethodReturnType(returnType, checker);
416         if (!this.typeIsValid(returnType)) {
417             checker.handleError(DescriptorException.returnAndMappingWithTransparentIndirectionMismatch(this.getMapping(), this.validTypeName()));
418         }
419     }
420
421     /**
422      * INTERNAL:
423      * Verify that setter parameterType is correct for the
424      * indirection policy. If it is incorrect, add an exception
425      * to the integrity checker.
426      * In this case, the attribute type MUST be
427      * compatible with the one specified by the ContainerPolicy.
428      */

429     public void validateSetMethodParameterType(Class JavaDoc parameterType, IntegrityChecker checker) throws DescriptorException {
430         super.validateSetMethodParameterType(parameterType, checker);
431         if (!this.typeIsValid(parameterType)) {
432             checker.handleError(DescriptorException.parameterAndMappingWithTransparentIndirectionMismatch(this.getMapping(), this.validTypeName()));
433         }
434     }
435
436     /**
437      * INTERNAL:
438      * Return the type that is appropriate for the indirection policy.
439      */

440     protected String JavaDoc validTypeName() {
441         return Helper.getShortClassName(this.getContainerClass());
442     }
443
444     /**
445      * INTERNAL:
446      * Return the value to be stored in the object's attribute.
447      * This value is determined by invoking the appropriate
448      * method on the object and passing it the row and session.
449      * TransformationMappings should not be using transparent direction.
450      */

451     public Object JavaDoc valueFromMethod(Object JavaDoc object, AbstractRecord row, AbstractSession session) {
452         throw DescriptorException.invalidUseOfTransparentIndirection(this.getMapping());
453     }
454
455     /**
456      * INTERNAL:
457      * Return the value to be stored in the object's attribute.
458      * This value is determined by the query.
459      * In this case, wrap the query in an IndirectContainer for later invocation.
460      */

461     public Object JavaDoc valueFromQuery(ReadQuery query, AbstractRecord row, AbstractSession session) {
462         return this.buildIndirectContainer(new QueryBasedValueHolder(query, row, session));
463     }
464
465     /**
466      * INTERNAL:
467      * A combination of valueFromQuery and valueFromRow(object).
468      * Sometimes the attribute is known (joining) but we still need to hang on
469      * to the query (pessimistic locking).
470      */

471     public Object JavaDoc valueFromQuery(ReadQuery query, AbstractRecord row, Object JavaDoc object, AbstractSession session) {
472         return valueFromQuery(query, row, session);
473     }
474
475     /**
476      * INTERNAL:
477      * Return the value to be stored in the object's attribute.
478      * This allows wrapping of the real value, none is required for transparent.
479      */

480     public Object JavaDoc valueFromRow(Object JavaDoc object) {
481         return object;
482     }
483 }
484
Popular Tags