FileDocCategorySizeDatePackage
TransparentIndirectionPolicy.javaAPI DocGlassfish v2 API21429Tue May 22 16:54:36 BST 2007oracle.toplink.essentials.internal.indirection

TransparentIndirectionPolicy

public class TransparentIndirectionPolicy extends IndirectionPolicy

Purpose

: TransparentIndirectionPolicy implements the behavior necessary for a a CollectionMapping to use IndirectContainers to delay the reading of objects from the database until they are actually needed.
see
CollectionMapping
see
IndirectContainer
author
Big Country
since
TOPLink/Java 2.5

Fields Summary
protected static Integer
defaultContainerSize
Constructors Summary
public TransparentIndirectionPolicy()
INTERNAL: Construct a new indirection policy.

        super();
    
Methods Summary
public java.lang.ObjectbackupCloneAttribute(java.lang.Object attributeValue, java.lang.Object clone, java.lang.Object backup, oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl unitOfWork)
INTERNAL: Return a backup clone of the attribute.

        // delay instantiation until absolutely necessary
        if ((!(attributeValue instanceof IndirectContainer)) || objectIsInstantiated(attributeValue)) {
            return super.backupCloneAttribute(attributeValue, clone, backup, unitOfWork);
        } else {
            return buildBackupClone((IndirectContainer)attributeValue);
        }
    
protected java.lang.ObjectbuildBackupClone(oracle.toplink.essentials.indirection.IndirectContainer container)
INTERNAL: Return a backup clone of a clone container that has not been read from the database yet. This is used by the indirection policy to hook together a UOW clone with its backup clone - only when the clone (the working copy returned to the user) instantiates its contents from the database will these contents be copied to the backup clone.

        UnitOfWorkValueHolder containerValueHolder = (UnitOfWorkValueHolder)container.getValueHolder();
        // CR#2852176 Use a BackupValueHolder to handle replacing of the original.
        BackupValueHolder backupValueHolder = new BackupValueHolder(containerValueHolder);
        containerValueHolder.setBackupValueHolder(backupValueHolder);
        return this.buildIndirectContainer(backupValueHolder);
    
protected oracle.toplink.essentials.indirection.IndirectContainerbuildIndirectContainer()
Construct and return an instance of the specified indirect container class.

        //3732
        if (defaultContainerSize != null) {
            return (IndirectContainer)getContainerPolicy().containerInstance(getDefaultContainerSize());
        } else {
            return (IndirectContainer)getContainerPolicy().containerInstance();
        }
    
protected java.lang.ObjectbuildIndirectContainer(oracle.toplink.essentials.indirection.ValueHolderInterface valueHolder)
Return a new IndirectContainer with the specified value holder.

        IndirectContainer result = buildIndirectContainer();
        result.setValueHolder(valueHolder);
        return result;
    
public java.lang.ObjectcloneAttribute(java.lang.Object attributeValue, java.lang.Object original, java.lang.Object clone, oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl unitOfWork, boolean buildDirectlyFromRow)
Return a clone of the attribute.

