FileDocCategorySizeDatePackage
ObjectBuildingQuery.javaAPI DocGlassfish v2 API23152Tue May 22 16:54:50 BST 2007oracle.toplink.essentials.queryframework

ObjectBuildingQuery

public abstract class ObjectBuildingQuery extends ReadQuery

Purpose: Abstract class for all read queries that build objects and potentially manipulate the TopLink cache.

Description: Contains common behavior for all read queries building objects.

author
Gordon Yorke
since
TopLink Essentials

Fields Summary
protected Class
referenceClass
The class of the target objects to be read from the database.
protected String
referenceClassName
protected boolean
shouldRefreshIdentityMapResult
Allows for the resulting objects to be refresh with the data from the database.
protected boolean
shouldRefreshRemoteIdentityMapResult
protected boolean
shouldRegisterResultsInUnitOfWork
INTERNAL: for bug 2612601 allow ability not to register results in UOW.
protected boolean
shouldProcessResultsInUnitOfWork
CMP only. Allow users to configure whether finder should be executed in a uow or not.
protected ForUpdateClause
lockingClause
Used for pessimistic locking.
public static final short
NO_LOCK
public static final short
LOCK
public static final short
LOCK_NOWAIT
public static final short
DEFAULT_LOCK_MODE
protected boolean
isPrePrepared
protected long
executionTime
Used to set the read time on objects that use this query. Should be set to the time the query returned from the database.
protected boolean
shouldUseExclusiveConnection
Added for Exclusive Connection (VPD) support see accessor for information
public static final String
LOCK_RESULT_PROPERTY
INTERNAL: This is the key for accessing unregistered and locked result in the query's properties. The uow and QueryBaseValueHolder use this property to record amd to retreive the result respectively.
protected boolean
wasDefaultLockMode
PERF: Store if the query originally used the default lock mode.
Constructors Summary
public ObjectBuildingQuery()
INTERNAL: Initialize the state of the query

    
                
      
        this.shouldRefreshIdentityMapResult = false;
    
Methods Summary
public voidconvertClassNamesToClasses(java.lang.ClassLoader classLoader)
INTERNAL: Convert all the class-name-based settings in this query to actual class-based settings. This method is used when converting a project that has been built with class names to a project with classes.

param
classLoader

        super.convertClassNamesToClasses(classLoader);
        Class referenceClass = null;
        try{
            if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
                try {
                    referenceClass = (Class)AccessController.doPrivileged(new PrivilegedClassForName(getReferenceClassName(), true, classLoader));
                } catch (PrivilegedActionException exception) {
                    throw ValidationException.classNotFoundWhileConvertingClassNames(getReferenceClassName(), exception.getException());
                }
            } else {
                referenceClass = oracle.toplink.essentials.internal.security.PrivilegedAccessHelper.getClassForName(getReferenceClassName(), true, classLoader);
            }
        } catch (ClassNotFoundException exc){
            throw ValidationException.classNotFoundWhileConvertingClassNames(getReferenceClassName(), exc);
        }
        setReferenceClass(referenceClass);
    
public voiddontRefreshIdentityMapResult()
PUBLIC: When unset means perform read normally and dont do refresh.

        setShouldRefreshIdentityMapResult(false);
    
public voiddontRefreshRemoteIdentityMapResult()
PUBLIC: When unset means perform read normally and dont do refresh.

        setShouldRefreshRemoteIdentityMapResult(false);
    
public java.util.ListgetDataResults()
INTERNAL: Return all of the rows fetched by the query, used for 1-m joining.

        return null;
    
public longgetExecutionTime()
INTERNAL: Return the time this query actually went to the database

        return executionTime;
    
public oracle.toplink.essentials.queryframework.FetchGroupgetFetchGroup()
Return the fetch group set in the query. If a fetch group is not explicitly set in the query, default fetch group optionally defined in the decsiptor would be used, unless the user explicitly calls query.setShouldUseDefaultFetchGroup(false).

        return null;
    
public shortgetLockMode()
PUBLIC: Return the current locking mode.

        if (lockingClause == null) {
            return DEFAULT_LOCK_MODE;
        } else {
            return lockingClause.getLockMode();
        }
    
