FileDocCategorySizeDatePackage
ObjectBuilder.javaAPI DocGlassfish v2 API115344Tue May 22 16:54:22 BST 2007oracle.toplink.essentials.internal.descriptors

ObjectBuilder

public class ObjectBuilder extends Object implements Serializable, Cloneable

Purpose: Object builder is one of the behaviour class attached to descriptor. It is responsible for building objects, rows, and extracting primary keys from the object and the rows.

author
Sati
since
TOPLink/Java 1.0

Fields Summary
protected oracle.toplink.essentials.descriptors.ClassDescriptor
descriptor
protected Map
mappingsByAttribute
protected Map
mappingsByField
protected Map
readOnlyMappingsByField
protected Vector
primaryKeyMappings
protected Vector
primaryKeyClassifications
protected transient Vector
nonPrimaryKeyMappings
protected transient Expression
primaryKeyExpression
protected Vector
joinedAttributes
PERF: Cache mapping that use joining.
protected List
cloningMappings
PERF: Cache mappings that require cloning.
Constructors Summary
public ObjectBuilder(oracle.toplink.essentials.descriptors.ClassDescriptor descriptor)


       
        this.mappingsByField = new HashMap(20);
        this.readOnlyMappingsByField = new HashMap(20);
        this.mappingsByAttribute = new HashMap(20);
        this.primaryKeyMappings = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(5);
        this.nonPrimaryKeyMappings = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(10);
        this.cloningMappings = new ArrayList(10);
        this.descriptor = descriptor;
    
Methods Summary
public voidaddPrimaryKeyForNonDefaultTable(oracle.toplink.essentials.internal.sessions.AbstractRecord databaseRow)
Add the primary key and its value to the databaseRow for all the non default tables. This method is used while writing into the multiple tables.

        // this method has been revised so it calls addPrimaryKeyForNonDefaultTable(DatabaseRow, Object, Session) is similar.
        // the session and object are null in this case.
        addPrimaryKeyForNonDefaultTable(databaseRow, null, null);
    
public voidaddPrimaryKeyForNonDefaultTable(oracle.toplink.essentials.internal.sessions.AbstractRecord databaseRow, java.lang.Object object, oracle.toplink.essentials.internal.sessions.AbstractSession session)
Add the primary key and its value to the databaseRow for all the non default tables. This method is used while writing into the multiple tables.

        if (!getDescriptor().hasMultipleTables()) {
            return;
        }
        Enumeration tablesEnum = getDescriptor().getTables().elements();

        // Skip first table.
        tablesEnum.nextElement();
        while (tablesEnum.hasMoreElements()) {
            DatabaseTable table = (DatabaseTable)tablesEnum.nextElement();
            Map keyMapping = (Map)getDescriptor().getAdditionalTablePrimaryKeyFields().get(table);

            // Loop over the additionalTablePK fields and add the PK info for the table. The join might
            // be between a fk in the source table and pk in secondary table.
            if (keyMapping != null) {
                Iterator primaryKeyFieldEnum = keyMapping.keySet().iterator();
                Iterator secondaryKeyFieldEnum = keyMapping.values().iterator();
                while (primaryKeyFieldEnum.hasNext()) {
                    DatabaseField primaryKeyField = (DatabaseField)primaryKeyFieldEnum.next();
                    DatabaseField secondaryKeyField = (DatabaseField)secondaryKeyFieldEnum.next();
                    Object primaryValue = databaseRow.get(primaryKeyField);

                    // normally the primary key has a value, however if the multiple tables were joined by a foreign
                    // key the foreign key has a value.
                    if ((primaryValue == null) && (!databaseRow.containsKey(primaryKeyField))) {
                        if (object != null) {
                            DatabaseMapping mapping = getMappingForField(secondaryKeyField);
                            if (mapping == null) {
                                throw DescriptorException.missingMappingForField(secondaryKeyField, getDescriptor());
                            }
                            mapping.writeFromObjectIntoRow(object, databaseRow, session);
                        }
                        databaseRow.put(primaryKeyField, databaseRow.get(secondaryKeyField));
                    } else {
                        databaseRow.put(secondaryKeyField, primaryValue);
                    }
                }
            }
        }
    
public voidassignReturnRow(java.lang.Object object, oracle.toplink.essentials.internal.sessions.AbstractSession writeSession, oracle.toplink.essentials.internal.sessions.AbstractRecord row)
INTERNAL: Assign returned row to object

        writeSession.log(SessionLog.FINEST, SessionLog.QUERY, "assign_return_row", row);

        // Require a query context to read into an object.
        ReadObjectQuery query = new ReadObjectQuery();
        query.setSession(writeSession);

        // To avoid processing the same mapping twice,
        // maintain Collection of mappings already used.
        HashSet handledMappings = new HashSet(row.size());
        for (int index = 0; index < row.size(); index++) {
            DatabaseField field = (DatabaseField)row.getFields().elementAt(index);
            assignReturnValueForField(object, query, row, field, handledMappings);
        }
    
public voidassignReturnValueForField(java.lang.Object object, ReadObjectQuery query, oracle.toplink.essentials.internal.sessions.AbstractRecord row, DatabaseField field, java.util.Collection handledMappings)
INTERNAL: Assign values from objectRow to the object through all the mappings corresponding to the field.

        DatabaseMapping mapping = getMappingForField(field);
        if (mapping != null) {
            assignReturnValueToMapping(object, query, row, field, mapping, handledMappings);
        }
        Vector mappingVector = getReadOnlyMappingsForField(field);
        if (mappingVector != null) {
            for (int j = 0; j < mappingVector.size(); j++) {
                mapping = (DatabaseMapping)mappingVector.elementAt(j);
                assignReturnValueToMapping(object, query, row, field, mapping, handledMappings);
            }
        }
    
protected voidassignReturnValueToMapping(java.lang.Object object, ReadObjectQuery query, oracle.toplink.essentials.internal.sessions.AbstractRecord row, DatabaseField field, DatabaseMapping mapping, java.util.Collection handledMappings)
INTERNAL: Assign values from objectRow to the object through the mapping.

        if (handledMappings.contains(mapping)) {
            return;
        }
        Object attributeValue;
        if (mapping.isAggregateObjectMapping()) {
            attributeValue = ((AggregateObjectMapping)mapping).readFromReturnRowIntoObject(row, object, query, handledMappings);
        } else if (mapping.isDirectToFieldMapping()) {
            attributeValue = mapping.readFromRowIntoObject(row, null, object, query);
        } else {
            query.getSession().log(SessionLog.FINEST, SessionLog.QUERY, "field_for_unsupported_mapping_returned", field, getDescriptor());
        }
    
public java.lang.ObjectassignSequenceNumber(java.lang.Object object, oracle.toplink.essentials.internal.sessions.AbstractSession writeSession)
INTERNAL: Update the object primary key by fetching a new sequence number from the accessor. This assume the uses sequence numbers check has already been done.

return
the sequence value or null if not assigned.
exception
DatabaseException - an error has occurred on the database.

        DatabaseField sequenceNumberField = getDescriptor().getSequenceNumberField();
        Object existingValue = getBaseValueForField(sequenceNumberField, object);

        //** sequencing refactoring
        if (existingValue != null) {
            if (!writeSession.getSequencing().shouldOverrideExistingValue(object.getClass(), existingValue)) {
                return null;
            }
        }
        Object sequenceValue = writeSession.getSequencing().getNextValue(object.getClass());

        //CR#2272
        writeSession.log(SessionLog.FINEST, SessionLog.SEQUENCING, "assign_sequence", sequenceValue, object);

        // Check that the value is not null, this occurs on Sybase identity only **
        if (sequenceValue == null) {
            return null;
        }

        // Now add the value to the object, this gets ugly.
        AbstractRecord tempRow = createRecord(1);
        tempRow.put(sequenceNumberField, sequenceValue);

        // Require a query context to read into an object.
        ReadObjectQuery query = new ReadObjectQuery();
        query.setSession(writeSession);
        DatabaseMapping mapping = getBaseMappingForField(sequenceNumberField);
        Object sequenceIntoObject = getParentObjectForField(sequenceNumberField, object);

        // the following method will return the converted value for the sequence
        Object convertedSequenceValue = mapping.readFromRowIntoObject(tempRow, null, sequenceIntoObject, query);

        return convertedSequenceValue;
    
public voidbuildAttributesIntoObject(java.lang.Object domainObject, oracle.toplink.essentials.internal.sessions.AbstractRecord databaseRow, ObjectBuildingQuery query, oracle.toplink.essentials.internal.queryframework.JoinedAttributeManager joinManager, boolean forRefresh)
Each mapping is recursed to assign values from the databaseRow to the attributes in the domain object.

        AbstractSession executionSession = query.getSession().getExecutionSession(query);

        // PERF: Avoid synchronized enumerator as is concurrency bottleneck.
        Vector mappings = getDescriptor().getMappings();

        // PERF: Cache if all mappings should be read.
        boolean readAllMappings = query.shouldReadAllMappings();
        int mappingsSize = mappings.size();
        for (int index = 0; index < mappingsSize; index++) {
            DatabaseMapping mapping = (DatabaseMapping)mappings.get(index);
            if (readAllMappings || query.shouldReadMapping(mapping)) {
                mapping.readFromRowIntoObject(databaseRow, joinManager, domainObject, query, executionSession);
            }
        }

        // PERF: Avoid events if no listeners.
        if (getDescriptor().getEventManager().hasAnyEventListeners()) {
            // Need to run post build or refresh selector, currently check with the query for this,
            // I'm not sure which should be called it case of refresh building a new object, currently refresh is used...
            oracle.toplink.essentials.descriptors.DescriptorEvent event = new oracle.toplink.essentials.descriptors.DescriptorEvent(domainObject);
            event.setQuery(query);
            event.setSession(query.getSession());
            event.setRecord(databaseRow);
            if (forRefresh) {
                //this method can be called from different places within TopLink.  We may be
                //executing refresh query but building the object not refreshing so we must
                //throw the appropriate event.
                //bug 3325315
                event.setEventCode(DescriptorEventManager.PostRefreshEvent);
            } else {
                event.setEventCode(DescriptorEventManager.PostBuildEvent);
            }
            getDescriptor().getEventManager().executeEvent(event);
        }
    
public voidbuildAttributesIntoShallowObject(java.lang.Object original, oracle.toplink.essentials.internal.sessions.AbstractRecord databaseRow, ObjectBuildingQuery query)
INTERNAL: For reading through the write connection when in transaction, We need a partially populated original, so that we can build a clone using the copy policy, even though we can't put this original in the shared cache yet; just build a shallow original (i.e. just enough to copy over the primary key and some direct attributes) and keep it on the UOW.

        AbstractSession executionSession = query.getSession().getExecutionSession(query);

        // PERF: Avoid synchronized enumerator as is concurrency bottleneck.
        Vector pkMappings = getPrimaryKeyMappings();
        int mappingsSize = pkMappings.size();
        for (int i = 0; i < mappingsSize; i++) {
            DatabaseMapping mapping = (DatabaseMapping)pkMappings.get(i);

            //if (query.shouldReadMapping(mapping)) {
            if (!mapping.isDirectToFieldMapping()) {
                mapping.buildShallowOriginalFromRow(databaseRow, original, query, executionSession);
            }
        }
        Vector mappings = getDescriptor().getMappings();
        mappingsSize = mappings.size();
        for (int i = 0; i < mappingsSize; i++) {
            DatabaseMapping mapping = (DatabaseMapping)mappings.get(i);

            //if (query.shouldReadMapping(mapping)) {
            if (mapping.isDirectToFieldMapping()) {
                mapping.buildShallowOriginalFromRow(databaseRow, original, query, executionSession);
            }
        }
    
public voidbuildAttributesIntoWorkingCopyClone(java.lang.Object clone, ObjectBuildingQuery query, oracle.toplink.essentials.internal.queryframework.JoinedAttributeManager joinManager, oracle.toplink.essentials.internal.sessions.AbstractRecord databaseRow, oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl unitOfWork, boolean forRefresh)
INTERNAL: For reading through the write connection when in transaction, populate the clone directly from the database row.

        AbstractSession executionSession = unitOfWork;
        //execution session is UnitOfWork as these objects are being built within
        //the unit of work
        Vector mappings = getDescriptor().getMappings();
        int mappingsSize = mappings.size();
        for (int i = 0; i < mappingsSize; i++) {
            DatabaseMapping mapping = (DatabaseMapping)mappings.get(i);
            if (query.shouldReadMapping(mapping)) {
                mapping.buildCloneFromRow(databaseRow, joinManager, clone, query, unitOfWork, executionSession);
            }
        }

        // PERF: Avoid events if no listeners.
        if (getDescriptor().getEventManager().hasAnyEventListeners()) {
            // Need to run post build or refresh selector, currently check with the query for this,
            // I'm not sure which should be called it case of refresh building a new object, currently refresh is used...
            oracle.toplink.essentials.descriptors.DescriptorEvent event = new oracle.toplink.essentials.descriptors.DescriptorEvent(clone);
            event.setQuery(query);
            event.setSession(query.getSession());
            event.setRecord(databaseRow);
            if (forRefresh) {
                event.setEventCode(DescriptorEventManager.PostRefreshEvent);
            } else {
                event.setEventCode(DescriptorEventManager.PostBuildEvent);
            }
            getDescriptor().getEventManager().executeEvent(event);
        }
    