param
buildDirectlyFromRow indicates that we are building the clone directly from a row as opposed to building the original from the row, putting it in the shared cache, and then cloning the original.

        ValueHolderInterface valueHolder = null;
        Object container = null;
        if (attributeValue instanceof IndirectContainer) {
            valueHolder = ((IndirectContainer)attributeValue).getValueHolder();
        }
        if (!buildDirectlyFromRow && unitOfWork.isOriginalNewObject(original)) {
            // CR#3156435 Throw a meaningful exception if a serialized/dead value holder is detected.
            // This can occur if an existing serialized object is attempt to be registered as new.
            if ((valueHolder instanceof DatabaseValueHolder)
                    && (! ((DatabaseValueHolder) valueHolder).isInstantiated())
                    && (((DatabaseValueHolder) valueHolder).getSession() == null)
                    && (! ((DatabaseValueHolder) valueHolder).isSerializedRemoteUnitOfWorkValueHolder())) {
                throw DescriptorException.attemptToRegisterDeadIndirection(original, getMapping());
            }
            if (getMapping().getRelationshipPartner() == null) {
                container = getMapping().buildCloneForPartObject(attributeValue, original, clone, unitOfWork, false);
            } else {
                if (!(attributeValue instanceof IndirectContainer)) {
                    valueHolder = new ValueHolder(attributeValue);
                }
                AbstractRecord row = null;
                if (valueHolder instanceof DatabaseValueHolder) {
                    row = ((DatabaseValueHolder)valueHolder).getRow();
                }

                //If a new object is being cloned then we must build a new UOWValueHolder
                //  this is so that new clones can also have their relationships managed
                // here the code instantiates the valueholder in a privledged manner because a
                // UOWValueHolder will assume the objects in the collection are existing if the valueholder
                //  Goes through it's own instantiation process.
                UnitOfWorkValueHolder newValueHolder = this.getMapping().createUnitOfWorkValueHolder(valueHolder, original, clone, row, unitOfWork, buildDirectlyFromRow);
                container = buildIndirectContainer(newValueHolder);
                Object cloneCollection = getMapping().buildCloneForPartObject(attributeValue, original, clone, unitOfWork, false);
                newValueHolder.privilegedSetValue(cloneCollection);
                newValueHolder.setInstantiated();
            }
        } else {
            if (!(attributeValue instanceof IndirectContainer)) {
                valueHolder = new ValueHolder(attributeValue);
            }
            AbstractRecord row = null;
            if (valueHolder instanceof DatabaseValueHolder) {
                row = ((DatabaseValueHolder)valueHolder).getRow();
            }
            container = buildIndirectContainer(getMapping().createUnitOfWorkValueHolder(valueHolder, original, clone, row, unitOfWork, buildDirectlyFromRow));
        }
        return container;
    
protected booleancontainerPolicyIsValid()
INTERNAL: Return whether the container policy is valid for the indirection policy. In this case, the container policy MUST be configured for an IndirectContainer.

        if (Helper.classImplementsInterface(this.getContainerClass(), ClassConstants.IndirectContainer_Class)) {
            return true;
        }
        return false;
    
