FileDocCategorySizeDatePackage
DirectCollectionMapping.javaAPI DocGlassfish v2 API66519Tue May 22 16:54:46 BST 2007oracle.toplink.essentials.mappings

DirectCollectionMapping

public class DirectCollectionMapping extends CollectionMapping implements RelationalMapping

Purpose: This mapping is used to store a collection of simple types (String, Number, Date, etc.) into a single table. The table must store the value and a foreign key to the source object. A converter can be used if the desired object type and the data type do not match.

see
Converter
see
ObjectTypeConverter
see
TypeConversionConverter
see
SerializedObjectConverter
author
Sati
since
TOPLink/Java 1.0

Fields Summary
protected static final String
Delete
Used for data modification events.
protected static final String
Insert
protected static final String
DeleteAll
protected Converter
valueConverter
Allows user defined conversion between the object value and the database value.
protected transient DatabaseTable
referenceTable
Stores the reference table
protected transient DatabaseField
directField
The direct field name is converted and stored
protected transient Vector
sourceKeyFields
protected transient Vector
referenceKeyFields
protected transient DataModifyQuery
insertQuery
Used for insertion for m-m and dc, not used in 1-m.
protected transient ModifyQuery
changeSetDeleteQuery
Used for deletion when ChangeSets are used
protected transient boolean
hasCustomDeleteQuery
protected transient boolean
hasCustomInsertQuery
Constructors Summary
public DirectCollectionMapping()
PUBLIC: Default constructor.


            
      
        this.insertQuery = new DataModifyQuery();
        this.sourceKeyFields = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(1);
        this.referenceKeyFields = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(1);
        this.selectionQuery = new DirectReadQuery();
        this.hasCustomInsertQuery = false;
        this.isPrivateOwned = true;
    
Methods Summary
public voidaddReferenceKeyField(DatabaseField referenceForeignKeyField, DatabaseField sourcePrimaryKeyField)
PUBLIC: Add the reference key field. This is used for composite reference keys. This is the foreign key field in the direct table referencing the primary key of the source object. Both the reference field and the source field that it references must be provided.

        getSourceKeyFields().addElement(sourcePrimaryKeyField);
        getReferenceKeyFields().addElement(referenceForeignKeyField);
    
public voidaddReferenceKeyFieldName(java.lang.String referenceForeignKeyFieldName, java.lang.String sourcePrimaryKeyFieldName)
PUBLIC: Add the name of the reference key field. This is used for composite reference keys. This is the foreign key field in the direct table referencing the primary key of the source object. Both the reference field name and the name of the source field that it references must be provided.

        addReferenceKeyField(new DatabaseField(referenceForeignKeyFieldName), new DatabaseField(sourcePrimaryKeyFieldName));
    
public voidaddToCollectionChangeRecord(java.lang.Object newKey, java.lang.Object newValue, ObjectChangeSet objectChangeSet, oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl uow)
INTERNAL: Add a new value and its change set to the collection change record. This is used by attribute change tracking.

        if (newValue == null) {
            newValue = DirectCollectionChangeRecord.Null;
        }
        ClassDescriptor descriptor;
        DirectCollectionChangeRecord collectionChangeRecord = (DirectCollectionChangeRecord)objectChangeSet.getChangesForAttributeNamed(this.getAttributeName());
        if (collectionChangeRecord == null) {
            collectionChangeRecord = new DirectCollectionChangeRecord(objectChangeSet);
            collectionChangeRecord.setAttribute(getAttributeName());
            collectionChangeRecord.setMapping(this);
            objectChangeSet.addChange(collectionChangeRecord);
            Object collection = getRealAttributeValueFromObject(objectChangeSet.getUnitOfWorkClone(), uow);
            collectionChangeRecord.storeDatabaseCounts(collection, getContainerPolicy(), uow);
        }
        collectionChangeRecord.addAdditionChange(newValue, new Integer(1));
    
public voidbuildCopy(java.lang.Object copy, java.lang.Object original, oracle.toplink.essentials.sessions.ObjectCopyingPolicy policy)
INTERNAL: Copy of the attribute of the object. This is NOT used for unit of work but for templatizing an object.

        Object attributeValue = getRealCollectionAttributeValueFromObject(original, policy.getSession());
        attributeValue = getContainerPolicy().cloneFor(attributeValue);
        setRealAttributeValueInObject(copy, attributeValue);
    
protected java.lang.ObjectbuildElementClone(java.lang.Object element, oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl unitOfWork, boolean isExisting)
INTERNAL: Clone the element, if necessary. DirectCollections hold on to objects that do not have Descriptors (e.g. int, String). These objects do not need to be cloned, unless they use a converter - they are immutable.

        Object cloneValue = element;
        if ((getValueConverter() != null) && getValueConverter().isMutable()) {
            cloneValue = getValueConverter().convertDataValueToObjectValue(getValueConverter().convertObjectValueToDataValue(cloneValue, unitOfWork), unitOfWork);
        }
        return cloneValue;
    