public java.lang.ObjectbuildBackupClone(java.lang.Object clone, oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl unitOfWork)
Returns the clone of the specified object. This is called only from unit of work. The clonedDomainObject sent as parameter is always a working copy from the unit of work.

        // The copy policy builds clone	
        Object backup = getDescriptor().getCopyPolicy().buildClone(clone, unitOfWork);

        // PERF: Avoid synchronized enumerator as is concurrency bottleneck.
        List mappings = getCloningMappings();
        for (int index = 0; index < mappings.size(); index++) {
            ((DatabaseMapping)mappings.get(index)).buildBackupClone(clone, backup, unitOfWork);
        }

        return backup;
    
public ExpressionbuildDeleteExpression(DatabaseTable table, oracle.toplink.essentials.internal.sessions.AbstractRecord row)
Build and return the expression to use as the where clause to delete an object. The row is passed to allow the version number to be extracted from it.

        if (getDescriptor().usesOptimisticLocking() && (getDescriptor().getTables().firstElement().equals(table))) {
            return getDescriptor().getOptimisticLockingPolicy().buildDeleteExpression(table, primaryKeyExpression, row);
        } else {
            return buildPrimaryKeyExpression(table);
        }
    
public java.lang.ObjectbuildNewInstance()
Return a new instance of the receiver's javaClass.

        return getDescriptor().getInstantiationPolicy().buildNewInstance();
    
public java.lang.ObjectbuildObject(ObjectBuildingQuery query, oracle.toplink.essentials.internal.sessions.AbstractRecord databaseRow, oracle.toplink.essentials.internal.queryframework.JoinedAttributeManager joinManager)
Return an instance of the recievers javaClass. Set the attributes of an instance from the values stored in the database row.

        // Profile object building.
        AbstractSession session = query.getSession();
        session.startOperationProfile(SessionProfiler.OBJECT_BUILDING);

        Vector primaryKey = extractPrimaryKeyFromRow(databaseRow, session);

        // Check for null primary key, this is not allowed.
        if ((primaryKey == null) && (!query.hasPartialAttributeExpressions()) && (!getDescriptor().isAggregateCollectionDescriptor())) {
            // Profile object building.
            session.endOperationProfile(SessionProfiler.OBJECT_BUILDING);

            //BUG 3168689: EJBQL: "Select Distinct s.customer from SpouseBean s"
            //BUG 3168699: EJBQL: "Select s.customer from SpouseBean s where s.id = '6'"
            //If we return either a single null, or a Collection containing at least 
            //one null, then we want the nulls returned/included if the indicated 
            //property is set in the query. (As opposed to throwing an Exception).
            if (query.getProperty("return null if primary key is null") != null) {
                return null;
            } else {
                throw QueryException.nullPrimaryKeyInBuildingObject(query, databaseRow);
            }
        }
        ClassDescriptor concreteDescriptor = getDescriptor();
        if (concreteDescriptor.hasInheritance() && concreteDescriptor.getInheritancePolicy().shouldReadSubclasses()) {
            Class classValue = concreteDescriptor.getInheritancePolicy().classFromRow(databaseRow, session);
            concreteDescriptor = session.getDescriptor(classValue);
            if ((concreteDescriptor == null) && query.hasPartialAttributeExpressions()) {
                concreteDescriptor = getDescriptor();
            }
            if (concreteDescriptor == null) {
                // Profile object building.
                session.endOperationProfile(SessionProfiler.OBJECT_BUILDING);
                throw QueryException.noDescriptorForClassFromInheritancePolicy(query, classValue);
            }
        }
        Object domainObject = null;
        try {
            if (session.isUnitOfWork()) {
                // Do not wrap yet if in UnitOfWork, as there is still much more
                // processing ahead.
                domainObject = buildObjectInUnitOfWork(query, joinManager, databaseRow, (UnitOfWorkImpl)session, primaryKey, concreteDescriptor);
            } else {
                domainObject = buildObject(query, databaseRow, session, primaryKey, concreteDescriptor, joinManager);

                // wrap the object if the query requires it.
                if (query.shouldUseWrapperPolicy()) {
                    domainObject = concreteDescriptor.getObjectBuilder().wrapObject(domainObject, session);
                }
            }
        } finally {
            session.endOperationProfile(SessionProfiler.OBJECT_BUILDING);
        }
        return domainObject;
    
protected java.lang.ObjectbuildObject(ObjectBuildingQuery query, oracle.toplink.essentials.internal.sessions.AbstractRecord databaseRow, oracle.toplink.essentials.internal.sessions.AbstractSession session, java.util.Vector primaryKey, oracle.toplink.essentials.descriptors.ClassDescriptor concreteDescriptor, oracle.toplink.essentials.internal.queryframework.JoinedAttributeManager joinManager)
Return an instance of the recievers javaClass. Set the attributes of an instance from the values stored in the database row.

        Object domainObject = null;

        //cache key is used for object locking
        CacheKey cacheKey = null;
        try {
            // Check if the objects exists in the identity map.
            if (query.shouldMaintainCache()) {
                //lock the object in the IM
                // PERF: Only use deferred locking if required.
                // CR#3876308 If joining is used, deferred locks are still required.
                if (DeferredLockManager.SHOULD_USE_DEFERRED_LOCKS && (concreteDescriptor.shouldAcquireCascadedLocks() || joinManager.hasJoinedAttributes())) {
                    cacheKey = session.getIdentityMapAccessorInstance().acquireDeferredLock(primaryKey, concreteDescriptor.getJavaClass(), concreteDescriptor);
                    domainObject = cacheKey.getObject();

                    int counter = 0;
                    while ((domainObject == null) && (counter < 1000)) {
                        if (cacheKey.getMutex().getActiveThread() == Thread.currentThread()) {
                            break;
                        }
                        //must release lock here to prevent acquiring multiple deferred locks but only
                        //releasing one at the end of the build object call.
			//BUG 5156075
                        cacheKey.releaseDeferredLock();

                        //sleep and try again if we arenot the owner of the lock for CR 2317
                        // prevents us from modifying a cache key that another thread has locked.												
                        try {
                            Thread.sleep(10);
                        } catch (InterruptedException exception) {
                        }
                        cacheKey = session.getIdentityMapAccessorInstance().acquireDeferredLock(primaryKey, concreteDescriptor.getJavaClass(), concreteDescriptor);
                        domainObject = cacheKey.getObject();
                        counter++;
                    }
                    if (counter == 1000) {
                        throw ConcurrencyException.maxTriesLockOnBuildObjectExceded(cacheKey.getMutex().getActiveThread(), Thread.currentThread());
                    }
                } else {
                    cacheKey = session.getIdentityMapAccessorInstance().acquireLock(primaryKey, concreteDescriptor.getJavaClass(), concreteDescriptor);
                    domainObject = cacheKey.getObject();
                }
            }

            if (domainObject == null) {
                if (query.isReadObjectQuery() && ((ReadObjectQuery)query).shouldLoadResultIntoSelectionObject()) {
                    domainObject = ((ReadObjectQuery)query).getSelectionObject();
                } else {
                    domainObject = concreteDescriptor.getObjectBuilder().buildNewInstance();
                }

                // The object must be registered before building its attributes to resolve circular dependancies. 
                if (query.shouldMaintainCache()) {
                    cacheKey.setObject(domainObject);

                    copyQueryInfoToCacheKey(cacheKey, query, databaseRow, session, concreteDescriptor);

                    //set the fetch group to the domain object
                    if (concreteDescriptor.hasFetchGroupManager()) {
                        concreteDescriptor.getFetchGroupManager().setObjectFetchGroup(domainObject, query.getFetchGroup());
                    }
                }

                concreteDescriptor.getObjectBuilder().buildAttributesIntoObject(domainObject, databaseRow, query, joinManager, false);
            } else {
                if (query.isReadObjectQuery() && ((ReadObjectQuery)query).shouldLoadResultIntoSelectionObject()) {
                    copyInto(domainObject, ((ReadObjectQuery)query).getSelectionObject());
                    domainObject = ((ReadObjectQuery)query).getSelectionObject();
                }

                //check if the cached object has been invalidated
                boolean isInvalidated = concreteDescriptor.getCacheInvalidationPolicy().isInvalidated(cacheKey, query.getExecutionTime());

                //CR #4365 - Queryid comparison used to prevent infinit recursion on refresh object cascade all
                //if the concurrency manager is locked by the merge process then no refresh is required.
                // bug # 3388383 If this thread does not have the active lock then someone is building the object so in order to maintain data integrity this thread will not
                // fight to overwrite the object ( this also will avoid potential deadlock situations
                if ((cacheKey.getMutex().getActiveThread() == Thread.currentThread()) && ((query.shouldRefreshIdentityMapResult() || concreteDescriptor.shouldAlwaysRefreshCache() || isInvalidated) && ((cacheKey.getLastUpdatedQueryId() != query.getQueryId()) && !cacheKey.getMutex().isLockedByMergeManager()))) {
                    //cached object might be partially fetched, only refresh the fetch group attributes of the query if
                    //the cached partial object is not invalidated and does not contain all data for the fetch group.	
                    if (concreteDescriptor.hasFetchGroupManager() && concreteDescriptor.getFetchGroupManager().isPartialObject(domainObject)) {
                        //only ObjectLevelReadQuery and above support partial objects
                        revertFetchGroupData(domainObject, concreteDescriptor, cacheKey, ((ObjectLevelReadQuery)query), joinManager, databaseRow, session);
                    } else {
                        boolean refreshRequired = true;
                        if (concreteDescriptor.usesOptimisticLocking()) {
                            OptimisticLockingPolicy policy = concreteDescriptor.getOptimisticLockingPolicy();
                            Object cacheValue = policy.getValueToPutInCache(databaseRow, session);
                            if (concreteDescriptor.shouldOnlyRefreshCacheIfNewerVersion()) {
                                refreshRequired = policy.isNewerVersion(databaseRow, domainObject, primaryKey, session);
                                if (!refreshRequired) {
                                    cacheKey.setReadTime(query.getExecutionTime());
                                }
                            }
                            if (refreshRequired) {
                                //update the wriet lock value
                                cacheKey.setWriteLockValue(cacheValue);
                            }
                        }
                        if (refreshRequired) {
                            //CR #4365 - used to prevent infinit recursion on refresh object cascade all
                            cacheKey.setLastUpdatedQueryId(query.getQueryId());
                            concreteDescriptor.getObjectBuilder().buildAttributesIntoObject(domainObject, databaseRow, query, joinManager, true);
                            cacheKey.setReadTime(query.getExecutionTime());
                        }
                    }
                } else if (concreteDescriptor.hasFetchGroupManager() && (concreteDescriptor.getFetchGroupManager().isPartialObject(domainObject) && (!concreteDescriptor.getFetchGroupManager().isObjectValidForFetchGroup(domainObject, query.getFetchGroup())))) {
                    //the fetched object is not sufficient for the fetch group of the query 
                    //refresh attributes of the query's fetch group
                    concreteDescriptor.getObjectBuilder().buildAttributesIntoObject(domainObject, databaseRow, query, joinManager, false);
                    concreteDescriptor.getFetchGroupManager().unionFetchGroupIntoObject(domainObject, query.getFetchGroup());
                }
                // 3655915: a query with join/batch'ing that gets a cache hit
                // may require some attributes' valueholders to be re-built.
                else if (joinManager.hasJoinedAttributeExpressions()) {
                    for (Iterator e = joinManager.getJoinedAttributeExpressions().iterator();
                             e.hasNext();) {
                        QueryKeyExpression qke = (QueryKeyExpression)e.next();

                        // only worry about immediate attributes
                        if (qke.getBaseExpression().isExpressionBuilder()) {
                            DatabaseMapping dm = getMappingForAttributeName(qke.getName());

                            if (dm == null) {
                                throw ValidationException.missingMappingForAttribute(concreteDescriptor, qke.getName(), this.toString());
                            } else {
                                // Bug 4230655 - do not replace instantiated valueholders
                                Object attributeValue = dm.getAttributeValueFromObject(domainObject);
                                if (!((attributeValue != null) && dm.isForeignReferenceMapping() && ((ForeignReferenceMapping)dm).usesIndirection() && ((ForeignReferenceMapping)dm).getIndirectionPolicy().objectIsInstantiated(attributeValue))) {
                                    dm.readFromRowIntoObject(databaseRow, joinManager, domainObject, query, query.getSession().getExecutionSession(query));
                                }
                            }
                        }
                    }
                }
            }
        } finally {
            if (query.shouldMaintainCache() && (cacheKey != null)) {
                // bug 2681401:
                // in case of exception (for instance, thrown by buildNewInstance())
                // cacheKey.getObject() may be null.
                if (cacheKey.getObject() != null) {
                    cacheKey.updateAccess();
                }

                // PERF: Only use deferred locking if required.
                if (DeferredLockManager.SHOULD_USE_DEFERRED_LOCKS && (concreteDescriptor.shouldAcquireCascadedLocks() || joinManager.hasJoinedAttributes())) {
                    cacheKey.releaseDeferredLock();
                } else {
                    cacheKey.release();
                }
            }
        }

        return domainObject;
    