public java.lang.ClassgetReferenceClass()
PUBLIC: Return the reference class of the query.

        return referenceClass;
    
public java.lang.StringgetReferenceClassName()
INTERNAL: Return the reference class of the query.

        if ((referenceClassName == null) && (referenceClass != null)) {
            referenceClassName = referenceClass.getName();
        }
        return referenceClassName;
    
public booleanhasPartialAttributeExpressions()
INTERNAL: Return if partial attributes.

        return false;
    
public booleanisAttributeJoined(oracle.toplink.essentials.descriptors.ClassDescriptor mappingDescriptor, java.lang.String attributeName)
INTERNAL: Return if the attribute is specified for joining.

        return false;
    
public booleanisClonePessimisticLocked(java.lang.Object clone, oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl uow)
INTERNAL: Helper method that checks if clone has been locked with uow.

        return false;
    
public booleanisDefaultLock()
INTERNAL: Helper method to determine the default mode. If true and quey has a pessimistic locking policy, locking will be configured according to the pessimistic locking policy.

        return (lockingClause == null);
    
public booleanisLockQuery()
PUBLIC: Answers if the query lock mode is known to be LOCK or LOCK_NOWAIT. In the case of DEFAULT_LOCK_MODE and the query reference class being a CMP entity bean, at execution time LOCK, LOCK_NOWAIT, or NO_LOCK will be decided.

If a single joined attribute was configured for pessimistic locking then this will return true (after first execution) as the SQL contained a FOR UPDATE OF clause.

        return getLockMode() > NO_LOCK;
    
public booleanisObjectBuildingQuery()
PUBLIC: Return if this is an object building query.

        return true;
    
protected booleanisRegisteringResults()
INTERNAL: Answers if we are executing through a UnitOfWork and registering results. This is only ever false if using the conforming without registering feature.

        return ((shouldRegisterResultsInUnitOfWork() && getDescriptor().shouldRegisterResultsInUnitOfWork()) || isLockQuery());
    
public voidrecordCloneForPessimisticLocking(java.lang.Object clone, oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl uow)
INTERNAL: Helper method that records clone with uow if query is pessimistic locking.

        if ((isLockQuery()) && lockingClause.isReferenceClassLocked()) {
            uow.addPessimisticLockedClone(clone);
        }
    
public voidrefreshIdentityMapResult()
PUBLIC: Refresh the attributes of the object(s) resulting from the query. If cascading is used the private parts of the objects will also be refreshed.

        setShouldRefreshIdentityMapResult(true);
    
public voidrefreshRemoteIdentityMapResult()
PUBLIC: Refresh the attributes of the object(s) resulting from the query. If cascading is used the private parts of the objects will also be refreshed.

        setShouldRefreshRemoteIdentityMapResult(true);
    
public java.lang.ObjectregisterIndividualResult(java.lang.Object result, oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl unitOfWork, boolean buildDirectlyFromRows, oracle.toplink.essentials.internal.queryframework.JoinedAttributeManager joinManager)
INTERNAL: Constructs the final (registered) object for every individual object queried via a UnitOfWork.

Called for every object in a read all, the object in a read object, and every time the next or previous row is retrieved from a cursor.

The (conform) without registering feature is implemented here, and may return an original non UnitOfWork registered result.

Pessimistically locked objects are tracked here.