public java.util.VectorextractPrimaryKeyForReferenceObject(java.lang.Object referenceObject, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Return the primary key for the reference object (i.e. the object object referenced by domainObject and specified by mapping). This key will be used by a RemoteValueHolder. OneToOneMappings should not be using transparent direction.

        throw DescriptorException.invalidUseOfTransparentIndirection(this.getMapping());
    
public oracle.toplink.essentials.internal.sessions.AbstractRecordextractReferenceRow(java.lang.Object referenceObject)
INTERNAL: Return the reference row for the reference object. This allows the new row to be built without instantiating the reference object. Return null if the object has already been instantiated.

        if (this.objectIsInstantiated(referenceObject)) {
            return null;
        } else {
            return ((DatabaseValueHolder)((IndirectContainer)referenceObject).getValueHolder()).getRow();
        }
    
protected java.lang.ClassgetContainerClass()
INTERNAL: Return the container class for the mapping.

        return this.getContainerPolicy().getContainerClass();
    
protected oracle.toplink.essentials.internal.queryframework.ContainerPolicygetContainerPolicy()
INTERNAL: Return the container policy for the mapping.

        return this.getCollectionMapping().getContainerPolicy();
    
protected static intgetDefaultContainerSize()
INTERNAL: Return the the size to of container to create. Default to using default constructor.

        //3732
        return defaultContainerSize.intValue();
    
public java.lang.ObjectgetOriginalIndirectionObject(java.lang.Object unitOfWorkIndirectionObject, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Return the original indirection object for a unit of work indirection object.

        IndirectContainer container = (IndirectContainer)unitOfWorkIndirectionObject;
        if (container.getValueHolder() instanceof UnitOfWorkValueHolder) {
            ValueHolderInterface valueHolder = ((UnitOfWorkValueHolder)container.getValueHolder()).getWrappedValueHolder();
            return buildIndirectContainer(valueHolder);
        } else {
            return container;
        }
    
public java.lang.ObjectgetRealAttributeValueFromObject(java.lang.Object object, java.lang.Object attribute)
INTERNAL: Return the "real" attribute value, as opposed to any wrapper. This will trigger the wrapper to instantiate the value.

        this.getContainerPolicy().sizeFor(attribute);// forgive me for this hack: but we have to do something to trigger the database read
        return attribute;
    
public voiditerateOnAttributeValue(oracle.toplink.essentials.internal.descriptors.DescriptorIterator iterator, java.lang.Object attributeValue)
INTERNAL: Iterate over the specified attribute value.

        if (attributeValue instanceof IndirectContainer) {
            iterator.iterateIndirectContainerForMapping((IndirectContainer)attributeValue, this.getMapping());
        } else {// it must be a "real" collection
            super.iterateOnAttributeValue(iterator, attributeValue);
        }
    
public java.lang.ObjectnullValueFromRow()
INTERNAL: Return the null value of the appropriate attribute. That is, the field from the database is NULL, return what should be placed in the object's attribute as a result. OneToOneMappings should not be using transparent direction.

        throw DescriptorException.invalidUseOfTransparentIndirection(this.getMapping());
    
public booleanobjectIsInstantiated(java.lang.Object object)
INTERNAL: Return whether the specified object is instantiated.

        if (object instanceof IndirectContainer) {
            return ((IndirectContainer)object).isInstantiated();
        } else {
            return true;// it must be a "real" collection
        }
    
public static voidsetDefaultContainerSize(int defaultSize)
ADVANCED: Set the size to of container to create. Default to using default constructor.

        //3732
        defaultContainerSize = new Integer(defaultSize);
    
public voidsetRealAttributeValueInObject(java.lang.Object target, java.lang.Object attributeValue)
INTERNAL: Set the value of the appropriate attribute of target to attributeValue. If the Target has yet to be instantiated then we need to instantiate the target to ensure that the backup clone is instantiated for comparison.


        /*
           Bug 3573808 - do NOT trigger the valueholder; SPECj benchmark
           deadlocks in this method.
           Re-ran the original testcase IndirectContainerTestDatabase
            testMergeCloneWithSerializedTransparentIndirection
           and it passes without triggering the valueholder. MWN

        //cr 3788
        // Trigger the valueholder when setting the value in an object
        Object object = this.getMapping().getAttributeValueFromObject(target);
        if (object instanceof IndirectContainer){
            ((IndirectContainer)object).getValueHolder().getValue();
        }
        */
        super.setRealAttributeValueInObject(target, attributeValue);
    
protected booleantypeIsValid(java.lang.Class declaredType)
INTERNAL: Return whether the type is appropriate for the indirection policy. In this case, the attribute type MUST be compatible with the one specified by the ContainerPolicy (i.e. either the container policy class is a subclass of the declared type [jdk1.1] or the container policy class implements the declared interface [jdk1.2]).

        if (Helper.classIsSubclass(this.getContainerClass(), declaredType)) {
            return true;
        }
        if (Helper.classImplementsInterface(this.getContainerClass(), declaredType)) {
            return true;
        }
        return false;
    
public booleanusesTransparentIndirection()
INTERNAL: Return whether the indirection policy uses transparent indirection.

        return true;
    
protected java.lang.StringvalidTypeName()
INTERNAL: Return the type that is appropriate for the indirection policy.

        return Helper.getShortClassName(this.getContainerClass());
    
public java.lang.ObjectvalidateAttributeOfInstantiatedObject(java.lang.Object attributeValue)
INTERNAL: Verify that the value of the attribute within an instantiated object is of the appropriate type for the indirection policy. In this case, the attribute must be non-null and it must be at least a subclass or implementor of the container type. If the value is null return a new indirection object to be used for the attribute.

        // PERF: If the value is null, create a new value holder instance for the attribute value,
        // this allows for indirection attributes to not be instantiated in the constructor as they
        // are typically replaced when reading or cloning so is very inefficent to initialize.
        if (attributeValue == null) {
            return buildIndirectContainer();
        }
        if (!(this.getContainerPolicy().isValidContainer(attributeValue))) {
            throw DescriptorException.indirectContainerInstantiationMismatch(attributeValue, this.getMapping());
        }
        return attributeValue;
    
public voidvalidateContainerPolicy(oracle.toplink.essentials.exceptions.IntegrityChecker checker)
INTERNAL: Verify that the container policy is compatible with the indirection policy. If it is incorrect, add an exception to the integrity checker.

        super.validateContainerPolicy(checker);
        if (!this.containerPolicyIsValid()) {
            checker.handleError(DescriptorException.invalidContainerPolicyWithTransparentIndirection(this.getMapping(), this.getContainerPolicy()));
        }

        // Bug 2618982
        if (getContainerPolicy().isMapPolicy() && ((((ForeignReferenceMapping)getMapping()).getRelationshipPartnerAttributeName() != null) || (getMapping().getRelationshipPartner() != null))) {
            checker.handleError(DescriptorException.unsupportedTypeForBidirectionalRelationshipMaintenance(this.getMapping(), this.getContainerPolicy()));
        }
    
public voidvalidateDeclaredAttributeType(java.lang.Class attributeType, oracle.toplink.essentials.exceptions.IntegrityChecker checker)
INTERNAL: Verify that attributeType is correct for the indirection policy. If it is incorrect, add an exception to the integrity checker. In this case, the attribute type MUST be compatible with the one specified by the ContainerPolicy.

        super.validateDeclaredAttributeType(attributeType, checker);
        if (!this.typeIsValid(attributeType)) {
            checker.handleError(DescriptorException.attributeAndMappingWithTransparentIndirectionMismatch(this.getMapping(), this.validTypeName()));
        }
    
public voidvalidateGetMethodReturnType(java.lang.Class returnType, oracle.toplink.essentials.exceptions.IntegrityChecker checker)
INTERNAL: Verify that getter returnType is correct for the indirection policy. If it is incorrect, add an exception to the integrity checker. In this case, the attribute type MUST be compatible with the one specified by the ContainerPolicy.

        super.validateGetMethodReturnType(returnType, checker);
        if (!this.typeIsValid(returnType)) {
            checker.handleError(DescriptorException.returnAndMappingWithTransparentIndirectionMismatch(this.getMapping(), this.validTypeName()));
        }
    
public voidvalidateSetMethodParameterType(java.lang.Class parameterType, oracle.toplink.essentials.exceptions.IntegrityChecker checker)
INTERNAL: Verify that setter parameterType is correct for the indirection policy. If it is incorrect, add an exception to the integrity checker. In this case, the attribute type MUST be compatible with the one specified by the ContainerPolicy.

        super.validateSetMethodParameterType(parameterType, checker);
        if (!this.typeIsValid(parameterType)) {
            checker.handleError(DescriptorException.parameterAndMappingWithTransparentIndirectionMismatch(this.getMapping(), this.validTypeName()));
        }
    
public java.lang.ObjectvalueFromMethod(java.lang.Object object, oracle.toplink.essentials.internal.sessions.AbstractRecord row, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Return the value to be stored in the object's attribute. This value is determined by invoking the appropriate method on the object and passing it the row and session. TransformationMappings should not be using transparent direction.

        throw DescriptorException.invalidUseOfTransparentIndirection(this.getMapping());
    
public java.lang.ObjectvalueFromQuery(oracle.toplink.essentials.queryframework.ReadQuery query, oracle.toplink.essentials.internal.sessions.AbstractRecord row, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Return the value to be stored in the object's attribute. This value is determined by the query. In this case, wrap the query in an IndirectContainer for later invocation.

        return this.buildIndirectContainer(new QueryBasedValueHolder(query, row, session));
    
public java.lang.ObjectvalueFromQuery(oracle.toplink.essentials.queryframework.ReadQuery query, oracle.toplink.essentials.internal.sessions.AbstractRecord row, java.lang.Object object, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: A combination of valueFromQuery and valueFromRow(object). Sometimes the attribute is known (joining) but we still need to hang on to the query (pessimistic locking).

        return valueFromQuery(query, row, session);
    
public java.lang.ObjectvalueFromRow(java.lang.Object object)
INTERNAL: Return the value to be stored in the object's attribute. This allows wrapping of the real value, none is required for transparent.

        return object;