protected java.lang.ObjectbuildObjectInUnitOfWork(ObjectBuildingQuery query, oracle.toplink.essentials.internal.queryframework.JoinedAttributeManager joinManager, oracle.toplink.essentials.internal.sessions.AbstractRecord databaseRow, oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl unitOfWork, java.util.Vector primaryKey, oracle.toplink.essentials.descriptors.ClassDescriptor concreteDescriptor)
For executing all reads on the UnitOfWork, the session when building objects from rows will now be the UnitOfWork. Usefull if the rows were read via a dirty write connection and we want to avoid putting uncommitted data in the global cache.

Decides whether to call either buildWorkingCopyCloneFromRow (bypassing shared cache) or buildWorkingCopyCloneNormally (placing the result in the shared cache).

        // When in transaction we are reading via the write connection
        // and so do not want to corrupt the shared cache with dirty objects.
        // Hence we build and refresh clones directly from the database row.
        if ((unitOfWork.getCommitManager().isActive() || unitOfWork.wasTransactionBegunPrematurely()) && !unitOfWork.isClassReadOnly(concreteDescriptor.getJavaClass())) {
            // It is easier to switch once to the correct builder here.
            return concreteDescriptor.getObjectBuilder().buildWorkingCopyCloneFromRow(query, joinManager, databaseRow, unitOfWork, primaryKey);
        }

        return buildWorkingCopyCloneNormally(query, databaseRow, unitOfWork, primaryKey, concreteDescriptor, joinManager);
    
public java.lang.ObjectbuildObjectsInto(ReadAllQuery query, java.util.Vector databaseRows, java.lang.Object domainObjects)
Return a container which contains the instances of the receivers javaClass. Set the fields of the instance to the values stored in the database rows.

        Set identitySet = null;
        for (Enumeration rowsEnum = databaseRows.elements(); rowsEnum.hasMoreElements();) {
            AbstractRecord databaseRow = (AbstractRecord)rowsEnum.nextElement();

            // Skip null rows from 1-m joining duplicate row filtering.
            if (databaseRow != null) {
                Object domainObject = buildObject(query, databaseRow, query.getJoinedAttributeManager());

                // Avoid duplicates if -m joining was used and a cache hit occured.
                if (query.getJoinedAttributeManager().isToManyJoin()) {
                    if (identitySet == null) {
                        identitySet = new TopLinkIdentityHashSet(databaseRows.size());
                    }
                    if (!identitySet.contains(domainObject)) {
                        identitySet.add(domainObject);
                        query.getContainerPolicy().addInto(domainObject, domainObjects, query.getSession());
                    }
                } else {
                    query.getContainerPolicy().addInto(domainObject, domainObjects, query.getSession());
                }
            }
        }

        return domainObjects;
    
public voidbuildPrimaryKeyAttributesIntoObject(java.lang.Object original, oracle.toplink.essentials.internal.sessions.AbstractRecord databaseRow, ObjectBuildingQuery query)
INTERNAL: Build just the primary key mappings into the object.

        AbstractSession executionSession = query.getSession().getExecutionSession(query);

        // PERF: Avoid synchronized enumerator as is concurrency bottleneck.
        Vector mappings = getPrimaryKeyMappings();
        int mappingsSize = mappings.size();
        for (int i = 0; i < mappingsSize; i++) {
            DatabaseMapping mapping = (DatabaseMapping)mappings.get(i);
            mapping.buildShallowOriginalFromRow(databaseRow, original, query, executionSession);
        }
    
public ExpressionbuildPrimaryKeyExpression(DatabaseTable table)
Build the primary key expression for the secondary table.

        if (getDescriptor().getTables().firstElement().equals(table)) {
            return getPrimaryKeyExpression();
        }

        Map keyMapping = (Map)getDescriptor().getAdditionalTablePrimaryKeyFields().get(table);
        if (keyMapping == null) {
            throw DescriptorException.multipleTablePrimaryKeyNotSpecified(getDescriptor());
        }

        ExpressionBuilder builder = new ExpressionBuilder();
        Expression expression = null;
        for (Iterator primaryKeyEnum = keyMapping.values().iterator(); primaryKeyEnum.hasNext();) {
            DatabaseField field = (DatabaseField)primaryKeyEnum.next();
            expression = (builder.getField(field).equal(builder.getParameter(field))).and(expression);
        }

        return expression;
    
public ExpressionbuildPrimaryKeyExpressionFromKeys(java.util.Vector primaryKeyValues, oracle.toplink.essentials.internal.sessions.AbstractSession session)
Build the primary key expression from the specified primary key values.

        Expression expression = null;
        Expression subExpression;
        Expression builder = new ExpressionBuilder();
        List primaryKeyFields = getDescriptor().getPrimaryKeyFields();

        for (int index = 0; index < primaryKeyFields.size(); index++) {
            Object value = primaryKeyValues.get(index);
            DatabaseField field = (DatabaseField)primaryKeyFields.get(index);
            if (value != null) {
                subExpression = builder.getField(field).equal(value);
                expression = subExpression.and(expression);
            }
        }

        return expression;
    
public ExpressionbuildPrimaryKeyExpressionFromObject(java.lang.Object domainObject, oracle.toplink.essentials.internal.sessions.AbstractSession session)
Build the primary key expression from the specified domain object.

        return buildPrimaryKeyExpressionFromKeys(extractPrimaryKeyFromObject(domainObject, session), session);
    
public oracle.toplink.essentials.internal.sessions.AbstractRecordbuildRow(java.lang.Object object, oracle.toplink.essentials.internal.sessions.AbstractSession session)
Build the row representation of an object.

        return buildRow(createRecord(), object, session);
    
public oracle.toplink.essentials.internal.sessions.AbstractRecordbuildRow(oracle.toplink.essentials.internal.sessions.AbstractRecord databaseRow, java.lang.Object object, oracle.toplink.essentials.internal.sessions.AbstractSession session)
Build the row representation of an object.

        // PERF: Avoid synchronized enumerator as is concurrency bottleneck.
        Vector mappings = getDescriptor().getMappings();
        int mappingsSize = mappings.size();
        for (int index = 0; index < mappingsSize; index++) {
            DatabaseMapping mapping = (DatabaseMapping)mappings.get(index);
            mapping.writeFromObjectIntoRow(object, databaseRow, session);
        }

        // If this descriptor is involved in inheritence add the class type.
        if (getDescriptor().hasInheritance()) {
            getDescriptor().getInheritancePolicy().addClassIndicatorFieldToRow(databaseRow);
        }

        // If this descriptor has multiple tables then we need to append the primary keys for 
        // the non default tables.
        if (!getDescriptor().isAggregateDescriptor()) {
            addPrimaryKeyForNonDefaultTable(databaseRow);
        }

        return databaseRow;
    
public oracle.toplink.essentials.internal.sessions.AbstractRecordbuildRowForShallowDelete(java.lang.Object object, oracle.toplink.essentials.internal.sessions.AbstractSession session)
Build the row representation of the object for update. The row built does not contain entries for non-relationship fields.

        return buildRowForShallowDelete(createRecord(), object, session);
    
public oracle.toplink.essentials.internal.sessions.AbstractRecordbuildRowForShallowDelete(oracle.toplink.essentials.internal.sessions.AbstractRecord databaseRow, java.lang.Object object, oracle.toplink.essentials.internal.sessions.AbstractSession session)
Build the row representation of the object for update. The row built does not contain entries for non-relationship fields.

        // PERF: Avoid synchronized enumerator as is concurrency bottleneck.
        Vector mappings = getDescriptor().getMappings();
        int mappingsSize = mappings.size();
        for (int index = 0; index < mappingsSize; index++) {
            DatabaseMapping mapping = (DatabaseMapping)mappings.get(index);
            mapping.writeFromObjectIntoRowForShallowDelete(object, databaseRow, session);
        }
        return databaseRow;
    
public oracle.toplink.essentials.internal.sessions.AbstractRecordbuildRowForShallowInsert(java.lang.Object object, oracle.toplink.essentials.internal.sessions.AbstractSession session)
Build the row representation of the object for update. The row built does not contain entries for uninstantiated attributes.

        return buildRowForShallowInsert(createRecord(), object, session);
    
public oracle.toplink.essentials.internal.sessions.AbstractRecordbuildRowForShallowInsert(oracle.toplink.essentials.internal.sessions.AbstractRecord databaseRow, java.lang.Object object, oracle.toplink.essentials.internal.sessions.AbstractSession session)
Build the row representation of the object for update. The row built does not contain entries for uninstantiated attributes.

        // PERF: Avoid synchronized enumerator as is concurrency bottleneck.
        Vector mappings = getDescriptor().getMappings();
        int mappingsSize = mappings.size();
        for (int index = 0; index < mappingsSize; index++) {
            DatabaseMapping mapping = (DatabaseMapping)mappings.get(index);
            mapping.writeFromObjectIntoRowForShallowInsert(object, databaseRow, session);
        }

        // If this descriptor is involved in inheritence add the class type.
        if (getDescriptor().hasInheritance()) {
            getDescriptor().getInheritancePolicy().addClassIndicatorFieldToRow(databaseRow);
        }

        // If this descriptor has multiple tables then we need to append the primary keys for 
        // the non default tables.
        if (!getDescriptor().isAggregateDescriptor()) {
            addPrimaryKeyForNonDefaultTable(databaseRow);
        }

        return databaseRow;
    
public oracle.toplink.essentials.internal.sessions.AbstractRecordbuildRowForShallowInsertWithChangeSet(ObjectChangeSet objectChangeSet, oracle.toplink.essentials.internal.sessions.AbstractSession session)
Build the row representation of the object for update. The row built does not contain entries for uninstantiated attributes.

        return buildRowForShallowInsertWithChangeSet(createRecord(), objectChangeSet, session);
    
public oracle.toplink.essentials.internal.sessions.AbstractRecordbuildRowForShallowInsertWithChangeSet(oracle.toplink.essentials.internal.sessions.AbstractRecord databaseRow, ObjectChangeSet objectChangeSet, oracle.toplink.essentials.internal.sessions.AbstractSession session)
Build the row representation of the object for update. The row built does not contain entries for uninstantiated attributes.

        for (Iterator changeRecords = objectChangeSet.getChanges().iterator();
                 changeRecords.hasNext();) {
            ChangeRecord changeRecord = (ChangeRecord)changeRecords.next();
            DatabaseMapping mapping = changeRecord.getMapping();
            mapping.writeFromObjectIntoRowForShallowInsertWithChangeRecord(changeRecord, databaseRow, session);
        }

        // If this descriptor is involved in inheritence add the class type.
        if (getDescriptor().hasInheritance()) {
            getDescriptor().getInheritancePolicy().addClassIndicatorFieldToRow(databaseRow);
        }

        // If this descriptor has multiple tables then we need to append the primary keys for 
        // the non default tables.
        if (!getDescriptor().isAggregateDescriptor()) {
            addPrimaryKeyForNonDefaultTable(databaseRow);
        }

        return databaseRow;
    