public voidcalculateDeferredChanges(ChangeRecord changeRecord, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Used by AttributeLevelChangeTracking to update a changeRecord with calculated changes as apposed to detected changes. If an attribute can not be change tracked it's changes can be detected through this process.

        DirectCollectionChangeRecord collectionRecord = (DirectCollectionChangeRecord) changeRecord;
        compareCollectionsForChange(collectionRecord.getOriginalCollection(), collectionRecord.getLatestCollection(), collectionRecord, session);
    
public voidcascadePerformRemoveIfRequired(java.lang.Object object, oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl uow, IdentityHashtable visitedObjects)
INTERNAL: Cascade perform delete through mappings that require the cascade

        //as this mapping type references primitive objects this method does not apply
    
public voidcascadeRegisterNewIfRequired(java.lang.Object object, oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl uow, IdentityHashtable visitedObjects)
INTERNAL: Cascade registerNew for Create through mappings that require the cascade

        //as this mapping type references primitive objects this method does not apply
    
public java.lang.Objectclone()
INTERNAL: The mapping clones itself to create deep copy.

        DirectCollectionMapping clone = (DirectCollectionMapping)super.clone();

        clone.setSourceKeyFields(cloneFields(getSourceKeyFields()));
        clone.setReferenceKeyFields(cloneFields(getReferenceKeyFields()));

        return clone;
    
public voidcompareCollectionsForChange(java.lang.Object oldCollection, java.lang.Object newCollection, ChangeRecord changeRecord, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: This method is used to calculate the differences between two collections.

        ContainerPolicy cp = getContainerPolicy();
        int numberOfNewNulls = 0;

        HashMap originalKeyValues = new HashMap(10);
        HashMap cloneKeyValues = new HashMap(10);
        
        if (oldCollection != null){
            Object backUpIter = cp.iteratorFor(oldCollection);

            while (cp.hasNext(backUpIter)) {// Make a lookup of the objects
                Object secondObject = cp.next(backUpIter, session);

                // For CR#2258/CR#2378 handle null values inserted in a collection.
                if (secondObject == null) {
                    numberOfNewNulls--;
                } else {
                    Integer count = (Integer)originalKeyValues.get(secondObject);
                    if (count == null) {
                        originalKeyValues.put(secondObject, new Integer(1));
                    } else {
                        originalKeyValues.put(secondObject, new Integer(count.intValue() + 1));
                    }
                }
            }
        }
        // should a removal occur this is the original count of objects on the database.
        // this value is used to determine how many objects to re-insert after the delete as a
        // delete will delete all of the objects not just one.
        HashMap databaseCount = (HashMap)originalKeyValues.clone();
        int databaseNullCount = Math.abs(numberOfNewNulls);

        if (newCollection != null){
            Object cloneIter = cp.iteratorFor(newCollection);

            /* The following code is used to compare objects in a direct collection.
               Because objects in a direct collection are primitives and may be the same object
               the following code must count the number of instances in the collection not just the
               existence of an object.
            */
            while (cp.hasNext(cloneIter)) {//Compare them with the objects from the clone
                Object firstObject = cp.next(cloneIter, session);
    
                // For CR#2258/CR#2378 handle null values inserted in a collection.
                if (firstObject == null) {
                    numberOfNewNulls++;
                } else {
                    Integer count = (Integer)originalKeyValues.get(firstObject);
                    if (count == null) {//the object was not in the backup
                        Integer cloneCount = (Integer)cloneKeyValues.get(firstObject);
    
                        //Add it to the additions hashtable
                        if (cloneCount == null) {
                            cloneKeyValues.put(firstObject, new Integer(1));
                        } else {
                            cloneKeyValues.put(firstObject, new Integer(cloneCount.intValue() + 1));
                        }
                    } else if (count.intValue() == 1) {
                        //There is only one object so remove the whole reference
                        originalKeyValues.remove(firstObject);
                    } else {
                        originalKeyValues.put(firstObject, new Integer(count.intValue() - 1));
                    }
                }
            }
        }        
        if (cloneKeyValues.isEmpty() && originalKeyValues.isEmpty() && (numberOfNewNulls == 0) && (!changeRecord.getOwner().isNew())) {
            return;
        }
        ((DirectCollectionChangeRecord)changeRecord).addAdditionChange(cloneKeyValues, databaseCount);
        ((DirectCollectionChangeRecord)changeRecord).addRemoveChange(originalKeyValues, databaseCount);
        //For CR#2258, produce a changeRecord which reflects the addition and removal of null values.
        if (numberOfNewNulls != 0) {
            Vector changeList = null;
            ((DirectCollectionChangeRecord)changeRecord).getCommitAddMap().put(DirectCollectionChangeRecord.Null, new Integer(databaseNullCount));
            if (numberOfNewNulls > 0) {
                ((DirectCollectionChangeRecord)changeRecord).addAdditionChange(DirectCollectionChangeRecord.Null, new Integer(numberOfNewNulls));
            } else {
                numberOfNewNulls *= -1;
                ((DirectCollectionChangeRecord)changeRecord).addRemoveChange(DirectCollectionChangeRecord.Null, new Integer(numberOfNewNulls));
            }
        }
    
public ChangeRecordcompareForChange(java.lang.Object clone, java.lang.Object backUp, ObjectChangeSet owner, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: This method compares the changes between two direct collections. Comparisons are made on equality not identity.

return
prototype.changeset.ChangeRecord

        Object cloneAttribute = null;
        Object backUpAttribute = null;
        int numberOfNewNulls = 0;

        ContainerPolicy cp = getContainerPolicy();

        cloneAttribute = getAttributeValueFromObject(clone);

        if ((cloneAttribute != null) && (!getIndirectionPolicy().objectIsInstantiated(cloneAttribute))) {
            return null;
        }

        Object cloneObjectCollection = getRealCollectionAttributeValueFromObject(clone, session);

        Object backUpCollection = null;

        if (!owner.isNew()) {
            backUpAttribute = getAttributeValueFromObject(backUp);

            if ((backUpAttribute == null) && (cloneAttribute == null)) {
                return null;
            }

            backUpCollection = getRealCollectionAttributeValueFromObject(backUp, session);
        }
        DirectCollectionChangeRecord changeRecord = new DirectCollectionChangeRecord(owner);
        changeRecord.setAttribute(getAttributeName());
        changeRecord.setMapping(this);
        compareCollectionsForChange(backUpCollection, cloneObjectCollection, changeRecord, session);
        if (changeRecord.hasChanges()){
            return changeRecord;
        }
        return null;
    
public booleancompareObjects(java.lang.Object firstObject, java.lang.Object secondObject, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Compare the attributes belonging to this mapping for the objects.

        Object firstCollection = getRealCollectionAttributeValueFromObject(firstObject, session);
        Object secondCollection = getRealCollectionAttributeValueFromObject(secondObject, session);
        ContainerPolicy containerPolicy = getContainerPolicy();

        if (containerPolicy.sizeFor(firstCollection) != containerPolicy.sizeFor(secondCollection)) {
            return false;
        }

        HashMap firstCounter = new HashMap();
        HashMap secondCounter = new HashMap();
        for (Object iter = containerPolicy.iteratorFor(firstCollection);containerPolicy.hasNext(iter);) {
            Object object = containerPolicy.next(iter, session);
            if (firstCounter.containsKey(object)){
                int count = ((Integer)firstCounter.get(object)).intValue();
                firstCounter.put(object, new Integer(++count));
            }else{
                firstCounter.put(object, new Integer(1));
            }
        }
        for (Object iter = containerPolicy.iteratorFor(secondCollection);containerPolicy.hasNext(iter);) {
            Object object = containerPolicy.next(iter, session);
            if (secondCounter.containsKey(object)){
                int count = ((Integer)secondCounter.get(object)).intValue();
                secondCounter.put(object, new Integer(++count));
            }else{
                secondCounter.put(object, new Integer(1));
            }
        }
        for (Iterator iterator = firstCounter.keySet().iterator(); iterator.hasNext();){
            Object object = iterator.next();
            
            if (!secondCounter.containsKey(object) || ( ((Integer)secondCounter.get(object)).intValue() != ((Integer)firstCounter.get(object)).intValue()) ) {
                return false;
            }else{
                iterator.remove();
                secondCounter.remove(object);
            }
        }
        if ( !firstCounter.isEmpty()  || !secondCounter.isEmpty() ) {
            return false;
        }
        return true;
    
public voidconvertClassNamesToClasses(java.lang.ClassLoader classLoader)
INTERNAL: Convert all the class-name-based settings in this mapping to actual class-based settings This method is implemented by subclasses as necessary.

param
classLoader

        super.convertClassNamesToClasses(classLoader);
        
        if (valueConverter != null) {
            if (valueConverter instanceof TypeConversionConverter){
                ((TypeConversionConverter)valueConverter).convertClassNamesToClasses(classLoader);
            } else if (valueConverter instanceof ObjectTypeConverter) {
                // To avoid 1.5 dependencies with the EnumTypeConverter check
                // against ObjectTypeConverter.
                ((ObjectTypeConverter) valueConverter).convertClassNamesToClasses(classLoader);
            }
        }
    
protected java.util.VectorextractKeyFromReferenceRow(oracle.toplink.essentials.internal.sessions.AbstractRecord row, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Extract the source primary key value from the reference direct row. Used for batch reading, most following same order and fields as in the mapping.

        Vector key = new Vector(getReferenceKeyFields().size());

        for (int index = 0; index < getReferenceKeyFields().size(); index++) {
            DatabaseField relationField = (DatabaseField)getReferenceKeyFields().elementAt(index);
            DatabaseField sourceField = (DatabaseField)getSourceKeyFields().elementAt(index);
            Object value = row.get(relationField);

            // Must ensure the classificatin to get a cache hit.
            try {
                value = session.getDatasourcePlatform().getConversionManager().convertObject(value, getDescriptor().getObjectBuilder().getFieldClassification(sourceField));
            } catch (ConversionException e) {
                throw ConversionException.couldNotBeConverted(this, getDescriptor(), e);
            }

            key.addElement(value);
        }

        return key;
    
protected java.util.VectorextractPrimaryKeyFromRow(oracle.toplink.essentials.internal.sessions.AbstractRecord row, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Extract the primary key value from the source row. Used for batch reading, most following same order and fields as in the mapping.

        Vector key = new Vector(getSourceKeyFields().size());

        for (Enumeration fieldEnum = getSourceKeyFields().elements(); fieldEnum.hasMoreElements();) {
            DatabaseField field = (DatabaseField)fieldEnum.nextElement();
            Object value = row.get(field);

            // Must ensure the classificatin to get a cache hit.
            try {
                value = session.getDatasourcePlatform().getConversionManager().convertObject(value, getDescriptor().getObjectBuilder().getFieldClassification(field));
            } catch (ConversionException e) {
                throw ConversionException.couldNotBeConverted(this, getDescriptor(), e);
            }

            key.addElement(value);
        }

        return key;
    
protected ModifyQuerygetDeleteQuery()

        if (changeSetDeleteQuery == null) {
            changeSetDeleteQuery = new DataModifyQuery();
        }
        return changeSetDeleteQuery;
    
public DatabaseFieldgetDirectField()
INTERNAL: Return the direct field. This is the field in the direct table to store the values.

        return directField;
    
public java.lang.StringgetDirectFieldName()
PUBLIC: Returns the name of the field name in the reference table.

        if (getDirectField() == null) {
            return null;
        }
        return getDirectField().getQualifiedName();
    
protected DataModifyQuerygetInsertQuery()

        return insertQuery;
    
public java.lang.ClassgetReferenceClass()
INTERNAL: This cannot be used with direct collection mappings.

        return null;
    
public java.lang.StringgetReferenceClassName()

        return null;
    
public oracle.toplink.essentials.descriptors.ClassDescriptorgetReferenceDescriptor()
INTERNAL: There is none on direct collection.

        return null;
    
public java.util.VectorgetReferenceKeyFieldNames()
INTERNAL: Return the reference key field names associated with the mapping. These are in-order with the sourceKeyFieldNames.

        Vector fieldNames = new Vector(getReferenceKeyFields().size());
        for (Enumeration fieldsEnum = getReferenceKeyFields().elements();
                 fieldsEnum.hasMoreElements();) {
            fieldNames.addElement(((DatabaseField)fieldsEnum.nextElement()).getQualifiedName());
        }

        return fieldNames;
    
public java.util.VectorgetReferenceKeyFields()
INTERNAL: Return the reference key fields.

        return referenceKeyFields;
    
public DatabaseTablegetReferenceTable()
INTERNAL: Return the direct table. This is the table to store the values.

        return referenceTable;
    
public java.lang.StringgetReferenceTableName()
PUBLIC: Returns the name of the reference table

        if (getReferenceTable() == null) {
            return null;
        }
        return getReferenceTable().getName();
    
public java.lang.StringgetReferenceTableQualifiedName()
PUBLIC: Returns the qualified name of the reference table

//CR#2407  
        if (getReferenceTable() == null) {
            return null;
        }
        return getReferenceTable().getQualifiedName();
    
public DatabaseMappinggetRelationshipPartner()
INTERNAL: Return the relationshipPartner mapping for this bi-directional mapping. If the relationshipPartner is null then this is a uni-directional mapping. DirectCollectionMapping can not be part of a bi-directional mapping

        return null;
    
public java.util.VectorgetSourceKeyFieldNames()
PUBLIC: Return the source key field names associated with the mapping. These are in-order with the referenceKeyFieldNames.

        Vector fieldNames = new Vector(getSourceKeyFields().size());
        for (Enumeration fieldsEnum = getSourceKeyFields().elements();
                 fieldsEnum.hasMoreElements();) {
            fieldNames.addElement(((DatabaseField)fieldsEnum.nextElement()).getQualifiedName());
        }

        return fieldNames;
    
public java.util.VectorgetSourceKeyFields()
INTERNAL: Return the source key fields.

        return sourceKeyFields;
    
public ConvertergetValueConverter()
PUBLIC: Return the converter on the mapping. A converter can be used to convert between the direct collection's object value and database value.

        return valueConverter;
    
protected booleanhasCustomDeleteQuery()

        return hasCustomDeleteQuery;
    
protected booleanhasCustomInsertQuery()

        return hasCustomInsertQuery;
    
public voidinitialize(oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Initialize and validate the mapping properties.

        if (isKeyForSourceSpecified()) {
            initializeSourceKeys(session);
        } else {
            initializeSourceKeysWithDefaults(session);
        }

        initializeReferenceTable(session);
        initializeReferenceKeys(session);
        initializeDirectField(session);
        if (shouldInitializeSelectionCriteria()) {
            initializeSelectionCriteria(session);
            initializeSelectionStatement(session);
        }
        if (!getSelectionQuery().hasSessionName()) {
            getSelectionQuery().setSessionName(session.getName());
        }
        if ((getValueConverter() != null) && (getSelectionQuery() instanceof DirectReadQuery)) {
            ((DirectReadQuery)getSelectionQuery()).setValueConverter(getValueConverter());
        }
        initializeDeleteAllQuery(session);
        initializeDeleteQuery(session);
        initializeInsertQuery(session);
        if (getValueConverter() != null) {
            getValueConverter().initialize(this, session);
        }
        super.initialize(session);
    
protected voidinitializeDeleteAllQuery(oracle.toplink.essentials.internal.sessions.AbstractSession session)
Initialize delete all query. This query is used to delete the collection of objects from the reference table.

        if (!getDeleteAllQuery().hasSessionName()) {
            getDeleteAllQuery().setSessionName(session.getName());
        }

        if (hasCustomDeleteAllQuery()) {
            return;
        }

        Expression expression = null;
        Expression subExp1;
        Expression subExp2;
        Expression subExpression;
        Expression builder = new ExpressionBuilder();
        SQLDeleteStatement statement = new SQLDeleteStatement();

        // Construct an expression to delete from the relation table.
        for (int index = 0; index < getReferenceKeyFields().size(); index++) {
            DatabaseField referenceKey = (DatabaseField)getReferenceKeyFields().elementAt(index);
            DatabaseField sourceKey = (DatabaseField)getSourceKeyFields().elementAt(index);

            subExp1 = builder.getField(referenceKey);
            subExp2 = builder.getParameter(sourceKey);
            subExpression = subExp1.equal(subExp2);

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

        statement.setWhereClause(expression);
        statement.setTable(getReferenceTable());
        getDeleteAllQuery().setSQLStatement(statement);
    
protected voidinitializeDeleteQuery(oracle.toplink.essentials.internal.sessions.AbstractSession session)

        if (!getDeleteQuery().hasSessionName()) {
            getDeleteQuery().setSessionName(session.getName());
        }

        if (hasCustomDeleteQuery()) {
            return;
        }

        Expression builder = new ExpressionBuilder();
        Expression directExp = builder.getField(getDirectField()).equal(builder.getParameter(getDirectField()));
        Expression expression = null;
        SQLDeleteStatement statement = new SQLDeleteStatement();

        // Construct an expression to delete from the relation table.
        for (int index = 0; index < getReferenceKeyFields().size(); index++) {
            DatabaseField referenceKey = (DatabaseField)getReferenceKeyFields().elementAt(index);
            DatabaseField sourceKey = (DatabaseField)getSourceKeyFields().elementAt(index);

            Expression subExp1 = builder.getField(referenceKey);
            Expression subExp2 = builder.getParameter(sourceKey);
            Expression subExpression = subExp1.equal(subExp2);

            expression = subExpression.and(expression);
        }
        expression = expression.and(directExp);
        statement.setWhereClause(expression);
        statement.setTable(getReferenceTable());
        getDeleteQuery().setSQLStatement(statement);
    
protected voidinitializeDirectField(oracle.toplink.essentials.internal.sessions.AbstractSession session)
The field name on the reference table is initialized and cached.

        if (getDirectField() == null) {
            throw DescriptorException.directFieldNameNotSet(this);
        }

        getDirectField().setTable(getReferenceTable());
        getDirectField().setIndex(0);
    
protected voidinitializeInsertQuery(oracle.toplink.essentials.internal.sessions.AbstractSession session)
Initialize insert query. This query is used to insert the collection of objects into the reference table.

        if (!getInsertQuery().hasSessionName()) {
            getInsertQuery().setSessionName(session.getName());
        }

        if (hasCustomInsertQuery()) {
            return;
        }

        SQLInsertStatement statement = new SQLInsertStatement();
        statement.setTable(getReferenceTable());
        AbstractRecord directRow = new DatabaseRecord();
        for (Enumeration referenceEnum = getReferenceKeyFields().elements();
                 referenceEnum.hasMoreElements();) {
            directRow.put((DatabaseField)referenceEnum.nextElement(), null);
        }
        directRow.put(getDirectField(), null);
        statement.setModifyRow(directRow);
        getInsertQuery().setSQLStatement(statement);
        getInsertQuery().setModifyRow(directRow);
    
protected voidinitializeReferenceDescriptor(oracle.toplink.essentials.internal.sessions.AbstractSession session)
There is no reference descriptor

        ;
    
protected voidinitializeReferenceKeys(oracle.toplink.essentials.internal.sessions.AbstractSession session)
The reference keys on the reference table are initalized

        if (getReferenceKeyFields().size() == 0) {
            throw DescriptorException.noReferenceKeyIsSpecified(this);
        }

        for (Enumeration referenceEnum = getReferenceKeyFields().elements();
                 referenceEnum.hasMoreElements();) {
            DatabaseField field = (DatabaseField)referenceEnum.nextElement();
            if (field.hasTableName() && (!(field.getTableName().equals(getReferenceTable().getName())))) {
                throw DescriptorException.referenceKeyFieldNotProperlySpecified(field, this);
            }
            field.setTable(getReferenceTable());
        }
    
protected voidinitializeReferenceTable(oracle.toplink.essentials.internal.sessions.AbstractSession session)

        Platform platform = session.getDatasourcePlatform();

        if (getReferenceTable() == null) {
            throw DescriptorException.referenceTableNotSpecified(this);
        }

        if (platform.getTableQualifier().length() == 0) {
            return;
        }

        if (getReferenceTable().getTableQualifier().length() == 0) {
            getReferenceTable().setTableQualifier(platform.getTableQualifier());
        }
    
protected voidinitializeSelectionCriteria(oracle.toplink.essentials.internal.sessions.AbstractSession session)

        Expression exp1;
        Expression exp2;
        Expression expression;
        Expression criteria = null;
        Enumeration referenceKeysEnum;
        Enumeration sourceKeysEnum;
        ExpressionBuilder base = new ExpressionBuilder();
        TableExpression table = (TableExpression)base.getTable(getReferenceTable());

        referenceKeysEnum = getReferenceKeyFields().elements();
        sourceKeysEnum = getSourceKeyFields().elements();

        for (; referenceKeysEnum.hasMoreElements();) {
            DatabaseField referenceKey = (DatabaseField)referenceKeysEnum.nextElement();
            DatabaseField sourceKey = (DatabaseField)sourceKeysEnum.nextElement();

            exp1 = table.getField(referenceKey);
            exp2 = base.getParameter(sourceKey);
            expression = exp1.equal(exp2);

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

        setSelectionCriteria(criteria);
    
protected voidinitializeSelectionQuery(oracle.toplink.essentials.internal.sessions.AbstractSession session)
The selection query is initialized

        // Nothing required.
    
protected voidinitializeSelectionStatement(oracle.toplink.essentials.internal.sessions.AbstractSession session)

        SQLSelectStatement statement = new SQLSelectStatement();
        statement.addTable(getReferenceTable());
        statement.addField((DatabaseField)getDirectField().clone());
        statement.setWhereClause(getSelectionCriteria());
        statement.normalize(session, null);
        getSelectionQuery().setSQLStatement(statement);
    
protected voidinitializeSourceKeys(oracle.toplink.essentials.internal.sessions.AbstractSession session)
The source keys are initalized

        for (Enumeration sourceKeyEnum = getSourceKeyFields().elements();
                 sourceKeyEnum.hasMoreElements();) {
            getDescriptor().buildField((DatabaseField)sourceKeyEnum.nextElement());
        }
    
protected voidinitializeSourceKeysWithDefaults(oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: If a user does not specify the source key then the primary keys of the source table are used.

        List<DatabaseField> primaryKeyFields = getDescriptor().getPrimaryKeyFields();
        for (int index = 0; index < primaryKeyFields.size(); index++) {
            getSourceKeyFields().addElement(primaryKeyFields.get(index));
        }
    
public booleanisCascadedLockingSupported()
INTERNAL Return true if this mapping supports cascaded version optimistic locking.

        return true;
    
public booleanisChangeTrackingSupported()
INTERNAL: Return if this mapping supports change tracking.

        return true;
    
public booleanisDirectCollectionMapping()
INTERNAL:

        return true;
    
protected booleanisKeyForSourceSpecified()
INTERNAL: Checks if source and target keys are mentioned by the user or not.

        return !getSourceKeyFields().isEmpty();
    
public booleanisPrivateOwned()
INTERNAL: Return true if referenced objects are provately owned else false.

        return true;
    
public booleanisRelationalMapping()

        return true;
    
public voiditerateOnElement(DescriptorIterator iterator, java.lang.Object element)
INTERNAL: Iterate on the specified element.

        iterator.iteratePrimitiveForMapping(element, this);
    
public voiditerateOnRealAttributeValue(DescriptorIterator iterator, java.lang.Object realAttributeValue)
INTERNAL: Iterate on the attribute value. The value holder has already been processed. PERF: Avoid iteration if not required.

        if (iterator.shouldIterateOnPrimitives()) {
            super.iterateOnRealAttributeValue(iterator, realAttributeValue);
        }
    
public voidmergeChangesIntoObject(java.lang.Object target, ChangeRecord changeRecord, java.lang.Object source, MergeManager mergeManager)
INTERNAL: Merge changes from the source to the target object. Because this is a collection mapping, values are added to or removed from the collection based on the changeset

        ContainerPolicy containerPolicy = getContainerPolicy();
        Object valueOfTarget = null;
        AbstractSession session = mergeManager.getSession();

        //collect the changes into a vector
        HashMap addObjects = ((DirectCollectionChangeRecord)changeRecord).getAddObjectMap();
        HashMap removeObjects = ((DirectCollectionChangeRecord)changeRecord).getRemoveObjectMap();

        //Check to see if the target has an instantiated collection
        if ((isAttributeValueInstantiated(target)) && (!changeRecord.getOwner().isNew())) {
            valueOfTarget = getRealCollectionAttributeValueFromObject(target, session);
        } else {
            //if not create an instance of the collection
            valueOfTarget = containerPolicy.containerInstance(addObjects.size());
        }
        if (!isAttributeValueInstantiated(target)) {
            if (mergeManager.shouldMergeChangesIntoDistributedCache()) {
                return;
            }
            for (Object iterator = containerPolicy.iteratorFor(getRealCollectionAttributeValueFromObject(source, session));
                     containerPolicy.hasNext(iterator);) {
                containerPolicy.addInto(containerPolicy.next(iterator, session), valueOfTarget, session);
            }
        } else {
            synchronized (valueOfTarget) {
                // Next iterate over the changes and add them to the container
                for (Iterator iterator = addObjects.keySet().iterator(); iterator.hasNext(); ){
                    Object object = iterator.next();
                    int objectCount = ((Integer)addObjects.get(object)).intValue();
                    for (int i = 0; i < objectCount; ++i) {
                        if (mergeManager.shouldMergeChangesIntoDistributedCache()) {
                            //bug#4458089 and 4454532- check if collection contains new item before adding during merge into distributed cache					
                            if (!containerPolicy.contains(object, valueOfTarget, session)) {
                                containerPolicy.addInto(object, valueOfTarget, session);
                            }
                        } else {
                            containerPolicy.addInto(object, valueOfTarget, session);
                        }
                    }
                }
                for (Iterator iterator = removeObjects.keySet().iterator(); iterator.hasNext(); ){
                    Object object = iterator.next();
                    int objectCount = ((Integer)removeObjects.get(object)).intValue();
                    for (int i = 0; i < objectCount; ++i) {
                        containerPolicy.removeFrom(object, valueOfTarget, session);
                    }
                }
            }
        }
        setRealAttributeValueInObject(target, valueOfTarget);
    
public voidmergeIntoObject(java.lang.Object target, boolean isTargetUnInitialized, java.lang.Object source, MergeManager mergeManager)
INTERNAL: Merge changes from the source to the target object.

        if (isTargetUnInitialized) {
            // This will happen if the target object was removed from the cache before the commit was attempted
            if (mergeManager.shouldMergeWorkingCopyIntoOriginal() && (!isAttributeValueInstantiated(source))) {
                setAttributeValueInObject(target, getIndirectionPolicy().getOriginalIndirectionObject(getAttributeValueFromObject(source), mergeManager.getSession()));
                return;
            }
        }
        if (!shouldMergeCascadeReference(mergeManager)) {
            // This is only going to happen on mergeClone, and we should not attempt to merge the reference
            return;
        }
        if (mergeManager.shouldMergeOriginalIntoWorkingCopy()) {
            if (!isAttributeValueInstantiated(target)) {
                // This will occur when the clone's value has not been instantiated yet and we do not need
                // the refresh that attribute
                return;
            }
        } else if (!isAttributeValueInstantiated(source)) {
            // I am merging from a clone into an original.  No need to do merge if the attribute was never
            // modified
            return;
        }

        ContainerPolicy containerPolicy = getContainerPolicy();
        Object valueOfSource = getRealCollectionAttributeValueFromObject(source, mergeManager.getSession());

        // trigger instantiation of target attribute
        Object valueOfTarget = getRealCollectionAttributeValueFromObject(target, mergeManager.getSession());
        Object newContainer = containerPolicy.containerInstance(containerPolicy.sizeFor(valueOfSource));
        boolean fireChangeEvents = false;
        valueOfTarget = newContainer;
        for (Object sourceValuesIterator = containerPolicy.iteratorFor(valueOfSource);
                 containerPolicy.hasNext(sourceValuesIterator);) {
            Object sourceValue = containerPolicy.next(sourceValuesIterator, mergeManager.getSession());
            containerPolicy.addInto(sourceValue, valueOfTarget, mergeManager.getSession());
        }

        // Must re-set variable to allow for set method to re-morph changes if the collection is not being stored directly.
        setRealAttributeValueInObject(target, valueOfTarget);
    
public voidperformDataModificationEvent(java.lang.Object[] event, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Perform the commit event. This is used in the uow to delay data modifications.

        // Hey I might actually want to use an inner class here... ok array for now.
        if (event[0] == Delete){
            session.executeQuery((DataModifyQuery)event[1], (AbstractRecord)event[(2)]);
        } else if (event[0] == Insert) {
            session.executeQuery((DataModifyQuery)event[1], (AbstractRecord)event[(2)]);
        } else if (event[0] == DeleteAll) {
            preDelete((DeleteObjectQuery)event[1]);
        } else {
            throw DescriptorException.invalidDataModificationEventCode(event[0], this);
        }
    
public voidpostInsert(WriteObjectQuery query)
INTERNAL: Insert the private owned object.

        Object objects;
        AbstractRecord databaseRow = new DatabaseRecord();

        if (isReadOnly()) {
            return;
        }

        objects = getRealCollectionAttributeValueFromObject(query.getObject(), query.getSession());
        ContainerPolicy containerPolicy = getContainerPolicy();
        if (containerPolicy.isEmpty(objects)) {
            return;
        }

        prepareTranslationRow(query.getTranslationRow(), query.getObject(), query.getSession());
        // Extract primary key and value from the source.
        for (int index = 0; index < getReferenceKeyFields().size(); index++) {
            DatabaseField referenceKey = (DatabaseField)getReferenceKeyFields().elementAt(index);
            DatabaseField sourceKey = (DatabaseField)getSourceKeyFields().elementAt(index);
            Object sourceKeyValue = query.getTranslationRow().get(sourceKey);
            databaseRow.put(referenceKey, sourceKeyValue);
        }

        // Extract target field and its value. Construct insert statement and execute it
        for (Object iter = containerPolicy.iteratorFor(objects); containerPolicy.hasNext(iter);) {
            Object object = containerPolicy.next(iter, query.getSession());
            if (getValueConverter() != null) {
                object = getValueConverter().convertObjectValueToDataValue(object, query.getSession());
            }
            databaseRow.put(getDirectField(), object);

            // In the uow data queries are cached until the end of the commit.
            if (query.shouldCascadeOnlyDependentParts()) {
                // Hey I might actually want to use an inner class here... ok array for now.
                Object[] event = new Object[3];
                event[0] = Insert;
                event[1] = getInsertQuery();
                event[2] = databaseRow.clone();
                query.getSession().getCommitManager().addDataModificationEvent(this, event);
            } else {
                query.getSession().executeQuery(getInsertQuery(), databaseRow);
            }
        }
    
public voidpostUpdate(WriteObjectQuery writeQuery)
INTERNAL: Update private owned part.

        if (isReadOnly()) {
            return;
        }

        if (writeQuery.getObjectChangeSet() != null){
            postUpdateWithChangeSet(writeQuery);
            return;
        }
        // If objects are not instantiated that means they are not changed.
        if (!isAttributeValueInstantiated(writeQuery.getObject())) {
            return;
        }

        if (writeQuery.getSession().isUnitOfWork()) {
            if (compareObjects(writeQuery.getObject(), writeQuery.getBackupClone(), writeQuery.getSession())) {
                return;// Nothing has changed, no work required
            }
        }

        DeleteObjectQuery deleteQuery = new DeleteObjectQuery();
        deleteQuery.setObject(writeQuery.getObject());
        deleteQuery.setSession(writeQuery.getSession());
        deleteQuery.setTranslationRow(writeQuery.getTranslationRow());

        if (writeQuery.shouldCascadeOnlyDependentParts()) {
            // Hey I might actually want to use an inner class here... ok array for now.
            Object[] event = new Object[3];
            event[0] = DeleteAll;
            event[1] = deleteQuery;
            writeQuery.getSession().getCommitManager().addDataModificationEvent(this, event);
        } else {
            preDelete(deleteQuery);
        }
        postInsert(writeQuery);
    
protected voidpostUpdateWithChangeSet(WriteObjectQuery writeQuery)
INTERNAL: Update private owned part.


        ObjectChangeSet changeSet = writeQuery.getObjectChangeSet();
        DirectCollectionChangeRecord changeRecord = (DirectCollectionChangeRecord)changeSet.getChangesForAttributeNamed(this.getAttributeName());
        if (changeRecord == null){
            return;
        }
        for (int index = 0; index < getReferenceKeyFields().size(); index++) {
            DatabaseField referenceKey = (DatabaseField)getReferenceKeyFields().elementAt(index);
            DatabaseField sourceKey = (DatabaseField)getSourceKeyFields().elementAt(index);
            Object sourceKeyValue = writeQuery.getTranslationRow().get(sourceKey);
            writeQuery.getTranslationRow().put(referenceKey, sourceKeyValue);
        }
        for (Iterator iterator = changeRecord.getRemoveObjectMap().keySet().iterator(); iterator.hasNext();){
            Object object = iterator.next();
            AbstractRecord thisRow = (AbstractRecord)writeQuery.getTranslationRow().clone();
            Object value = object;
            if (getValueConverter() != null){
                value = getValueConverter().convertObjectValueToDataValue(value, writeQuery.getSession());
            }
            if (value == DirectCollectionChangeRecord.Null){
                thisRow.add(getDirectField(), null);
            }else{
                thisRow.add(getDirectField(), value);
            }
            // Hey I might actually want to use an inner class here... ok array for now.
            Object[] event = new Object[3];
            event[0] = Delete;
            event[1] = getDeleteQuery();
            event[2] = thisRow;
            writeQuery.getSession().getCommitManager().addDataModificationEvent(this, event);
            Integer count = (Integer)changeRecord.getCommitAddMap().get(object);
            if (count != null){
                for (int counter = count.intValue(); counter > 0; --counter){
                    thisRow = (AbstractRecord)writeQuery.getTranslationRow().clone();
                    thisRow.add(getDirectField(), value);
                    // Hey I might actually want to use an inner class here... ok array for now.
                    event = new Object[3];
                    event[0] = Insert;
                    event[1] = getInsertQuery();
                    event[2] = thisRow;
                    writeQuery.getSession().getCommitManager().addDataModificationEvent(this, event);
                }
            }
        }
        for (Iterator iterator = changeRecord.getAddObjectMap().keySet().iterator(); iterator.hasNext();){
            Object object = iterator.next();
            Integer count = (Integer)changeRecord.getAddObjectMap().get(object);
            for (int counter = count.intValue(); counter > 0; --counter){
                AbstractRecord thisRow = (AbstractRecord)writeQuery.getTranslationRow().clone();
                Object value = object;
                if (getValueConverter() != null){
                    value = getValueConverter().convertObjectValueToDataValue(value, writeQuery.getSession());
                }
                if (value == DirectCollectionChangeRecord.Null){  //special placeholder for nulls
                    thisRow.add(getDirectField(), null);
                }else{
                    thisRow.add(getDirectField(), value);
                }
                // Hey I might actually want to use an inner class here... ok array for now.
                Object[] event = new Object[3];
                event[0] = Insert;
                event[1] = getInsertQuery();
                event[2] = thisRow;
                writeQuery.getSession().getCommitManager().addDataModificationEvent(this, event);
            }
        }
    
public voidpreDelete(WriteObjectQuery query)
INTERNAL: Delete private owned part. Which is a collection of objects from the reference table.

        if (isReadOnly()) {
            return;
        }

        prepareTranslationRow(query.getTranslationRow(), query.getObject(), query.getSession());
        query.getSession().executeQuery(getDeleteAllQuery(), query.getTranslationRow());
    
protected voidprepareTranslationRow(oracle.toplink.essentials.internal.sessions.AbstractRecord translationRow, java.lang.Object object, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: The translation row may require additional fields than the primary key if the mapping in not on the primary key.

        // Make sure that each source key field is in the translation row.
        for (Enumeration sourceFieldsEnum = getSourceKeyFields().elements();
                 sourceFieldsEnum.hasMoreElements();) {
            DatabaseField sourceKey = (DatabaseField)sourceFieldsEnum.nextElement();
            if (!translationRow.containsKey(sourceKey)) {
                Object value = getDescriptor().getObjectBuilder().extractValueFromObjectForField(object, sourceKey, session);
                translationRow.put(sourceKey, value);
            }
        }
    
public voidremoveFromCollectionChangeRecord(java.lang.Object newKey, java.lang.Object newValue, ObjectChangeSet objectChangeSet, oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl uow)
INTERNAL: Remove a value and its change set from the collection change record. This is used by attribute change tracking.

        if (newValue == null) {
            newValue = DirectCollectionChangeRecord.Null;
        }
        ClassDescriptor descriptor;
        DirectCollectionChangeRecord collectionChangeRecord = (DirectCollectionChangeRecord)objectChangeSet.getChangesForAttributeNamed(this.getAttributeName());
        if (collectionChangeRecord == null) {
            collectionChangeRecord = new DirectCollectionChangeRecord(objectChangeSet);
            collectionChangeRecord.setAttribute(getAttributeName());
            collectionChangeRecord.setMapping(this);
            objectChangeSet.addChange(collectionChangeRecord);
            Object collection = getRealAttributeValueFromObject(objectChangeSet.getUnitOfWorkClone(), uow);
            collectionChangeRecord.storeDatabaseCounts(collection, getContainerPolicy(), uow);
        }
        collectionChangeRecord.addRemoveChange(newValue, new Integer(1));
    
public voidsetContainerPolicy(ContainerPolicy containerPolicy)
ADVANCED: Configure the mapping to use a container policy. The policy manages the access to the collection.

        this.containerPolicy = containerPolicy;
        ((DataReadQuery)getSelectionQuery()).setContainerPolicy(containerPolicy);
    
public voidsetCustomDeleteQuery(ModifyQuery query)
PUBLIC: The default delete query for this mapping can be overridden by specifying the new query. This query is responsible for doing the deletion required by the mapping, such as deletion from join table for M-M. The query should delete a specific row from the DirectCollectionTable bases on the DirectField.

        setDeleteQuery(query);
        setHasCustomDeleteQuery(true);
    
public voidsetCustomInsertQuery(DataModifyQuery query)
PUBLIC: The default insert query for mapping can be overridden by specifying the new query. This query inserts the row into the direct table.

        setInsertQuery(query);
        setHasCustomInsertQuery(true);
    
protected voidsetDeleteQuery(ModifyQuery query)

        this.changeSetDeleteQuery = query;
    
public voidsetDeleteSQLString(java.lang.String sqlString)
PUBLIC: Set the receiver's delete SQL string. This allows the user to override the SQL generated by TopLink, with there own SQL or procedure call. The arguments are translated from the fields of the source row, through replacing the field names marked by '#' with the values for those fields. This SQL is responsible for doing the deletion required by the mapping, such as deletion from join table for M-M. Example, 'delete from RESPONS where EMP_ID = #EMP_ID and DESCRIP = #DESCRIP'.

        DataModifyQuery query = new DataModifyQuery();
        query.setSQLString(sqlString);
        setCustomDeleteQuery(query);
    
public voidsetDirectField(DatabaseField field)
PUBLIC: Set the direct field in the reference table. This is the field that the primitive data value is stored in.

        directField = field;
    
public voidsetDirectFieldClassification(java.lang.Class fieldType)
ADVANCED: Set the class type of the field value. This can be used if field value differs from the object value, has specific typing requirements such as usage of java.sql.Blob or NChar. This must be called after the field name has been set.

        getDirectField().setType(fieldType);
    
public voidsetDirectFieldName(java.lang.String fieldName)
PUBLIC: Set the direct field name in the reference table. This is the field that the primitive data value is stored in.

        setDirectField(new DatabaseField(fieldName));
    
protected voidsetHasCustomDeleteQuery(boolean bool)

        hasCustomDeleteQuery = bool;
    
protected voidsetHasCustomInsertQuery(boolean bool)

        hasCustomInsertQuery = bool;
    
protected voidsetInsertQuery(DataModifyQuery insertQuery)

        this.insertQuery = insertQuery;
    
public voidsetInsertSQLString(java.lang.String sqlString)
PUBLIC: Set the receiver's insert SQL string. This allows the user to override the SQL generated by TopLink, with there own SQL or procedure call. The arguments are translated from the fields of the source row, through replacing the field names marked by '#' with the values for those fields. This is used to insert an entry into the direct table. Example, 'insert into RESPONS (EMP_ID, RES_DESC) values (#EMP_ID, #RES_DESC)'.

        DataModifyQuery query = new DataModifyQuery();
        query.setSQLString(sqlString);
        setCustomInsertQuery(query);
    
public voidsetReferenceClass(java.lang.Class referenceClass)
INTERNAL: This cannot be used with direct collection mappings.

        return;
    
public voidsetReferenceClassName(java.lang.String referenceClassName)

        return;
    
public voidsetReferenceKeyFieldName(java.lang.String fieldName)
PUBLIC: Set the name of the reference key field. This is the foreign key field in the direct table referencing the primary key of the source object. This method is used if the reference key consists of only a single field.

        getReferenceKeyFields().addElement(new DatabaseField(fieldName));
    
public voidsetReferenceKeyFieldNames(java.util.Vector fieldNames)
INTERNAL: Set the reference key field names associated with the mapping. These must be in-order with the sourceKeyFieldNames.

        Vector fields = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(fieldNames.size());
        for (Enumeration fieldNamesEnum = fieldNames.elements(); fieldNamesEnum.hasMoreElements();) {
            fields.addElement(new DatabaseField((String)fieldNamesEnum.nextElement()));
        }

        setReferenceKeyFields(fields);
    
public voidsetReferenceKeyFields(java.util.Vector aVector)
INTERNAL: Set the reference fields.

        this.referenceKeyFields = aVector;
    
public voidsetReferenceTable(DatabaseTable table)
INTERNAL: Set the reference table.

        referenceTable = table;
    
public voidsetReferenceTableName(java.lang.String tableName)
PUBLIC: Set the reference table name.

        if (tableName == null) {
            setReferenceTable(null);
        } else {
            setReferenceTable(new DatabaseTable(tableName));
        }
    
public voidsetSessionName(java.lang.String name)
PUBLIC: Set the name of the session to execute the mapping's queries under. This can be used by the session broker to override the default session to be used for the target class.

        super.setSessionName(name);
        getInsertQuery().setSessionName(name);
    
public voidsetSourceKeyFieldNames(java.util.Vector fieldNames)
INTERNAL: Set the source key field names associated with the mapping. These must be in-order with the referenceKeyFieldNames.

        Vector fields = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(fieldNames.size());
        for (Enumeration fieldNamesEnum = fieldNames.elements(); fieldNamesEnum.hasMoreElements();) {
            fields.addElement(new DatabaseField((String)fieldNamesEnum.nextElement()));
        }

        setSourceKeyFields(fields);
    
public voidsetSourceKeyFields(java.util.Vector sourceKeyFields)
INTERNAL: Set the source fields.

        this.sourceKeyFields = sourceKeyFields;
    
public voidsetValueConverter(Converter valueConverter)
PUBLIC: Set the converter on the mapping. A converter can be used to convert between the direct collection's object value and database value.

        this.valueConverter = valueConverter;
    
public voidsimpleAddToCollectionChangeRecord(java.lang.Object referenceKey, java.lang.Object objectToAdd, ObjectChangeSet changeSet, oracle.toplink.essentials.internal.sessions.AbstractSession session)
ADVANCED: This method is used to have an object add to a collection once the changeSet is applied The referenceKey parameter should only be used for direct Maps.

        DirectCollectionChangeRecord collectionChangeRecord = (DirectCollectionChangeRecord)changeSet.getChangesForAttributeNamed(getAttributeName());
        if (collectionChangeRecord == null) {
            collectionChangeRecord = new DirectCollectionChangeRecord(changeSet);
            collectionChangeRecord.setAttribute(getAttributeName());
            collectionChangeRecord.setMapping(this);
            changeSet.addChange(collectionChangeRecord);
            Object collection = getRealAttributeValueFromObject(changeSet.getUnitOfWorkClone(), session);
            collectionChangeRecord.storeDatabaseCounts(collection, getContainerPolicy(), session);
        }
        collectionChangeRecord.addAdditionChange(objectToAdd, new Integer(1));
    
public voidsimpleRemoveFromCollectionChangeRecord(java.lang.Object referenceKey, java.lang.Object objectToRemove, ObjectChangeSet changeSet, oracle.toplink.essentials.internal.sessions.AbstractSession session)
ADVANCED: This method is used to have an object removed from a collection once the changeSet is applied The referenceKey parameter should only be used for direct Maps.

        DirectCollectionChangeRecord collectionChangeRecord = (DirectCollectionChangeRecord)changeSet.getChangesForAttributeNamed(getAttributeName());
        if (collectionChangeRecord == null) {
            collectionChangeRecord = new DirectCollectionChangeRecord(changeSet);
            collectionChangeRecord.setAttribute(getAttributeName());
            collectionChangeRecord.setMapping(this);
            changeSet.addChange(collectionChangeRecord);
            Object collection = getRealAttributeValueFromObject(changeSet.getUnitOfWorkClone(), session);
            collectionChangeRecord.storeDatabaseCounts(collection, getContainerPolicy(), session);
        }
        collectionChangeRecord.addRemoveChange(objectToRemove, new Integer(1));
    
public voidupdateChangeRecord(java.lang.Object clone, java.lang.Object newValue, java.lang.Object oldValue, ObjectChangeSet objectChangeSet, oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl uow)
INTERNAL: Either create a new change record or update with the new value. This is used by attribute change tracking. Specifically in a collection mapping this will be called when the customer Set a new collection. In this case we will need to mark the change record with the new and the old versions of the collection. And mark the ObjectChangeSet with the attribute name then when the changes are calculated force a compare on the collections to determine changes.

        DirectCollectionChangeRecord collectionChangeRecord = (DirectCollectionChangeRecord)objectChangeSet.getChangesForAttributeNamed(this.getAttributeName());
        if (collectionChangeRecord == null) {
            collectionChangeRecord = new DirectCollectionChangeRecord(objectChangeSet);
            collectionChangeRecord.setAttribute(getAttributeName());
            collectionChangeRecord.setMapping(this);
            objectChangeSet.addChange(collectionChangeRecord);
        }
        if (collectionChangeRecord.getOriginalCollection() == null){
            collectionChangeRecord.setOriginalCollection(oldValue);
        }
        collectionChangeRecord.setLatestCollection(newValue);
        
        objectChangeSet.deferredDetectionRequiredOn(getAttributeName());
    
public voiduseCollectionClass(java.lang.Class concreteClass)
PUBLIC: Configure the mapping to use an instance of the specified container class to hold the target objects.

jdk1.2.x: The container class must implement (directly or indirectly) the Collection interface.

jdk1.1.x: The container class must be a subclass of Vector.

        ContainerPolicy policy = ContainerPolicy.buildPolicyFor(concreteClass);
        setContainerPolicy(policy);
    
public voiduseMapClass(java.lang.Class concreteClass, java.lang.String methodName)
PUBLIC: It is illegal to use a Map as the container of a DirectCollectionMapping. Only Collection containers are supported for DirectCollectionMappings.

see
oracle.toplink.essentials.mappings.DirectMapMapping

        throw ValidationException.illegalUseOfMapInDirectCollection(this, concreteClass, methodName);
    
public java.lang.ObjectvalueFromRow(oracle.toplink.essentials.internal.sessions.AbstractRecord row, JoinedAttributeManager joinManager, ObjectBuildingQuery query, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Return the value of the reference attribute or a value holder. Check whether the mapping's attribute should be optimized through batch and joining. Overridden to support flasback/historical queries.

        ReadQuery targetQuery = getSelectionQuery();
        return getIndirectionPolicy().valueFromQuery(targetQuery, row, query.getSession());
    
public booleanverifyDelete(java.lang.Object object, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Checks if object is deleted from the database or not.

        // Row is built for translation
        if (isReadOnly()) {
            return true;
        }

        AbstractRecord row = getDescriptor().getObjectBuilder().buildRowForTranslation(object, session);
        Object value = session.executeQuery(getSelectionQuery(), row);

        return getContainerPolicy().isEmpty(value);