param
result may be an object (in the identity map of the parent session), which becomes the original, or a raw database row if in transaction.
param
buildDirectlyFromRows true if must construct a registered result from raw database rows.
return
a refreshed UnitOfWork queried object, unwrapped.

        Object clone = null;
        if (buildDirectlyFromRows) {
            // This method will either call back later with buildDirectlyFromRows == false,
            // or special code which builds/refreshes clones directly from the
            // row will be invoked.
            return buildObject((AbstractRecord)result);
        }
        // For bug 2612601 Conforming without registering in Unit Of Work.
        else if (!isRegisteringResults()) {
            clone = unitOfWork.getIdentityMapAccessorInstance().getIdentityMapManager().getFromIdentityMap(result);

            // If object not registered do not register it here!  Simply return 
            // the original to the user.
            // Avoid setting clone = original, in case revert(clone) is called.
            if (clone == null) {
                clone = result;
            }
        } else {
            // bug # 3183379 either the object comes from the shared cache and is existing, or
            //it is from a parent unit of work and this unit of work does not need to know if it is new
            //or not.  It will query the parent unit of work to determine newness.
            clone = unitOfWork.registerExistingObject(result, joinManager);
        }

        // Check for refreshing, require to revert in the unit of work to accomplish a refresh.
        if (shouldRefreshIdentityMapResult()) {
            // Revert only works in the object is in the parent cache, if it is not merge must be used.
            if (unitOfWork.getParent().getIdentityMapAccessor().containsObjectInIdentityMap(clone)) {
                if (shouldCascadeAllParts()) {
                    unitOfWork.deepRevertObject(clone);
                } else if (shouldCascadePrivateParts()) {
                    unitOfWork.revertObject(clone);
                } else if (shouldCascadeByMapping()) {
                    unitOfWork.revertObject(clone, MergeManager.CASCADE_BY_MAPPING);
                } else if (!shouldCascadeParts()) {
                    unitOfWork.shallowRevertObject(clone);
                }
            } else {
                if (shouldCascadeAllParts()) {
                    unitOfWork.deepMergeClone(result);
                } else if (shouldCascadePrivateParts()) {
                    unitOfWork.mergeClone(result);
                } else if (shouldCascadeByMapping()) {
                    unitOfWork.mergeClone(result, MergeManager.CASCADE_BY_MAPPING);
                } else if (!shouldCascadeParts()) {
                    unitOfWork.shallowMergeClone(result);
                }
            }
        }

        // record clone if referenced class has pessimistic locking policy
        recordCloneForPessimisticLocking(clone, unitOfWork);

        return clone;
    
public voidsetExecutionTime(long executionTime)
INTERNAL: Set the the time this query went to the database.

        this.executionTime = executionTime;
    
public voidsetLockMode(short lockMode)
PUBLIC: Sets whether this is a pessimistically locking query.
  • ObjectBuildingQuery.LOCK: SELECT .... FOR UPDATE issued.
  • ObjectBuildingQuery.LOCK_NOWAIT: SELECT .... FOR UPDATE NO WAIT issued.
  • ObjectBuildingQuery.NO_LOCK: no pessimistic locking.
  • ObjectBuildingQuery.DEFAULT_LOCK_MODE (default) and you have a CMP descriptor: fine grained locking will occur.

Fine Grained Locking: On execution the reference class and those of all joined attributes will be checked. If any of these have a PessimisticLockingPolicy set on their descriptor, they will be locked in a SELECT ... FOR UPDATE OF ... {NO WAIT}. Issues fewer locks and avoids setting the lock mode on each query.

Example:readAllQuery.setSelectionCriteria(employee.get("address").equal("Ottawa"));

  • LOCK: all employees in Ottawa and all referenced Ottawa addresses will be locked.
  • DEFAULT_LOCK_MODE: if address is a joined attribute, and only address has a pessimistic locking policy, only referenced Ottawa addresses will be locked.

see
oracle.toplink.essentials.descriptors.PessimisticLockingPolicy

        lockingClause = ForUpdateClause.newInstance(lockMode);
    
public voidsetReferenceClass(java.lang.Class aClass)
REQUIRED: Set the reference class for the query.

        referenceClass = aClass;
        setIsPrepared(false);
    
public voidsetReferenceClassName(java.lang.String aClass)
INTERNAL: Set the reference class for the query.

        referenceClassName = aClass;
        setIsPrepared(false);
    
public voidsetShouldProcessResultsInUnitOfWork(boolean processResultsInUnitOfWork)
ADVANCED: Used for CMP only. This allows users to indicate whether cmp finders executed at the beginning of a transaction should always be run against a UnitOfWork. Defaults to true.

If set to false, then UnitOfWork allocation will be deferred until a business method (including creates/removes) or finder with shouldProcessResultsInUnitOfWork == true is invoked. Any finder executed before such a time, will do so against the underlying ServerSession. Forcing finder execution to always go through a UnitOfWork means the results will be cloned and cached in the UnitOfWork up front. This is desired when the results will be accessed in the same transaction.

Note that finders executed with an unspecified transaction context will never be executed against a UnitOfWork, even if this setting is true. This case may happen with the NotSupported, Never, and Supports attributes.

        this.shouldProcessResultsInUnitOfWork = processResultsInUnitOfWork;
    