public oracle.toplink.essentials.internal.sessions.AbstractRecordbuildRowForTranslation(java.lang.Object object, oracle.toplink.essentials.internal.sessions.AbstractSession session)
Build the row representation of an object. The row built is used only for translations for the expressions in the expresion framework.

        AbstractRecord databaseRow = createRecord();

        for (Iterator mappings = getPrimaryKeyMappings().iterator(); mappings.hasNext();) {
            DatabaseMapping mapping = (DatabaseMapping)mappings.next();
            if (mapping != null) {
                mapping.writeFromObjectIntoRow(object, databaseRow, session);
            }
        }

        // If this descriptor has multiple tables then we need to append the primary keys for 
        // the non default tables, this is require for m-m, dc defined in the Builder that prefixes the wrong table name.
        // Ideally the mappings should take part in building the translation row so they can add required values.
        addPrimaryKeyForNonDefaultTable(databaseRow, object, session);

        return databaseRow;
    
public oracle.toplink.essentials.internal.sessions.AbstractRecordbuildRowForUpdate(WriteObjectQuery query)
Build the row representation of the object for update. The row built does not contain entries for uninstantiated attributes.

        AbstractRecord databaseRow = createRecord();

        for (Iterator mappings = getNonPrimaryKeyMappings().iterator();
                 mappings.hasNext();) {
            DatabaseMapping mapping = (DatabaseMapping)mappings.next();
            mapping.writeFromObjectIntoRowForUpdate(query, databaseRow);
        }

        // If this descriptor is involved in inheritence and is an Aggregate, add the class type.
        // Added Nov 8, 2000 Mostly by PWK but also JED
        // Prs 24801
        // Modified  Dec 11, 2000 TGW with assitance from PWK
        // Prs 27554
        if (getDescriptor().hasInheritance() && getDescriptor().isAggregateDescriptor()) {
            if (query.getObject() != null) {
                if (query.getBackupClone() == null) {
                    getDescriptor().getInheritancePolicy().addClassIndicatorFieldToRow(databaseRow);
                } else {
                    if (!query.getObject().getClass().equals(query.getBackupClone().getClass())) {
                        getDescriptor().getInheritancePolicy().addClassIndicatorFieldToRow(databaseRow);
                    }
                }
            }
        }

        return databaseRow;
    
public oracle.toplink.essentials.internal.sessions.AbstractRecordbuildRowForUpdateWithChangeSet(WriteObjectQuery query)
Build the row representation of the object for update. The row built does not contain entries for uninstantiated attributes.

        AbstractRecord databaseRow = createRecord();

        for (Iterator changeRecords = query.getObjectChangeSet().getChanges().iterator();
                 changeRecords.hasNext();) {
            ChangeRecord changeRecord = (ChangeRecord)changeRecords.next();
            DatabaseMapping mapping = changeRecord.getMapping();
            mapping.writeFromObjectIntoRowWithChangeRecord(changeRecord, databaseRow, query.getSession());
        }

        return databaseRow;
    
public oracle.toplink.essentials.internal.sessions.AbstractRecordbuildRowForWhereClause(ObjectLevelModifyQuery query)
Build the row representation of an object.

        AbstractRecord databaseRow = createRecord();

        for (Iterator mappings = getDescriptor().getMappings().iterator();
                 mappings.hasNext();) {
            DatabaseMapping mapping = (DatabaseMapping)mappings.next();
            mapping.writeFromObjectIntoRowForWhereClause(query, databaseRow);
        }

        // If this descriptor has multiple tables then we need to append the primary keys for 
        // the non default tables.
        if (!getDescriptor().isAggregateDescriptor()) {
            addPrimaryKeyForNonDefaultTable(databaseRow);
        }

        return databaseRow;
    
public oracle.toplink.essentials.internal.sessions.AbstractRecordbuildRowFromPrimaryKeyValues(java.util.Vector key, oracle.toplink.essentials.internal.sessions.AbstractSession session)
Build the row from the primary key values.

        AbstractRecord databaseRow = createRecord(key.size());
        int keySize = key.size();
        for (int index = 0; index < keySize; index++) {
            DatabaseField field = (DatabaseField)getDescriptor().getPrimaryKeyFields().get(index);
            Object value = key.elementAt(index);
            value = session.getPlatform(getDescriptor().getJavaClass()).getConversionManager().convertObject(value, field.getType());
            databaseRow.put(field, value);
        }

        return databaseRow;
    
public oracle.toplink.essentials.internal.sessions.AbstractRecordbuildRowWithChangeSet(ObjectChangeSet objectChangeSet, oracle.toplink.essentials.internal.sessions.AbstractSession session)
Build the row representation of an object.

        return buildRowWithChangeSet(createRecord(), objectChangeSet, session);
    
public oracle.toplink.essentials.internal.sessions.AbstractRecordbuildRowWithChangeSet(oracle.toplink.essentials.internal.sessions.AbstractRecord databaseRow, ObjectChangeSet objectChangeSet, oracle.toplink.essentials.internal.sessions.AbstractSession session)
Build the row representation of an object.

        for (Enumeration changeRecords = objectChangeSet.getChanges().elements();
                 changeRecords.hasMoreElements();) {
            ChangeRecord changeRecord = (ChangeRecord)changeRecords.nextElement();
            DatabaseMapping mapping = changeRecord.getMapping();
            mapping.writeFromObjectIntoRowWithChangeRecord(changeRecord, databaseRow, session);
        }

        // If this descriptor is involved in inheritence add the class type.
        if (getDescriptor().hasInheritance()) {
            getDescriptor().getInheritancePolicy().addClassIndicatorFieldToRow(databaseRow);
        }

        return databaseRow;
    
public oracle.toplink.essentials.internal.sessions.AbstractRecordbuildTemplateInsertRow(oracle.toplink.essentials.internal.sessions.AbstractSession session)
Build the row of all of the fields used for insertion.

        AbstractRecord databaseRow = createRecord();
        buildTemplateInsertRow(session, databaseRow);
        return databaseRow;
    
public voidbuildTemplateInsertRow(oracle.toplink.essentials.internal.sessions.AbstractSession session, oracle.toplink.essentials.internal.sessions.AbstractRecord databaseRow)

        for (Iterator mappings = getDescriptor().getMappings().iterator();
                 mappings.hasNext();) {
            DatabaseMapping mapping = (DatabaseMapping)mappings.next();
            mapping.writeInsertFieldsIntoRow(databaseRow, session);
        }

        // If this descriptor is involved in inheritence add the class type.
        if (getDescriptor().hasInheritance()) {
            getDescriptor().getInheritancePolicy().addClassIndicatorFieldToInsertRow(databaseRow);
        }

        // If this descriptor has multiple tables then we need to append the primary keys for 
        // the non default tables.
        if (!getDescriptor().isAggregateDescriptor()) {
            addPrimaryKeyForNonDefaultTable(databaseRow);
        }

        if (getDescriptor().usesOptimisticLocking()) {
            getDescriptor().getOptimisticLockingPolicy().addLockFieldsToUpdateRow(databaseRow, session);
        }

        //** sequencing refactoring
        if (getDescriptor().usesSequenceNumbers() && session.getSequencing().shouldAcquireValueAfterInsert(getDescriptor().getJavaClass())) {
            databaseRow.remove(getDescriptor().getSequenceNumberField());
        }
    
public oracle.toplink.essentials.internal.sessions.AbstractRecordbuildTemplateUpdateRow(oracle.toplink.essentials.internal.sessions.AbstractSession session)
Build the row representation of the object for update. The row built does not contain entries for uninstantiated attributes.

        AbstractRecord databaseRow = createRecord();

        for (Iterator mappings = getNonPrimaryKeyMappings().iterator();
                 mappings.hasNext();) {
            DatabaseMapping mapping = (DatabaseMapping)mappings.next();
            mapping.writeUpdateFieldsIntoRow(databaseRow, session);
        }

        if (getDescriptor().usesOptimisticLocking()) {
            getDescriptor().getOptimisticLockingPolicy().addLockFieldsToUpdateRow(databaseRow, session);
        }

        return databaseRow;
    
public ExpressionbuildUpdateExpression(DatabaseTable table, oracle.toplink.essentials.internal.sessions.AbstractRecord transactionRow, oracle.toplink.essentials.internal.sessions.AbstractRecord modifyRow)
Build and return the expression to use as the where clause to an update object. The row is passed to allow the version number to be extracted from it.

        // Only the first table must use the lock check.
        Expression primaryKeyExpression = buildPrimaryKeyExpression(table);
        if (getDescriptor().usesOptimisticLocking()) {
            return getDescriptor().getOptimisticLockingPolicy().buildUpdateExpression(table, primaryKeyExpression, transactionRow, modifyRow);
        } else {
            return primaryKeyExpression;
        }
    
protected java.lang.ObjectbuildWorkingCopyCloneFromRow(ObjectBuildingQuery query, oracle.toplink.essentials.internal.queryframework.JoinedAttributeManager joinManager, oracle.toplink.essentials.internal.sessions.AbstractRecord databaseRow, oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl unitOfWork, java.util.Vector primaryKey)
INTERNAL: Builds a working copy clone directly from the database row. This is the key method that allows us to execute queries against a UnitOfWork while in transaction and not cache the results in the shared cache. This is because we might violate transaction isolation by putting uncommitted versions of objects in the shared cache.

        // If the clone already exists then it may only need to be refreshed or returned.
        // We call directly on the identity map to avoid going to the parent,
        // registering if found, and wrapping the result.
        Object workingClone = unitOfWork.getIdentityMapAccessorInstance().getIdentityMapManager().getFromIdentityMap(primaryKey, getDescriptor().getJavaClass(), getDescriptor());

        // If there is a clone, and it is not a refresh then just return it.
        boolean wasAClone = workingClone != null;
        boolean isARefresh = query.shouldRefreshIdentityMapResult() || (query.isLockQuery() && (!wasAClone || !query.isClonePessimisticLocked(workingClone, unitOfWork)));
        if (wasAClone && (!isARefresh)) {
            return workingClone;
        }

        boolean wasAnOriginal = false;
        Object original = null;

        // If not refreshing can get the object from the cache.
        if (!isARefresh && !unitOfWork.shouldReadFromDB()) {
            CacheKey originalCacheKey = unitOfWork.getParentIdentityMapSession(query).getIdentityMapAccessorInstance().getCacheKeyForObject(primaryKey, getDescriptor().getJavaClass(), getDescriptor());
            if (originalCacheKey != null) {
                //bug 4772232- acquire readlock on cachekey then release to ensure object is fully built before being returned
                try {
                    originalCacheKey.acquireReadLock();
                    original = originalCacheKey.getObject();
                } finally {
                    originalCacheKey.releaseReadLock();
                }
                wasAnOriginal = original != null;
                // If the original is invalid or always refresh then need to refresh.
                isARefresh = wasAnOriginal && (getDescriptor().shouldAlwaysRefreshCache() || getDescriptor().getCacheInvalidationPolicy().isInvalidated(originalCacheKey, query.getExecutionTime()));
                // Otherwise can just register the cached original object and return it.
                if (wasAnOriginal && (!isARefresh)) {
                    return unitOfWork.cloneAndRegisterObject(original, originalCacheKey, joinManager);
                }
            }
        }

        CacheKey unitOfWorkCacheKey = null;
        if (!wasAClone) {
            // This code is copied from UnitOfWork.cloneAndRegisterObject.  Unlike
            // that method we don't need to lock the shared cache, because
            // are not building off of an original in the shared cache.
            // The copy policy is easier to invoke if we have an original.
            if (wasAnOriginal) {
                workingClone = instantiateWorkingCopyClone(original, unitOfWork);
                // intentionally put nothing in clones to originals, unless really was one.
                unitOfWork.getCloneToOriginals().put(workingClone, original);
            } else {
                // What happens if a copy policy is defined is not pleasant.
                workingClone = instantiateWorkingCopyCloneFromRow(databaseRow, query);
            }

            // This must be registered before it is built to avoid cycles.
            // The version and read is set below in copyQueryInfoToCacheKey.
            unitOfWorkCacheKey = unitOfWork.getIdentityMapAccessorInstance().internalPutInIdentityMap(workingClone, primaryKey, null, 0, getDescriptor());

            // This must be registered before it is built to avoid cycles.
            unitOfWork.getCloneMapping().put(workingClone, workingClone);
        }

        // Since there is no original cache key, we may need all the
        // info for the shared cache key in the UnitOfWork cache key.
        // PERF: Only lookup cache-key if did not just put it there.
        if (unitOfWorkCacheKey == null) {
            unitOfWorkCacheKey = unitOfWork.getIdentityMapAccessorInstance().getCacheKeyForObject(primaryKey, getDescriptor().getJavaClass(), getDescriptor());
        }

        // Must avoid infinite loops while refreshing.
        if (wasAClone && (unitOfWorkCacheKey.getLastUpdatedQueryId() >= query.getQueryId())) {
            return workingClone;
        }
        copyQueryInfoToCacheKey(unitOfWorkCacheKey, query, databaseRow, unitOfWork, getDescriptor());

        // If it was a clone the change listener must be cleared after.
        if (!wasAClone) {
            // The change listener must be set before building the clone as aggregate/collections need the listener.
            descriptor.getObjectChangePolicy().setChangeListener(workingClone, unitOfWork, getDescriptor());
        }

        // Turn it 'off' to prevent unwanted events.
        descriptor.getObjectChangePolicy().dissableEventProcessing(workingClone);
        // Build/refresh the clone from the row.
        buildAttributesIntoWorkingCopyClone(workingClone, query, joinManager, databaseRow, unitOfWork, wasAClone);
        Object backupClone = getDescriptor().getObjectChangePolicy().buildBackupClone(workingClone, this, unitOfWork);

        // If it was a clone the change listener must be cleared.
        if (wasAClone) {
            descriptor.getObjectChangePolicy().clearChanges(workingClone, unitOfWork, getDescriptor());
        }
        descriptor.getObjectChangePolicy().enableEventProcessing(workingClone);
        unitOfWork.getCloneMapping().put(workingClone, backupClone);
        query.recordCloneForPessimisticLocking(workingClone, unitOfWork);

        return workingClone;
    
protected java.lang.ObjectbuildWorkingCopyCloneNormally(ObjectBuildingQuery query, oracle.toplink.essentials.internal.sessions.AbstractRecord databaseRow, oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl unitOfWork, java.util.Vector primaryKey, oracle.toplink.essentials.descriptors.ClassDescriptor concreteDescriptor, oracle.toplink.essentials.internal.queryframework.JoinedAttributeManager joinManager)
buildWorkingCopyCloneFromRow is an alternative to this which is the normal behavior. A row is read from the database, an original is built/refreshed/returned from the shared cache, and the original is registered/conformed/reverted in the UnitOfWork.

This default behavior is only safe when the query is executed on a read connection, otherwise uncommitted data might get loaded into the shared cache.

Represents the way TopLink has always worked.

        // This is normal case when we are not in transaction.
        // Pass the query off to the parent.  Let it build the object and
        // cache it normally, then register/refresh it.
        AbstractSession session = unitOfWork.getParentIdentityMapSession(query);
        Object original = null;
        Object clone = null;

        // forwarding queries to different sessions is now as simple as setting
        // the session on the query.
        query.setSession(session);
        if (session.isUnitOfWork()) {
            original = buildObjectInUnitOfWork(query, joinManager, databaseRow, (UnitOfWorkImpl)session, primaryKey, concreteDescriptor);
        } else {
            original = buildObject(query, databaseRow, session, primaryKey, concreteDescriptor, joinManager);
        }
        query.setSession(unitOfWork);
        //GFBug#404  Pass in joinManager or not based on if shouldCascadeCloneToJoinedRelationship is set to true 
        if (unitOfWork.shouldCascadeCloneToJoinedRelationship()) {
            clone = query.registerIndividualResult(original, unitOfWork, false, joinManager);// false == no longer building directly from rows.
        } else {
            clone = query.registerIndividualResult(original, unitOfWork, false, null);// false == no longer building directly from rows.            
        }
        return clone;
    
public voidcascadePerformRemove(java.lang.Object object, oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl uow, IdentityHashtable visitedObjects)
INTERNAL: THis method is used by the UnitOfWork to cascade registration of new objects. It may rais exceptions as described inthe EJB 3.x specification

        Iterator mappings = getDescriptor().getMappings().iterator();
        while (mappings.hasNext()) {
            ((DatabaseMapping)mappings.next()).cascadePerformRemoveIfRequired(object, uow, visitedObjects);
        }
    
public voidcascadeRegisterNewForCreate(java.lang.Object object, oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl uow, IdentityHashtable visitedObjects)
INTERNAL: THis method is used by the UnitOfWork to cascade registration of new objects. It may rais exceptions as described inthe EJB 3.x specification

        Iterator mappings = getDescriptor().getMappings().iterator();
        while (mappings.hasNext()) {
            ((DatabaseMapping)mappings.next()).cascadeRegisterNewIfRequired(object, uow, visitedObjects);
        }
    
public java.lang.Objectclone()
Returns clone of itself

        Object object = null;

        try {
            object = super.clone();
        } catch (Exception exception) {
            ;
        }

        // Only the shallow copy is created. The entries never change in these data structures
        ((ObjectBuilder)object).setMappingsByAttribute(new HashMap(getMappingsByAttribute()));
        ((ObjectBuilder)object).setMappingsByField(new HashMap(getMappingsByField()));
        ((ObjectBuilder)object).setReadOnlyMappingsByField(new HashMap(getReadOnlyMappingsByField()));
        ((ObjectBuilder)object).setPrimaryKeyMappings((Vector)getPrimaryKeyMappings().clone());
        ((ObjectBuilder)object).setNonPrimaryKeyMappings((Vector)getNonPrimaryKeyMappings().clone());

        return object;
    