public voidsetShouldRefreshIdentityMapResult(boolean shouldRefreshIdentityMapResult)
PUBLIC: Set if the attributes of the object(s) resulting from the query should be refreshed. If cascading is used the private parts of the objects will also be refreshed.

        this.shouldRefreshIdentityMapResult = shouldRefreshIdentityMapResult;
        if (shouldRefreshIdentityMapResult) {
            setShouldRefreshRemoteIdentityMapResult(true);
        }
    
public voidsetShouldRefreshRemoteIdentityMapResult(boolean shouldRefreshIdentityMapResult)
PUBLIC: Set if the attributes of the object(s) resulting from the query should be refreshed. If cascading is used the private parts of the objects will also be refreshed.

        this.shouldRefreshRemoteIdentityMapResult = shouldRefreshIdentityMapResult;
    
public voidsetShouldRegisterResultsInUnitOfWork(boolean shouldRegisterResultsInUnitOfWork)
INTERNAL: Set to false to have queries conform to a UnitOfWork without registering any additional objects not already in that UnitOfWork.

see
#shouldRegisterResultsInUnitOfWork
bug
2612601

        this.shouldRegisterResultsInUnitOfWork = shouldRegisterResultsInUnitOfWork;
    
protected voidsetWasDefaultLockMode(boolean wasDefaultLockMode)
INTERNAL: Set if this query originally used the default lock mode.

        this.wasDefaultLockMode = wasDefaultLockMode;
    
public booleanshouldProcessResultsInUnitOfWork()
ADVANCED: Used for CMP only. Indicates whether cmp finders executed at the beginning of a transaction should always be run against a UnitOfWork. Defaults to true.

If set to false, then UnitOfWork allocation will be deferred until a business method (including creates/removes) or finder with shouldProcessResultsInUnitOfWork == true is invoked. Any finder executed before such a time, will do so against the underlying ServerSession. Forcing finder execution to always go through a UnitOfWork means the results will be cloned and cached in the UnitOfWork up front. This is desired when the results will be accessed in the same transaction.

Note that finders executed with an unspecified transaction context will never be executed against a UnitOfWork, even if this setting is true. This case may happen with the NotSupported, Never, and Supports attributes.

        return this.shouldProcessResultsInUnitOfWork;
    
public booleanshouldReadAllMappings()
INTERNAL: Return if this is a full object query, not partial nor fetch group.

        return true;
    
public booleanshouldReadMapping(oracle.toplink.essentials.mappings.DatabaseMapping mapping)
INTERNAL: Check if the mapping is part of the partial attributes.

        return true;
    
public booleanshouldRefreshIdentityMapResult()
PUBLIC: Set to a boolean. When set means refresh the instance variables of referenceObject from the database.

        return shouldRefreshIdentityMapResult;
    
public booleanshouldRefreshRemoteIdentityMapResult()
PUBLIC: Set to a boolean. When set means refresh the instance variables of referenceObject from the database.

        return shouldRefreshRemoteIdentityMapResult;
    
public booleanshouldRegisterResultsInUnitOfWork()
INTERNAL: Allows one to do conforming in a UnitOfWork without registering. Queries executed on a UnitOfWork will only return working copies for objects that have already been registered.

Extreme care should be taken in using this feature, for a user will get back a mix of registered and original (unregistered) objects.

Best used with a WrapperPolicy where invoking on an object will trigger its registration (CMP). Without a WrapperPolicy {@link oracle.toplink.essentials.sessions.UnitOfWork#registerExistingObject registerExistingObject} should be called on any object that you intend to change.

return
true by default.
see
#setShouldRegisterResultsInUnitOfWork
see
oracle.toplink.essentials.publicinterface.Descriptor#shouldRegisterResulstInUnitOfWork
bug
2612601

        return shouldRegisterResultsInUnitOfWork;
    
public java.lang.StringtoString()

        if (getReferenceClass() == null) {
            return super.toString();
        }
        return Helper.getShortClassName(getClass()) + "(" + getReferenceClass().getName() + ")";
    
protected booleanwasDefaultLockMode()
INTERNAL: Return if this query originally used the default lock mode.

        return wasDefaultLockMode;