public ObjectChangeSetcompareForChange(java.lang.Object clone, java.lang.Object backUp, UnitOfWorkChangeSet changeSet, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: This method creates an records changes for a particular object

return
ChangeRecord

        // delegate the change comparision to this objects ObjectChangePolicy - TGW
        return descriptor.getObjectChangePolicy().calculateChanges(clone, backUp, changeSet, session, getDescriptor(), true);
    
public booleancompareObjects(java.lang.Object firstObject, java.lang.Object secondObject, oracle.toplink.essentials.internal.sessions.AbstractSession session)
Compares the two specified objects

        // PERF: Avoid synchronized enumerator as is concurrency bottleneck.
        Vector mappings = getDescriptor().getMappings();
        for (int index = 0; index < mappings.size(); index++) {
            DatabaseMapping mapping = (DatabaseMapping)mappings.get(index);

            if (!mapping.compareObjects(firstObject, secondObject, session)) {
                Object firstValue = mapping.getAttributeValueFromObject(firstObject);
                Object secondValue = mapping.getAttributeValueFromObject(secondObject);
                session.log(SessionLog.FINEST, SessionLog.QUERY, "compare_failed", mapping, firstValue, secondValue);
                return false;
            }
        }

        return true;
    
public voidcopyInto(java.lang.Object source, java.lang.Object target, boolean cloneOneToOneValueHolders)
Copy each attribute from one object into the other.

        // PERF: Avoid synchronized enumerator as is concurrency bottleneck.
        Vector mappings = getDescriptor().getMappings();
        for (int index = 0; index < mappings.size(); index++) {
            DatabaseMapping mapping = (DatabaseMapping)mappings.get(index);
            Object value = null;
            if (cloneOneToOneValueHolders && mapping.isForeignReferenceMapping()){
                value = ((ForeignReferenceMapping)mapping).getAttributeValueWithClonedValueHolders(source);
            } else {
                value = mapping.getAttributeValueFromObject(source);
            }
            mapping.setAttributeValueInObject(target, value);
        }
    
public voidcopyInto(java.lang.Object source, java.lang.Object target)
Copy each attribute from one object into the other.

        copyInto(source, target, false);
    
public java.lang.ObjectcopyObject(java.lang.Object original, oracle.toplink.essentials.sessions.ObjectCopyingPolicy policy)
Return a copy of the object. This is NOT used for unit of work but for templatizing an object. The depth and primary key reseting are passed in.

        Object copy = policy.getCopies().get(original);
        if (copy != null) {
            return copy;
        }

        copy = instantiateClone(original, policy.getSession());
        policy.getCopies().put(original, copy);

        // PERF: Avoid synchronized enumerator as is concurrency bottleneck.
        List mappings = getCloningMappings();
        for (int index = 0; index < mappings.size(); index++) {
            ((DatabaseMapping)mappings.get(index)).buildCopy(copy, original, policy);
        }

        if (policy.shouldResetPrimaryKey() && (!(getDescriptor().isAggregateDescriptor() || getDescriptor().isAggregateCollectionDescriptor()))) {
            // Do not reset if any of the keys is mapped through a 1-1, i.e. back reference id has already changed.
            boolean hasOneToOne = false;
            for (Enumeration keyMappingsEnum = getPrimaryKeyMappings().elements();
                     keyMappingsEnum.hasMoreElements();) {
                if (((DatabaseMapping)keyMappingsEnum.nextElement()).isOneToOneMapping()) {
                    hasOneToOne = true;
                }
            }
            if (!hasOneToOne) {
                for (Enumeration keyMappingsEnum = getPrimaryKeyMappings().elements();
                         keyMappingsEnum.hasMoreElements();) {
                    DatabaseMapping mapping = (DatabaseMapping)keyMappingsEnum.nextElement();

                    // Only null out direct mappings, as others will be nulled in the respective objects.
                    if (mapping.isDirectToFieldMapping()) {
                        Object nullValue = ((AbstractDirectMapping)mapping).getAttributeValue(null, policy.getSession());
                        mapping.setAttributeValueInObject(copy, nullValue);
                    } else if (mapping.isTransformationMapping()) {
                        mapping.setAttributeValueInObject(copy, null);
                    }
                }
            }
        }

        // PERF: Avoid events if no listeners.
        if (getDescriptor().getEventManager().hasAnyEventListeners()) {
            oracle.toplink.essentials.descriptors.DescriptorEvent event = new oracle.toplink.essentials.descriptors.DescriptorEvent(copy);
            event.setSession(policy.getSession());
            event.setOriginalObject(original);
            event.setEventCode(DescriptorEventManager.PostCloneEvent);
            getDescriptor().getEventManager().executeEvent(event);
        }

        return copy;
    
protected voidcopyQueryInfoToCacheKey(CacheKey cacheKey, ObjectBuildingQuery query, oracle.toplink.essentials.internal.sessions.AbstractRecord databaseRow, oracle.toplink.essentials.internal.sessions.AbstractSession session, oracle.toplink.essentials.descriptors.ClassDescriptor concreteDescriptor)
Initialize a cache key. Called by buildObject and now also by buildWorkingCopyCloneFromRow.

        //CR #4365 - used to prevent infinit recursion on refresh object cascade all
        cacheKey.setLastUpdatedQueryId(query.getQueryId());

        if (concreteDescriptor.usesOptimisticLocking()) {
            OptimisticLockingPolicy policy = concreteDescriptor.getOptimisticLockingPolicy();
            Object cacheValue = policy.getValueToPutInCache(databaseRow, session);

            //register the object into the IM and set the write lock object
            cacheKey.setWriteLockValue(cacheValue);
        }
        cacheKey.setReadTime(query.getExecutionTime());
    
public ObjectChangeSetcreateObjectChangeSet(java.lang.Object clone, UnitOfWorkChangeSet uowChangeSet, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Used by the ObjectBuilder to create an ObjectChangeSet for the specified clone object

return
oracle.toplink.essentials.internal.sessions.ObjectChangeSet the newly created changeSet representing the clone object
param
clone java.lang.Object the object to convert to a changeSet
param
uowChangeSet oracle.toplink.essentials.internal.sessions.UnitOfWorkChangeSet the owner of this changeSet

        boolean isNew = ((UnitOfWorkImpl)session).isObjectNew(clone);
        return createObjectChangeSet(clone, uowChangeSet, isNew, session);
    
public ObjectChangeSetcreateObjectChangeSet(java.lang.Object clone, UnitOfWorkChangeSet uowChangeSet, boolean isNew, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Used by the ObjectBuilder to create an ObjectChangeSet for the specified clone object

return
oracle.toplink.essentials.internal.sessions.ObjectChangeSet the newly created changeSet representing the clone object
param
clone java.lang.Object the object to convert to a changeSet
param
uowChangeSet oracle.toplink.essentials.internal.sessions.UnitOfWorkChangeSet the owner of this changeSet
param
isNew boolean signifies if the clone object is a new object.

        ObjectChangeSet changes = (ObjectChangeSet)uowChangeSet.getObjectChangeSetForClone(clone);
        if (changes == null) {
            if (getDescriptor().isAggregateDescriptor()) {
                changes = new AggregateObjectChangeSet(new Vector(0), getDescriptor().getJavaClass(), clone, uowChangeSet, isNew);
            } else {
                changes = new ObjectChangeSet(extractPrimaryKeyFromObject(clone, session), getDescriptor().getJavaClass(), clone, uowChangeSet, isNew);
            }
            changes.setIsAggregate(getDescriptor().isAggregateDescriptor() || getDescriptor().isAggregateCollectionDescriptor());
            uowChangeSet.addObjectChangeSetForIdentity(changes, clone);
        }
        return changes;
    
public voidcreatePrimaryKeyExpression(oracle.toplink.essentials.internal.sessions.AbstractSession session)
Creates and stores primary key expression.

        Expression expression = null;
        Expression builder = new ExpressionBuilder();
        Expression subExp1;
        Expression subExp2;
        Expression subExpression;
        List primaryKeyFields = getDescriptor().getPrimaryKeyFields();

        for (int index = 0; index < primaryKeyFields.size(); index++) {
            DatabaseField primaryKeyField = (DatabaseField)primaryKeyFields.get(index);
            subExp1 = builder.getField(primaryKeyField);
            subExp2 = builder.getParameter(primaryKeyField);
            subExpression = subExp1.equal(subExp2);

            if (expression == null) {
                expression = subExpression;
            } else {
                expression = expression.and(subExpression);
            }
        }

        setPrimaryKeyExpression(expression);
    
public oracle.toplink.essentials.internal.sessions.AbstractRecordcreateRecord()
Create a new row/record for the object builder. This allows subclasses to define different record types.

        return new DatabaseRecord();
    
public oracle.toplink.essentials.internal.sessions.AbstractRecordcreateRecord(int size)
Create a new row/record for the object builder. This allows subclasses to define different record types.

        return new DatabaseRecord(size);
    
public java.util.VectorextractPrimaryKeyFromExpression(boolean requiresExactMatch, Expression expression, oracle.toplink.essentials.internal.sessions.AbstractRecord translationRow, oracle.toplink.essentials.internal.sessions.AbstractSession session)
Return the row with primary keys and their values from the given expression.

        AbstractRecord primaryKeyRow = createRecord(getPrimaryKeyMappings().size());

        //put the curent session onthe expression builder for use later store current session incase
        //it is required at a later stage
        AbstractSession oldSession = expression.getBuilder().getSession();
        expression.getBuilder().setSession(session.getRootSession(null));
        // Get all the field & values from expression.
        boolean isValid = expression.extractPrimaryKeyValues(requiresExactMatch, getDescriptor(), primaryKeyRow, translationRow);
        if (requiresExactMatch && (!isValid)) {
            return null;
        }

        // Check that the sizes match.
        if (primaryKeyRow.size() != getDescriptor().getPrimaryKeyFields().size()) {
            return null;
        }

        return extractPrimaryKeyFromRow(primaryKeyRow, session);
    
public java.util.VectorextractPrimaryKeyFromObject(java.lang.Object domainObject, oracle.toplink.essentials.internal.sessions.AbstractSession session)
Extract primary key attribute values from the domainObject.

        // Allow for inheritance, the concrete descriptor must always be used.
        if (getDescriptor().hasInheritance() && (domainObject.getClass() != getDescriptor().getJavaClass()) && (!domainObject.getClass().getSuperclass().equals(getDescriptor().getJavaClass()))) {
            return session.getDescriptor(domainObject).getObjectBuilder().extractPrimaryKeyFromObject(domainObject, session);
        } else {
            List primaryKeyFields = getDescriptor().getPrimaryKeyFields();
            Vector primaryKeyValues = new Vector(primaryKeyFields.size());

            // PERF: optimize simple case of direct mapped singleton primary key.
            if (getDescriptor().hasSimplePrimaryKey()) {
                // PERF: use index not enumeration			
                for (int index = 0; index < getPrimaryKeyMappings().size(); index++) {
                    AbstractDirectMapping mapping = (AbstractDirectMapping)getPrimaryKeyMappings().get(index);
                    Object keyValue = mapping.valueFromObject(domainObject, (DatabaseField)primaryKeyFields.get(index), session);
                    primaryKeyValues.add(keyValue);
                }
            } else {
                AbstractRecord databaseRow = createRecord(getPrimaryKeyMappings().size());

                // PERF: use index not enumeration			
                for (int index = 0; index < getPrimaryKeyMappings().size(); index++) {
                    DatabaseMapping mapping = (DatabaseMapping)getPrimaryKeyMappings().get(index);

                    // Primary key mapping may be null for aggregate collection.
                    if (mapping != null) {
                        mapping.writeFromObjectIntoRow(domainObject, databaseRow, session);
                    }
                }

                // PERF: use index not enumeration			
                for (int index = 0; index < primaryKeyFields.size(); index++) {
                    // Ensure that the type extracted from the object is the same type as in the descriptor,
                    // the main reason for this is that 1-1 can optimize on vh by getting from the row as the row-type.
                    Class classification = (Class)getPrimaryKeyClassifications().get(index);
                    Object value = databaseRow.get((DatabaseField)primaryKeyFields.get(index));

                    // CR2114 following line modified; domainObject.getClass() passed as an argument
                    primaryKeyValues.addElement(session.getPlatform(domainObject.getClass()).convertObject(value, classification));
                }
            }

            return primaryKeyValues;
        }
    
public java.util.VectorextractPrimaryKeyFromRow(oracle.toplink.essentials.internal.sessions.AbstractRecord databaseRow, oracle.toplink.essentials.internal.sessions.AbstractSession session)
Extract primary key values from the specified row. null is returned if the row does not contain the key.

        List primaryKeyFields = getDescriptor().getPrimaryKeyFields();
        Vector primaryKeyValues = new Vector(primaryKeyFields.size());

        // PERF: use index not enumeration
        for (int index = 0; index < primaryKeyFields.size(); index++) {
            DatabaseField field = (DatabaseField)primaryKeyFields.get(index);

            // Ensure that the type extracted from the row is the same type as in the object.
            Class classification = (Class)getPrimaryKeyClassifications().get(index);
            Object value = databaseRow.get(field);
            if (value != null) {
                primaryKeyValues.addElement(session.getPlatform(getDescriptor().getJavaClass()).convertObject(value, classification));
            } else {
                return null;
            }
        }

        return primaryKeyValues;
    
public oracle.toplink.essentials.internal.sessions.AbstractRecordextractPrimaryKeyRowFromExpression(Expression expression, oracle.toplink.essentials.internal.sessions.AbstractRecord translationRow, oracle.toplink.essentials.internal.sessions.AbstractSession session)
Return the row with primary keys and their values from the given expression.

        AbstractRecord primaryKeyRow = createRecord(getPrimaryKeyMappings().size());

        //put the curent session onthe expression builder for use later store current session incase
        //it is required at a later stage
        AbstractSession oldSession = expression.getBuilder().getSession();
        expression.getBuilder().setSession(session.getRootSession(null));
        // Get all the field & values from expression	
        boolean isValid = expression.extractPrimaryKeyValues(true, getDescriptor(), primaryKeyRow, translationRow);
        expression.getBuilder().setSession(session.getRootSession(null));
        if (!isValid) {
            return null;
        }

        // Check that the sizes match up 
        if (primaryKeyRow.size() != getDescriptor().getPrimaryKeyFields().size()) {
            return null;
        }

        return primaryKeyRow;
    
public oracle.toplink.essentials.internal.sessions.AbstractRecordextractPrimaryKeyRowFromObject(java.lang.Object domainObject, oracle.toplink.essentials.internal.sessions.AbstractSession session)
Extract primary key attribute values from the domainObject.

        AbstractRecord databaseRow = createRecord(getPrimaryKeyMappings().size());

        // PERF: use index not enumeration.
        for (int index = 0; index < getPrimaryKeyMappings().size(); index++) {
            ((DatabaseMapping)getPrimaryKeyMappings().get(index)).writeFromObjectIntoRow(domainObject, databaseRow, session);
        }

        // PERF: optimize simple primary key case, no need to remap.
        if (getDescriptor().hasSimplePrimaryKey()) {
            return databaseRow;
        }
        AbstractRecord primaryKeyRow = createRecord(getPrimaryKeyMappings().size());
        List primaryKeyFields = getDescriptor().getPrimaryKeyFields();
        for (int index = 0; index < primaryKeyFields.size(); index++) {
            // Ensure that the type extracted from the object is the same type as in the descriptor,
            // the main reason for this is that 1-1 can optimize on vh by getting from the row as the row-type.
            Class classification = (Class)getPrimaryKeyClassifications().get(index);
            DatabaseField field = (DatabaseField)primaryKeyFields.get(index);
            Object value = databaseRow.get(field);
            primaryKeyRow.put(field, session.getPlatform(domainObject.getClass()).convertObject(value, classification));
        }

        return primaryKeyRow;
    
public java.lang.ObjectextractValueFromObjectForField(java.lang.Object domainObject, DatabaseField field, oracle.toplink.essentials.internal.sessions.AbstractSession session)
Extract the value of the primary key attribute from the specified object.

        // Allow for inheritance, the concrete descriptor must always be used.
        ClassDescriptor descriptor = null;//this variable will be assigned in the final

        if (getDescriptor().hasInheritance() && (domainObject.getClass() != getDescriptor().getJavaClass()) && ((descriptor = session.getDescriptor(domainObject)).getJavaClass() != getDescriptor().getJavaClass())) {
            return descriptor.getObjectBuilder().extractValueFromObjectForField(domainObject, field, session);
        } else {
            DatabaseMapping mapping = getMappingForField(field);
            if (mapping == null) {
                throw DescriptorException.missingMappingForField(field, getDescriptor());
            }

            return mapping.valueFromObject(domainObject, field, session);
        }
    
public DatabaseMappinggetBaseMappingForField(DatabaseField databaseField)
Return the base mapping for the given DatabaseField.

        DatabaseMapping mapping = getMappingForField(databaseField);

        // Drill down through the mappings until we get the direct mapping to the databaseField.	
        while (mapping.isAggregateObjectMapping()) {
            mapping = ((AggregateObjectMapping)mapping).getReferenceDescriptor().getObjectBuilder().getMappingForField(databaseField);
        }
        return mapping;
    
public java.lang.ObjectgetBaseValueForField(DatabaseField databaseField, java.lang.Object domainObject)
Return the base value that is mapped to for given field.

        Object valueIntoObject = domainObject;
        DatabaseMapping mapping = getMappingForField(databaseField);

        // Drill down through the aggregate mappings to get to the direct to field mapping.
        while (mapping.isAggregateObjectMapping()) {
            valueIntoObject = mapping.getAttributeValueFromObject(valueIntoObject);
            mapping = ((AggregateMapping)mapping).getReferenceDescriptor().getObjectBuilder().getMappingForField(databaseField);
        }
        return mapping.getAttributeValueFromObject(valueIntoObject);
    
public java.util.ListgetCloningMappings()
PERF: Return all mappings that require cloning. This allows for simple directs to be avoided when using clone copying.

        return cloningMappings;
    
public oracle.toplink.essentials.descriptors.ClassDescriptorgetDescriptor()
Return the descriptor

        return descriptor;
    
public java.lang.ClassgetFieldClassification(DatabaseField fieldToClassify)
INTERNAL: Return the classifiction for the field contained in the mapping. This is used to convert the row value to a consistent java value.

        DatabaseMapping mapping = getMappingForField(fieldToClassify);
        if (mapping == null) {
            // Means that the mapping is read-only or the classification is unknown,
            // this is normally not an issue as the classification is only really used for primary keys
            // and only when the database type can be different and not polymorphic than the object type.
            return null;
        }

        return mapping.getFieldClassification(fieldToClassify);
    
public DatabaseFieldgetFieldForQueryKeyName(java.lang.String name)
Return the field used for the query key name.

        QueryKey key = getDescriptor().getQueryKeyNamed(name);
        if (key == null) {
            DatabaseMapping mapping = getMappingForAttributeName(name);
            if (mapping == null) {
                return null;
            }
            if (mapping.getFields().isEmpty()) {
                return null;
            }
            return (DatabaseField)mapping.getFields().firstElement();
        }
        if (key.isDirectQueryKey()) {
            return ((DirectQueryKey)key).getField();
        }
        return null;
    
public java.util.VectorgetJoinedAttributes()
INTERNAL: Answers the attributes which are always joined to the original query on reads.

        return joinedAttributes;
    
public DatabaseMappinggetMappingForAttributeName(java.lang.String name)
Return the mapping for the specified attribute name.

        return getMappingsByAttribute().get(name);
    
public DatabaseMappinggetMappingForField(DatabaseField field)
Return al the mapping for the specified field.

        return getMappingsByField().get(field);
    
protected java.util.MapgetMappingsByAttribute()
Return all the mapping to attribute associations

        return mappingsByAttribute;
    
public java.util.MapgetMappingsByField()
INTERNAL: Return all the mapping to field associations

        return mappingsByField;
    
protected java.util.VectorgetNonPrimaryKeyMappings()
Return the non primary key mappings.

        return nonPrimaryKeyMappings;
    
public java.lang.ObjectgetParentObjectForField(DatabaseField databaseField, java.lang.Object domainObject)
Return the base value that is mapped to for given field.

        Object valueIntoObject = domainObject;
        DatabaseMapping mapping = getMappingForField(databaseField);

        // Drill down through the aggregate mappings to get to the direct to field mapping.
        while (mapping.isAggregateObjectMapping()) {
            valueIntoObject = mapping.getAttributeValueFromObject(valueIntoObject);
            mapping = ((AggregateMapping)mapping).getReferenceDescriptor().getObjectBuilder().getMappingForField(databaseField);
        }
        return valueIntoObject;
    
public java.util.VectorgetPrimaryKeyClassifications()
Return primary key classifications. These are used to ensure a consistent type for the pk values.

        if (primaryKeyClassifications == null) {
            List primaryKeyFields = getDescriptor().getPrimaryKeyFields();
            Vector<Class> classifications = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(primaryKeyFields.size());

            for (int index = 0; index < primaryKeyFields.size(); index++) {
                DatabaseMapping mapping = (DatabaseMapping)getPrimaryKeyMappings().get(index);
                DatabaseField field = (DatabaseField)primaryKeyFields.get(index);
                if (mapping != null) {
                    classifications.add(Helper.getObjectClass(mapping.getFieldClassification(field)));
                } else {
                    classifications.add(null);
                }
                primaryKeyClassifications = classifications;
            }
        }
        return primaryKeyClassifications;
    
public ExpressiongetPrimaryKeyExpression()
Return the primary key expression

        return primaryKeyExpression;
    
public java.util.VectorgetPrimaryKeyMappings()
Return primary key mappings.

        return primaryKeyMappings;
    
public java.util.MapgetReadOnlyMappingsByField()
INTERNAL: Return all the read-only mapping to field associations

        return readOnlyMappingsByField;
    
public java.util.VectorgetReadOnlyMappingsForField(DatabaseField field)
Return all the read-only mapping for the specified field.

        return getReadOnlyMappingsByField().get(field);
    
public DatabaseFieldgetTargetFieldForQueryKeyName(java.lang.String queryKeyName)
INTERNAL: return a database field based on a query key name

        DatabaseMapping mapping = (DatabaseMapping)getMappingForAttributeName(queryKeyName);
        if ((mapping != null) && mapping.isDirectToFieldMapping()) {
            return ((AbstractDirectMapping)mapping).getField();
        }

        //mapping is either null or not direct to field.
        //check query keys
        QueryKey queryKey = getDescriptor().getQueryKeyNamed(queryKeyName);
        if ((queryKey != null) && queryKey.isDirectQueryKey()) {
            return ((DirectQueryKey)queryKey).getField();
        }

        //nothing found
        return null;
    
public booleanhasJoinedAttributes()
INTERNAL: Answers if any attributes are to be joined / returned in the same select statement.

        return (joinedAttributes != null);
    
public voidinitialize(oracle.toplink.essentials.internal.sessions.AbstractSession session)
Cache all the mappings by their attribute and fields.

        this.getMappingsByField().clear();
        this.getReadOnlyMappingsByField().clear();
        this.getMappingsByAttribute().clear();
        this.getCloningMappings().clear();

        for (Enumeration mappings = getDescriptor().getMappings().elements(); mappings.hasMoreElements();) {
            DatabaseMapping mapping = (DatabaseMapping)mappings.nextElement();

            // Add attribute to mapping association
            if (!mapping.isWriteOnly()) {
                getMappingsByAttribute().put(mapping.getAttributeName(), mapping);
            }
            
            if (mapping.isCloningRequired()) {
                getCloningMappings().add(mapping);
            }

            // Add field to mapping association
            for (Enumeration fields = mapping.getFields().elements(); fields.hasMoreElements(); ) {
                DatabaseField field = DatabaseField.class.cast(fields.nextElement());

                if (mapping.isReadOnly()) {
                    Vector mappingVector = (Vector) getReadOnlyMappingsByField().get(field);
    
                    if (mappingVector == null) {
                        mappingVector = NonSynchronizedVector.newInstance();
                        getReadOnlyMappingsByField().put(field, mappingVector);
                    }
    
                    mappingVector.add(mapping);
                } else {
                    if (mapping.isAggregateObjectMapping()) {
                        // For Embeddable class, we need to test read-only 
                        // status of individual fields in the embeddable.
                        ObjectBuilder aggregateObjectBuilder = AggregateObjectMapping.class.cast(mapping).getReferenceDescriptor().getObjectBuilder();
                        
                        // Look in the non-read-only fields mapping
                        DatabaseMapping aggregatedFieldMapping = aggregateObjectBuilder.getMappingForField(field);
    
                        if (aggregatedFieldMapping == null) { // mapping must be read-only
                            Vector mappingVector = (Vector) getReadOnlyMappingsByField().get(field);
                            
                            if (mappingVector == null) {
                                mappingVector = NonSynchronizedVector.newInstance();
                                getReadOnlyMappingsByField().put(field, mappingVector);
                            }
    
                            mappingVector.add(mapping);
                        } else {
                            getMappingsByField().put(field, mapping);
                        }
                    } else { // Not an embeddable mapping
                        if (getMappingsByField().containsKey(field)) {  
                            session.getIntegrityChecker().handleError(DescriptorException.multipleWriteMappingsForField(field.toString(), mapping));
                        } else {
                            getMappingsByField().put(field, mapping);
                        }
                    }
                }
            }
        }

        initializePrimaryKey(session);

        initializeJoinedAttributes();
    
public voidinitializeJoinedAttributes()
INTERNAL: Iterates through all one to one mappings and checks if any of them use joining.

By caching the result query execution in the case where there are no joined attributes can be improved.

        // For concurrency don't worry about doing this work twice, just make sure
        // if it happens don't add the same joined attributes twice.
        Vector<String> joinedAttributes = null;
        Vector mappings = getDescriptor().getMappings();
        for (int i = 0; i < mappings.size(); i++) {
            DatabaseMapping mapping = (DatabaseMapping)mappings.get(i);
            if (mapping.isOneToOneMapping() && (mapping.isRelationalMapping()) && ((OneToOneMapping)mapping).shouldUseJoining()) {
                if (joinedAttributes == null) {
                    joinedAttributes = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance();
                }
                joinedAttributes.add(mapping.getAttributeName());
            }
        }
        this.joinedAttributes = joinedAttributes;
    
public voidinitializePrimaryKey(oracle.toplink.essentials.internal.sessions.AbstractSession session)
Cache primary key and non primary key mappings.

        createPrimaryKeyExpression(session);

        List primaryKeyfields = getDescriptor().getPrimaryKeyFields();

        this.getPrimaryKeyMappings().clear();
        this.getNonPrimaryKeyMappings().clear();

        // This must be before because the scondary table primary key fields are registered after
        for (Iterator fields = getMappingsByField().keySet().iterator(); fields.hasNext();) {
            DatabaseField field = (DatabaseField)fields.next();
            if (!primaryKeyfields.contains(field)) {
                DatabaseMapping mapping = getMappingForField(field);
                if (!getNonPrimaryKeyMappings().contains(mapping)) {
                    getNonPrimaryKeyMappings().addElement(mapping);
                }
            }
        }
        List primaryKeyFields = getDescriptor().getPrimaryKeyFields();
        for (int index = 0; index < primaryKeyFields.size(); index++) {
            DatabaseField primaryKeyField = (DatabaseField)primaryKeyFields.get(index);
            DatabaseMapping mapping = getMappingForField(primaryKeyField);

            if ((mapping == null) && (!getDescriptor().isAggregateDescriptor()) && (!getDescriptor().isAggregateCollectionDescriptor())) {
                throw DescriptorException.noMappingForPrimaryKey(primaryKeyField, getDescriptor());
            }

            getPrimaryKeyMappings().addElement(mapping);
            if (mapping != null) {
                mapping.setIsPrimaryKeyMapping(true);
            }

            // Use the same mapping to map the additional table primary key fields.
            // This is required if someone trys to map to one of these fields.
            if (getDescriptor().hasMultipleTables() && (mapping != null)) {
                for (Map keyMapping : getDescriptor().getAdditionalTablePrimaryKeyFields().values()) {
                    DatabaseField secondaryField = (DatabaseField) keyMapping.get(primaryKeyField);

                    // This can be null in the custom multiple join case
                    if (secondaryField != null) {
                        getMappingsByField().put(secondaryField, mapping);

                        if (mapping.isAggregateObjectMapping()) {
                            // GF#1153,1391
                            // If AggregateObjectMapping contain primary keys and the descriptor has multiple tables
                            // AggregateObjectMapping should know the the primary key join columns (secondaryField here)
                            // to handle some cases properly
                            ((AggregateObjectMapping) mapping).addPrimaryKeyJoinField(primaryKeyField, secondaryField);
                        }
                    }
                }
            }
        }

        // PERF: compute if primary key is mapped through direct mappings,
        // to allow fast extraction.
        boolean hasSimplePrimaryKey = true;
        for (int index = 0; index < getPrimaryKeyMappings().size(); index++) {
            DatabaseMapping mapping = (DatabaseMapping)getPrimaryKeyMappings().get(index);

            // Primary key mapping may be null for aggregate collection.
            if ((mapping == null) || (!mapping.isDirectToFieldMapping())) {
                hasSimplePrimaryKey = false;
                break;
            }
        }
        getDescriptor().setHasSimplePrimaryKey(hasSimplePrimaryKey);
    
public java.lang.ObjectinstantiateClone(java.lang.Object domainObject, oracle.toplink.essentials.internal.sessions.AbstractSession session)
Returns the clone of the specified object. This is called only from unit of work. This only instatiates the clone instance, it does not clone the attributes, this allows the stub of the clone to be registered before cloning its parts.

        return getDescriptor().getCopyPolicy().buildClone(domainObject, session);
    
public java.lang.ObjectinstantiateWorkingCopyClone(java.lang.Object domainObject, oracle.toplink.essentials.internal.sessions.AbstractSession session)
Returns the clone of the specified object. This is called only from unit of work. The domainObject sent as parameter is always a copy from the parent of unit of work. bug 2612602 make a call to build a working clone. This will in turn call the copy policy to make a working clone. This allows for lighter and heavier clones to be created based on their use. this allows the stub of the clone to be registered before cloning its parts.

        return getDescriptor().getCopyPolicy().buildWorkingCopyClone(domainObject, session);
    
public java.lang.ObjectinstantiateWorkingCopyCloneFromRow(oracle.toplink.essentials.internal.sessions.AbstractRecord row, ObjectBuildingQuery query)
It is now possible to build working copy clones directly from rows.

An intermediary original is no longer needed.

This has ramifications to the copy policy and cmp, for clones are no longer built via cloning.

Instead the copy policy must in some cases not copy at all. this allows the stub of the clone to be registered before cloning its parts.

        if (query.isObjectLevelReadQuery()){ //for backward compat reasons cast this
            return getDescriptor().getCopyPolicy().buildWorkingCopyCloneFromRow(row, ((ObjectLevelReadQuery)query));
        }else{
            return getDescriptor().getCopyPolicy().buildWorkingCopyCloneFromRow(row, query);
        }
    
public booleanisPrimaryKeyMapping(DatabaseMapping mapping)

        return getPrimaryKeyMappings().contains(mapping);
    
public voiditerate(DescriptorIterator iterator)
INTERNAL: Perform the itteration opperation on the objects attributes through the mappings.

        // PERF: Avoid synchronized enumerator as is concurrency bottleneck.
        Vector mappings = getDescriptor().getMappings();
        int mappingsSize = mappings.size();
        for (int index = 0; index < mappingsSize; index++) {
            ((DatabaseMapping)mappings.get(index)).iterate(iterator);
        }
    
public voidmergeChangesIntoObject(java.lang.Object target, ObjectChangeSet changeSet, java.lang.Object source, MergeManager mergeManager)
INTERNAL: Merge changes between the objects, this merge algorthim is dependent on the merge manager.

        for (Enumeration changes = changeSet.getChanges().elements(); changes.hasMoreElements();) {
            ChangeRecord record = (ChangeRecord)changes.nextElement();

            //cr 4236, use ObjectBuilder getMappingForAttributeName not the Descriptor one because the
            // ObjectBuilder method is much more efficient.
            DatabaseMapping mapping = getMappingForAttributeName(record.getAttribute());
            mapping.mergeChangesIntoObject(target, record, source, mergeManager);
        }

        // PERF: Avoid events if no listeners.
        if (getDescriptor().getEventManager().hasAnyEventListeners()) {
            oracle.toplink.essentials.descriptors.DescriptorEvent event = new oracle.toplink.essentials.descriptors.DescriptorEvent(target);
            event.setSession(mergeManager.getSession());
            event.setOriginalObject(source);
            event.setChangeSet(changeSet);
            event.setEventCode(DescriptorEventManager.PostMergeEvent);
            getDescriptor().getEventManager().executeEvent(event);
        }
    
public voidmergeIntoObject(java.lang.Object target, boolean isUnInitialized, java.lang.Object source, MergeManager mergeManager)
INTERNAL: Merge the contents of one object into another, this merge algorthim is dependent on the merge manager. This merge also prevents the extra step of calculating the changes when it is not required.

        mergeIntoObject(target, isUnInitialized, source, mergeManager, false);
    
public voidmergeIntoObject(java.lang.Object target, boolean isUnInitialized, java.lang.Object source, MergeManager mergeManager, boolean cascadeOnly)
INTERNAL: Merge the contents of one object into another, this merge algorthim is dependent on the merge manager. This merge also prevents the extra step of calculating the changes when it is not required. If 'cascadeOnly' is true, only foreign reference mappings are merged.

        // cascadeOnly is introduced to optimize merge 
        // for GF#1139 Cascade merge operations to relationship mappings even if already registered
        
        // PERF: Avoid synchronized enumerator as is concurrency bottleneck.
        Vector mappings = getDescriptor().getMappings();
        for (int index = 0; index < mappings.size(); index++) {
            DatabaseMapping mapping = (DatabaseMapping)mappings.get(index);
            if(!cascadeOnly || mapping.isForeignReferenceMapping()){
                mapping.mergeIntoObject(target, isUnInitialized, source, mergeManager);
            }
        }

        // PERF: Avoid events if no listeners.
        if (getDescriptor().getEventManager().hasAnyEventListeners()) {
            oracle.toplink.essentials.descriptors.DescriptorEvent event = new oracle.toplink.essentials.descriptors.DescriptorEvent(target);
            event.setSession(mergeManager.getSession());
            event.setOriginalObject(source);
            event.setEventCode(DescriptorEventManager.PostMergeEvent);
            getDescriptor().getEventManager().executeEvent(event);
        }
    
public voidpopulateAttributesForClone(java.lang.Object original, java.lang.Object clone, oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl unitOfWork, oracle.toplink.essentials.internal.queryframework.JoinedAttributeManager joinedAttributeManager)
Clones the attributes of the specified object. This is called only from unit of work. The domainObject sent as parameter is always a copy from the parent of unit of work.

        // PERF: Avoid synchronized enumerator as is concurrency bottleneck.
        List mappings = getCloningMappings();
        for (int index = 0; index < mappings.size(); index++) {
            ((DatabaseMapping)mappings.get(index)).buildClone(original, clone, unitOfWork, joinedAttributeManager);
        }

        // PERF: Avoid events if no listeners.
        if (getDescriptor().getEventManager().hasAnyEventListeners()) {
            oracle.toplink.essentials.descriptors.DescriptorEvent event = new oracle.toplink.essentials.descriptors.DescriptorEvent(clone);
            event.setSession(unitOfWork);
            event.setOriginalObject(original);
            event.setEventCode(DescriptorEventManager.PostCloneEvent);
            getDescriptor().getEventManager().executeEvent(event);
        }
    
public voidrehashFieldDependancies(oracle.toplink.essentials.internal.sessions.AbstractSession session)
Rehash any hashtables based on fields. This is used to clone descriptors for aggregates, which hammer field names, it is probably better not to hammer the field name and this should be refactored.

        setMappingsByField(Helper.rehashMap(getMappingsByField()));
        setReadOnlyMappingsByField(Helper.rehashMap(getReadOnlyMappingsByField()));
        setPrimaryKeyMappings(oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(2));
        setNonPrimaryKeyMappings(oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(2));
        initializePrimaryKey(session);
    
private voidrevertFetchGroupData(java.lang.Object domainObject, oracle.toplink.essentials.descriptors.ClassDescriptor concreteDescriptor, CacheKey cacheKey, ObjectBuildingQuery query, oracle.toplink.essentials.internal.queryframework.JoinedAttributeManager joinManager, oracle.toplink.essentials.internal.sessions.AbstractRecord databaseRow, oracle.toplink.essentials.internal.sessions.AbstractSession session)
Clean up the cached object data and only revert the fetch group data back to the cached object.

        //the cached object is either invalidated, or staled as the version is newer, or a refresh is explicitly set on the query.
        //clean all data of the cache object.
        concreteDescriptor.getFetchGroupManager().reset(domainObject);
        //read in the fetch group data only
        concreteDescriptor.getObjectBuilder().buildAttributesIntoObject(domainObject, databaseRow, query, joinManager, false);
        //set fetch group refrence to the cached object
        concreteDescriptor.getFetchGroupManager().setObjectFetchGroup(domainObject, query.getFetchGroup());
        //set refresh on fetch group
        concreteDescriptor.getFetchGroupManager().setRefreshOnFetchGroupToObject(domainObject, (query.shouldRefreshIdentityMapResult() || concreteDescriptor.shouldAlwaysRefreshCache()));
        //set query id to prevent infinite recursion on refresh object cascade all
        cacheKey.setLastUpdatedQueryId(query.getQueryId());
        //register the object into the IM and set the write lock object if applied.
        if (concreteDescriptor.usesOptimisticLocking()) {
            OptimisticLockingPolicy policy = concreteDescriptor.getOptimisticLockingPolicy();
            cacheKey.setWriteLockValue(policy.getValueToPutInCache(databaseRow, session));
        }
        cacheKey.setReadTime(query.getExecutionTime());
        //validate the cached object
        cacheKey.setInvalidationState(CacheKey.CHECK_INVALIDATION_POLICY);
    
public voidsetDescriptor(oracle.toplink.essentials.descriptors.ClassDescriptor aDescriptor)
Set the descriptor.

        descriptor = aDescriptor;
    
protected voidsetMappingsByAttribute(java.util.Map theAttributeMappings)
All the mappings and their respective attribute associations are cached for performance improvement.

        mappingsByAttribute = theAttributeMappings;
    
public voidsetMappingsByField(java.util.Map theFieldMappings)
INTERNAL: All the mappings and their respective field associations are cached for performance improvement.

        mappingsByField = theFieldMappings;
    
protected voidsetNonPrimaryKeyMappings(java.util.Vector theNonPrimaryKeyMappings)
The non primary key mappings are cached to improve performance.

        nonPrimaryKeyMappings = theNonPrimaryKeyMappings;
    
protected voidsetPrimaryKeyClassifications(java.util.Vector primaryKeyClassifications)
Set primary key classifications. These are used to ensure a consistent type for the pk values.

        this.primaryKeyClassifications = primaryKeyClassifications;
    
public voidsetPrimaryKeyExpression(Expression criteria)
The primary key expression is cached to improve performance.

        primaryKeyExpression = criteria;
    
protected voidsetPrimaryKeyMappings(java.util.Vector thePrimaryKeyMappings)
The primary key mappings are cached to improve performance.

        primaryKeyMappings = thePrimaryKeyMappings;
    
public voidsetReadOnlyMappingsByField(java.util.Map theReadOnlyFieldMappings)
INTERNAL: All the read-only mappings and their respective field associations are cached for performance improvement.

        readOnlyMappingsByField = theReadOnlyFieldMappings;
    
public java.lang.StringtoString()

        return Helper.getShortClassName(getClass()) + "(" + getDescriptor().toString() + ")";
    
public java.lang.ObjectunwrapObject(java.lang.Object proxy, oracle.toplink.essentials.internal.sessions.AbstractSession session)
Unwrap the object if required. This is used for the wrapper policy support and EJB.

        if (proxy == null) {
            return null;
        }

        // Check if already unwrapped.
        if ((getDescriptor().getJavaClass() == proxy.getClass()) || !getDescriptor().hasWrapperPolicy() || !getDescriptor().getWrapperPolicy().isWrapped(proxy)) {
            return proxy;
        }

        // Allow for inheritance, the concrete wrapper must always be used.
        if (getDescriptor().hasInheritance() && (getDescriptor().getInheritancePolicy().hasChildren())) {
            ClassDescriptor descriptor = session.getDescriptor(proxy);
            if (descriptor != getDescriptor()) {
                return descriptor.getObjectBuilder().unwrapObject(proxy, session);
            }
        }

        if (getDescriptor().hasWrapperPolicy()) {
            return getDescriptor().getWrapperPolicy().unwrapObject(proxy, session);
        } else {
            return proxy;
        }
    
public voidvalidate(oracle.toplink.essentials.internal.sessions.AbstractSession session)
Validates the object builder. This is done once the object builder initialized and descriptor fires this validation.

        if (getDescriptor().usesSequenceNumbers()) {
            if (getMappingForField(getDescriptor().getSequenceNumberField()) == null) {
                throw DescriptorException.mappingForSequenceNumberField(getDescriptor());
            }
        }
    
public booleanverifyDelete(java.lang.Object object, oracle.toplink.essentials.internal.sessions.AbstractSession session)
Verify that an object has been deleted from the database. An object can span multiple tables. A query is performed on each of these tables using the primary key values of the object as the selection criteria. If the query returns a result then the object has not been deleted from the database. If no result is returned then each of the mappings is asked to verify that the object has been deleted. If all mappings answer true then the result is true.

        AbstractRecord translationRow = buildRowForTranslation(object, session);

        // If a call is used generated SQL cannot be executed, the call must be used.
        if ((getDescriptor().getQueryManager().getReadObjectQuery() != null) && getDescriptor().getQueryManager().getReadObjectQuery().isCallQuery()) {
            Object result = session.readObject(object);
            if (result != null) {
                return false;
            }
        } else {
            for (Enumeration tables = getDescriptor().getTables().elements();
                     tables.hasMoreElements();) {
                DatabaseTable table = (DatabaseTable)tables.nextElement();

                SQLSelectStatement sqlStatement = new SQLSelectStatement();
                sqlStatement.addTable(table);
                if (table == getDescriptor().getTables().firstElement()) {
                    sqlStatement.setWhereClause((Expression)getPrimaryKeyExpression().clone());
                } else {
                    sqlStatement.setWhereClause(buildPrimaryKeyExpression(table));
                }
                DatabaseField all = new DatabaseField("*");
                all.setTable(table);
                sqlStatement.addField(all);
                sqlStatement.normalize(session, null);

                DataReadQuery dataReadQuery = new DataReadQuery();
                dataReadQuery.setSQLStatement(sqlStatement);
                dataReadQuery.setSessionName(getDescriptor().getSessionName());

                // execute the query and check if there is a valid result
                Vector queryResults = (Vector)session.executeQuery(dataReadQuery, translationRow);
                if (!queryResults.isEmpty()) {
                    return false;
                }
            }
        }

        // now ask each of the mappings to verify that the object has been deleted.
        for (Enumeration mappings = getDescriptor().getMappings().elements();
                 mappings.hasMoreElements();) {
            DatabaseMapping mapping = (DatabaseMapping)mappings.nextElement();

            if (!mapping.verifyDelete(object, session)) {
                return false;
            }
        }

        return true;
    
public java.lang.ObjectwrapObject(java.lang.Object implementation, oracle.toplink.essentials.internal.sessions.AbstractSession session)
Wrap the object if required. This is used for the wrapper policy support and EJB.

        if (implementation == null) {
            return null;
        }

        // Check if already wrapped.
        if (!getDescriptor().hasWrapperPolicy() || getDescriptor().getWrapperPolicy().isWrapped(implementation)) {
            return implementation;
        }

        // Allow for inheritance, the concrete wrapper must always be used.
        if (getDescriptor().hasInheritance() && getDescriptor().getInheritancePolicy().hasChildren() && (implementation.getClass() != getDescriptor().getJavaClass())) {
            ClassDescriptor descriptor = session.getDescriptor(implementation);
            if(descriptor != getDescriptor()) {
                return descriptor.getObjectBuilder().wrapObject(implementation, session);
            }
        }
        if (getDescriptor().hasWrapperPolicy()) {
            return getDescriptor().getWrapperPolicy().wrapObject(implementation, session);
        } else {
            return implementation;
        }