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

AggregateMapping

public abstract class AggregateMapping extends DatabaseMapping
Purpose: Two objects can be considered to be related by aggregation if there is a strict 1:1 relationship between the objects. This means that if the source (parent)object exists, then the target (child or owned) object must exist. This class implements the behavior common to the aggregate object and structure mappings.
author
Sati
since
TopLink for Java 1.0

Fields Summary
protected Class
referenceClass
Stores a reference class
protected String
referenceClassName
protected oracle.toplink.essentials.descriptors.ClassDescriptor
referenceDescriptor
The descriptor of the reference class
Constructors Summary
public AggregateMapping()
Default constructor.

        super();
    
Methods Summary
protected DeleteObjectQuerybuildAggregateDeleteQuery(WriteObjectQuery sourceQuery, java.lang.Object sourceAttributeValue)
Make a copy of the sourceQuery for the attribute.

        DeleteObjectQuery aggregateQuery = new DeleteObjectQuery();
        buildAggregateModifyQuery(sourceQuery, aggregateQuery, sourceAttributeValue);
        return aggregateQuery;
    
protected voidbuildAggregateModifyQuery(ObjectLevelModifyQuery sourceQuery, ObjectLevelModifyQuery aggregateQuery, java.lang.Object sourceAttributeValue)
Initialize the aggregate query with the settings from the source query.

        if (sourceQuery.getSession().isUnitOfWork()) {
            Object backupAttributeValue = getAttributeValueFromBackupClone(sourceQuery.getBackupClone());
            if (backupAttributeValue == null) {
                backupAttributeValue = getObjectBuilder(sourceAttributeValue, sourceQuery.getSession()).buildNewInstance();
            }
            aggregateQuery.setBackupClone(backupAttributeValue);
        }
        aggregateQuery.setCascadePolicy(sourceQuery.getCascadePolicy());
        aggregateQuery.setObject(sourceAttributeValue);
        aggregateQuery.setTranslationRow(sourceQuery.getTranslationRow());
        aggregateQuery.setSession(sourceQuery.getSession());
        aggregateQuery.setProperties(sourceQuery.getProperties());
    
protected WriteObjectQuerybuildAggregateWriteQuery(WriteObjectQuery sourceQuery, java.lang.Object sourceAttributeValue)
Make a copy of the sourceQuery for the attribute.

        WriteObjectQuery aggregateQuery = new WriteObjectQuery();
        buildAggregateModifyQuery(sourceQuery, aggregateQuery, sourceAttributeValue);
        return aggregateQuery;
    
public voidbuildBackupClone(java.lang.Object clone, java.lang.Object backup, oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl unitOfWork)
INTERNAL: Clone the attribute from the clone and assign it to the backup.

        Object attributeValue = getAttributeValueFromObject(clone);
        setAttributeValueInObject(backup, buildBackupClonePart(attributeValue, unitOfWork));
    
protected java.lang.ObjectbuildBackupClonePart(java.lang.Object attributeValue, oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl unitOfWork)
INTERNAL: Build and return a backup clone of the attribute.

        if (attributeValue == null) {
            return null;
        }
        return getObjectBuilder(attributeValue, unitOfWork).buildBackupClone(attributeValue, unitOfWork);
    
public voidbuildClone(java.lang.Object original, java.lang.Object clone, oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl unitOfWork, oracle.toplink.essentials.internal.queryframework.JoinedAttributeManager joinedAttributeManager)
INTERNAL: Clone the attribute from the original and assign it to the clone.

        Object attributeValue = getAttributeValueFromObject(original);
        setAttributeValueInObject(clone, buildClonePart(original, attributeValue, unitOfWork));
    
public voidbuildCloneFromRow(oracle.toplink.essentials.internal.sessions.AbstractRecord databaseRow, oracle.toplink.essentials.internal.queryframework.JoinedAttributeManager joinManager, java.lang.Object clone, ObjectBuildingQuery sourceQuery, oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl unitOfWork, oracle.toplink.essentials.internal.sessions.AbstractSession executionSession)
INTERNAL: A combination of readFromRowIntoObject and buildClone.

buildClone assumes the attribute value exists on the original and can simply be copied.

readFromRowIntoObject assumes that one is building an original.

Both of the above assumptions are false in this method, and actually attempts to do both at the same time.

Extract value from the row and set the attribute to this value in the working copy clone. In order to bypass the shared cache when in transaction a UnitOfWork must be able to populate working copies directly from the row.

        // automatically returns a uow result from scratch that doesn't need cloning
        Object cloneAttributeValue = valueFromRow(databaseRow, joinManager, sourceQuery, executionSession);
        setAttributeValueInObject(clone, cloneAttributeValue);
    
protected java.lang.ObjectbuildClonePart(java.lang.Object original, java.lang.Object attributeValue, oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl unitOfWork)
INTERNAL: Build and return a clone of the attribute.

        if (attributeValue == null) {
            return null;
        }
        if (unitOfWork.isOriginalNewObject(original)) {
            unitOfWork.addNewAggregate(attributeValue);
        }

        // Do not clone for read-only.
        if (unitOfWork.isClassReadOnly(attributeValue.getClass())) {
            return attributeValue;
        }

        ObjectBuilder aggregateObjectBuilder = getObjectBuilder(attributeValue, unitOfWork);

        // bug 2612602 as we are building the working copy make sure that we call to correct clone method.
        Object clonedAttributeValue = aggregateObjectBuilder.instantiateWorkingCopyClone(attributeValue, unitOfWork);
        aggregateObjectBuilder.populateAttributesForClone(attributeValue, clonedAttributeValue, unitOfWork, null);

        return clonedAttributeValue;
    
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 = getAttributeValueFromObject(original);
        setAttributeValueInObject(copy, buildCopyOfAttributeValue(attributeValue, policy));
    
protected java.lang.ObjectbuildCopyOfAttributeValue(java.lang.Object attributeValue, oracle.toplink.essentials.sessions.ObjectCopyingPolicy policy)
Copy of the attribute of the object. This is NOT used for unit of work but for templatizing an object.

        if (attributeValue == null) {
            return null;
        }
        return getObjectBuilder(attributeValue, policy.getSession()).copyObject(attributeValue, policy);
    
protected java.lang.ObjectbuildNewMergeInstanceOf(java.lang.Object sourceAttributeValue, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Build and return a new instance of the specified attribute. This will be populated by a merge.

        return getObjectBuilder(sourceAttributeValue, session).buildNewInstance();
    
protected booleancompareAttributeValues(java.lang.Object attributeValue1, java.lang.Object attributeValue2, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Compare the attributes. Return true if they are alike.

        if ((attributeValue1 == null) && (attributeValue2 == null)) {
            return true;
        }
        if ((attributeValue1 == null) || (attributeValue2 == null)) {
            return false;
        }
        if (attributeValue1.getClass() != attributeValue2.getClass()) {
            return false;
        }
        return getObjectBuilder(attributeValue1, session).compareObjects(attributeValue1, attributeValue2, session);
    
public ChangeRecordcompareForChange(java.lang.Object clone, java.lang.Object backup, ObjectChangeSet owner, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Compare the changes between two aggregates. Return a change record holding the changes.

        Object cloneAttribute = getAttributeValueFromObject(clone);
        Object backupAttribute = null;

        if (!owner.isNew()) {
            backupAttribute = getAttributeValueFromObject(backup);
            if ((cloneAttribute == null) && (backupAttribute == null)) {
                return null;// no change
            }
            if ((cloneAttribute != null) && (backupAttribute != null) && (!cloneAttribute.getClass().equals(backupAttribute.getClass()))) {
                backupAttribute = null;
            }
        }

        AggregateChangeRecord changeRecord = new AggregateChangeRecord(owner);
        changeRecord.setAttribute(getAttributeName());
        changeRecord.setMapping(this);

        if (cloneAttribute == null) {// the attribute was set to null
            changeRecord.setChangedObject(null);
            return changeRecord;
        }

        ObjectBuilder builder = getObjectBuilder(cloneAttribute, session);

        //if the owner is new then the backup will be null, if the owner is new then the aggregate is new
        //if the backup is null but the owner is not new then this aggregate is new
        ObjectChangeSet initialChanges = builder.createObjectChangeSet(cloneAttribute, (UnitOfWorkChangeSet)owner.getUOWChangeSet(), (backupAttribute == null), session);
        ObjectChangeSet changeSet = builder.compareForChange(cloneAttribute, backupAttribute, (UnitOfWorkChangeSet)owner.getUOWChangeSet(), session);
        if (changeSet == null) {
            if (initialChanges.isNew()) {
                // This happens if original aggregate is of class A, the new aggregate
                // is of class B (B inherits from A) - and neither A nor B has any mapped attributes.
                // CR3664
                changeSet = initialChanges;
            } else {
                return null;// no change
            }
        }
        changeRecord.setChangedObject(changeSet);
        return changeRecord;
    
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.

        return compareAttributeValues(getAttributeValueFromObject(firstObject), getAttributeValueFromObject(secondObject), session);
    
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 used when converting a project that has been built with class names to a project with classes.

param
classLoader

        Class referenceClass = null;
        try{
            if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
                try {
                    referenceClass = (Class)AccessController.doPrivileged(new PrivilegedClassForName(getReferenceClassName(), true, classLoader));
                } catch (PrivilegedActionException exception) {
                    throw ValidationException.classNotFoundWhileConvertingClassNames(getReferenceClassName(), exception.getException());
                }
            } else {
                referenceClass = oracle.toplink.essentials.internal.security.PrivilegedAccessHelper.getClassForName(getReferenceClassName(), true, classLoader);
            }
        } catch (ClassNotFoundException exc){
            throw ValidationException.classNotFoundWhileConvertingClassNames(getReferenceClassName(), exc);
        }
        setReferenceClass(referenceClass);
    
protected voidexecuteEvent(int eventCode, ObjectLevelModifyQuery query)
INTERNAL: Execute a descriptor event for the specified event code.

        ClassDescriptor referenceDescriptor = getReferenceDescriptor(query.getObject(), query.getSession());

        // PERF: Avoid events if no listeners.
        if (referenceDescriptor.getEventManager().hasAnyEventListeners()) {
            referenceDescriptor.getEventManager().executeEvent(new oracle.toplink.essentials.descriptors.DescriptorEvent(eventCode, query));
        }
    
protected java.lang.ObjectgetAttributeValueFromBackupClone(java.lang.Object backupClone)
Return the appropriate attribute value. This method is a hack to allow the aggregate collection subclass to override....

        return getAttributeValueFromObject(backupClone);
    
protected ObjectBuildergetObjectBuilder(java.lang.Object attributeValue, oracle.toplink.essentials.internal.sessions.AbstractSession session)
Convenience method

        return getReferenceDescriptor(attributeValue, session).getObjectBuilder();
    
protected ObjectBuildergetObjectBuilderForClass(java.lang.Class javaClass, oracle.toplink.essentials.internal.sessions.AbstractSession session)
Convenience method

        return getReferenceDescriptor(javaClass, session).getObjectBuilder();
    
protected oracle.toplink.essentials.descriptors.DescriptorQueryManagergetQueryManager(java.lang.Object attributeValue, oracle.toplink.essentials.internal.sessions.AbstractSession session)
Convenience method

        return getReferenceDescriptor(attributeValue, session).getQueryManager();
    
public java.lang.ClassgetReferenceClass()
PUBLIC: Returns the reference class

        return referenceClass;
    
public java.lang.StringgetReferenceClassName()
INTERNAL: Used by MW.

        if ((referenceClassName == null) && (referenceClass != null)) {
            referenceClassName = referenceClass.getName();
        }
        return referenceClassName;
    
public oracle.toplink.essentials.descriptors.ClassDescriptorgetReferenceDescriptor()
INTERNAL: Return the referenceDescriptor. This is a descriptor which is associated with the reference class. NOTE: If you are looking for the descriptor for a specific aggregate object, use #getReferenceDescriptor(Object). This will ensure you get the right descriptor if the object's descriptor is part of an inheritance tree.

        return referenceDescriptor;
    
protected oracle.toplink.essentials.descriptors.ClassDescriptorgetReferenceDescriptor(java.lang.Class theClass, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: For inheritance purposes.

        if (getReferenceDescriptor().getJavaClass().equals(theClass)) {
            return getReferenceDescriptor();
        }

        ClassDescriptor subclassDescriptor = session.getDescriptor(theClass);
        if (subclassDescriptor == null) {
            throw DescriptorException.noSubClassMatch(theClass, this);
        } else {
            return subclassDescriptor;
        }
    
protected oracle.toplink.essentials.descriptors.ClassDescriptorgetReferenceDescriptor(java.lang.Object attributeValue, oracle.toplink.essentials.internal.sessions.AbstractSession session)
Convenience method

        if (attributeValue == null) {
            return getReferenceDescriptor();
        } else {
            return getReferenceDescriptor(attributeValue.getClass(), session);
        }
    
public voidinitialize(oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Initialize the reference descriptor.

        super.initialize(session);

        if (getReferenceClass() == null) {
            throw DescriptorException.referenceClassNotSpecified(this);
        }

        setReferenceDescriptor(session.getDescriptor(getReferenceClass()));

        ClassDescriptor refDescriptor = this.getReferenceDescriptor();
        if (refDescriptor == null) {
            session.getIntegrityChecker().handleError(DescriptorException.descriptorIsMissing(getReferenceClass().getName(), this));
        }
        if (refDescriptor.isAggregateDescriptor()) {
            refDescriptor.checkInheritanceTreeAggregateSettings(session, this);
        } else {
            session.getIntegrityChecker().handleError(DescriptorException.referenceDescriptorIsNotAggregate(getReferenceClass().getName(), this));
        }
    
public booleanisAggregateMapping()
INTERNAL: Related mapping should implement this method to return true.

        return true;
    
public voiditerate(DescriptorIterator iterator)
INTERNAL: Iterate on the appropriate attribute value.

        iterateOnAttributeValue(iterator, getAttributeValueFromObject(iterator.getVisitedParent()));
    
protected voiditerateOnAttributeValue(DescriptorIterator iterator, java.lang.Object attributeValue)
Iterate on the specified attribute value.

        iterator.iterateForAggregateMapping(attributeValue, this, getReferenceDescriptor(attributeValue, iterator.getSession()));
    
protected voidmergeAttributeValue(java.lang.Object targetAttributeValue, boolean isTargetUnInitialized, java.lang.Object sourceAttributeValue, MergeManager mergeManager)
Merge the attribute values.

        // don't merge read-only attributes
        if (mergeManager.getSession().isClassReadOnly(sourceAttributeValue.getClass())) {
            return;
        }
        if (mergeManager.getSession().isClassReadOnly(targetAttributeValue.getClass())) {
            return;
        }

        getObjectBuilder(sourceAttributeValue, mergeManager.getSession()).mergeIntoObject(targetAttributeValue, isTargetUnInitialized, sourceAttributeValue, mergeManager);
    
public voidmergeChangesIntoObject(java.lang.Object target, ChangeRecord changeRecord, java.lang.Object source, MergeManager mergeManager)
INTERNAL: Merge changes from the source to the target object. With aggregates the merge must cascade to the object changes for the aggregate object because aggregate objects have no identity outside of themselves. The actual aggregate object does not need to be replaced, because even if the clone references another aggregate it appears the same to TopLink

        ObjectChangeSet aggregateChangeSet = (ObjectChangeSet)((AggregateChangeRecord)changeRecord).getChangedObject();
        if (aggregateChangeSet == null) {// the change was to set the value to null
            setAttributeValueInObject(target, null);
            return;
        }

        Object sourceAggregate = null;
        if (source != null) {
            sourceAggregate = getAttributeValueFromObject(source);
        }
        ObjectBuilder objectBuilder = getObjectBuilderForClass(aggregateChangeSet.getClassType(mergeManager.getSession()), mergeManager.getSession());
        //Bug#4719341  Always obtain aggregate attribute value from the target object regardless of new or not
        Object targetAggregate = getAttributeValueFromObject(target);
        if (targetAggregate == null) {
            targetAggregate = objectBuilder.buildNewInstance();
        } else {
            if ((sourceAggregate != null) && (sourceAggregate.getClass() != targetAggregate.getClass())) {
                targetAggregate = objectBuilder.buildNewInstance();
            }
        }
        objectBuilder.mergeChangesIntoObject(targetAggregate, aggregateChangeSet, sourceAggregate, mergeManager);
        setAttributeValueInObject(target, targetAggregate);
    
public voidmergeIntoObject(java.lang.Object target, boolean isTargetUnInitialized, java.lang.Object source, MergeManager mergeManager)
INTERNAL: Merge changes from the source to the target object. This merge is only called when a changeSet for the target does not exist or the target is uninitialized

        Object sourceAttributeValue = getAttributeValueFromObject(source);
        if (sourceAttributeValue == null) {
            setAttributeValueInObject(target, null);
            return;
        }

        Object targetAttributeValue = getAttributeValueFromObject(target);
        if (targetAttributeValue == null) {
            // avoid null-pointer/nothing to merge to - create a new instance
            // (a new clone cannot be used as all changes must be merged)
            targetAttributeValue = buildNewMergeInstanceOf(sourceAttributeValue, mergeManager.getSession());
            mergeAttributeValue(targetAttributeValue, true, sourceAttributeValue, mergeManager);
            // setting new instance so fire event as if set was called by user.
            // this call will eventually get passed to updateChangeRecord which will 
            //ensure this new aggregates is fully initilized with listeners.
            this.getDescriptor().getObjectChangePolicy().raiseInternalPropertyChangeEvent(target, getAttributeName(), getAttributeValueFromObject(target), targetAttributeValue);
            
        } else {
            mergeAttributeValue(targetAttributeValue, isTargetUnInitialized, sourceAttributeValue, mergeManager);
        }

        // allow setter to re-morph any changes...
        setAttributeValueInObject(target, targetAttributeValue);
    
public voidpostDelete(WriteObjectQuery query)
INTERNAL: The message is passed to its reference class descriptor.

        if (!isReadOnly()) {
            postDeleteAttributeValue(query, getAttributeValueFromObject(query.getObject()));
        }
    
protected voidpostDeleteAttributeValue(WriteObjectQuery query, java.lang.Object attributeValue)
INTERNAL: The message is passed to its reference class descriptor.

        if (attributeValue == null) {
            return;
        }
        DeleteObjectQuery aggregateQuery = buildAggregateDeleteQuery(query, attributeValue);
        getQueryManager(attributeValue, query.getSession()).postDelete(aggregateQuery);
        executeEvent(DescriptorEventManager.PostDeleteEvent, aggregateQuery);
    
public voidpostInsert(WriteObjectQuery query)
INTERNAL: The message is passed to its reference class descriptor.

        if (!isReadOnly()) {
            postInsertAttributeValue(query, getAttributeValueFromObject(query.getObject()));
        }
    
protected voidpostInsertAttributeValue(WriteObjectQuery query, java.lang.Object attributeValue)
INTERNAL: The message is passed to its reference class descriptor.

        if (attributeValue == null) {
            return;
        }
        WriteObjectQuery aggregateQuery = buildAggregateWriteQuery(query, attributeValue);
        getQueryManager(attributeValue, query.getSession()).postInsert(aggregateQuery);
        executeEvent(DescriptorEventManager.PostInsertEvent, aggregateQuery);
        // aggregates do not actually use a query to write to the database so the post write must be called here
        executeEvent(DescriptorEventManager.PostWriteEvent, aggregateQuery);
    
public voidpostUpdate(WriteObjectQuery query)
INTERNAL: The message is passed to its reference class descriptor.

        if (!isReadOnly()) {
            postUpdateAttributeValue(query, getAttributeValueFromObject(query.getObject()));
        }
    
protected voidpostUpdateAttributeValue(WriteObjectQuery query, java.lang.Object attributeValue)
INTERNAL: The message is passed to its reference class descriptor.

        if (attributeValue == null) {
            return;
        }
        ObjectChangeSet changeSet = null;
        UnitOfWorkChangeSet uowChangeSet = null;
        if (query.getSession().isUnitOfWork() && (((UnitOfWorkImpl)query.getSession()).getUnitOfWorkChangeSet() != null)) {
            uowChangeSet = (UnitOfWorkChangeSet)((UnitOfWorkImpl)query.getSession()).getUnitOfWorkChangeSet();
            changeSet = (ObjectChangeSet)uowChangeSet.getObjectChangeSetForClone(attributeValue);
        }
        WriteObjectQuery aggregateQuery = buildAggregateWriteQuery(query, attributeValue);
        aggregateQuery.setObjectChangeSet(changeSet);
        getQueryManager(attributeValue, query.getSession()).postUpdate(aggregateQuery);
        executeEvent(DescriptorEventManager.PostUpdateEvent, aggregateQuery);
        // aggregates do not actually use a query to write to the database so the post write must be called here
        executeEvent(DescriptorEventManager.PostWriteEvent, aggregateQuery);
    
public voidpreDelete(WriteObjectQuery query)
INTERNAL: The message is passed to its reference class descriptor.

        if (!isReadOnly()) {
            preDeleteAttributeValue(query, getAttributeValueFromObject(query.getObject()));
        }
    
protected voidpreDeleteAttributeValue(WriteObjectQuery query, java.lang.Object attributeValue)
INTERNAL: The message is passed to its reference class descriptor.

        if (attributeValue == null) {
            return;
        }
        DeleteObjectQuery aggregateQuery = buildAggregateDeleteQuery(query, attributeValue);
        executeEvent(DescriptorEventManager.PreDeleteEvent, aggregateQuery);
        getQueryManager(attributeValue, query.getSession()).preDelete(aggregateQuery);
    
public voidpreInsert(WriteObjectQuery query)
INTERNAL: The message is passed to its reference class descriptor.

        if (!isReadOnly()) {
            preInsertAttributeValue(query, getAttributeValueFromObject(query.getObject()));
        }
    
protected voidpreInsertAttributeValue(WriteObjectQuery query, java.lang.Object attributeValue)
INTERNAL: The message is passed to its reference class descriptor.

        if (attributeValue == null) {
            return;
        }
        WriteObjectQuery aggregateQuery = buildAggregateWriteQuery(query, attributeValue);
        getQueryManager(attributeValue, query.getSession()).preInsert(aggregateQuery);
    
public voidpreUpdate(WriteObjectQuery query)
INTERNAL: The message is passed to its reference class descriptor.

        if (!isReadOnly()) {
            preUpdateAttributeValue(query, getAttributeValueFromObject(query.getObject()));
        }
    
protected voidpreUpdateAttributeValue(WriteObjectQuery query, java.lang.Object attributeValue)
INTERNAL: The message is passed to its reference class descriptor.

        if (attributeValue == null) {
            return;
        }
        WriteObjectQuery aggregateQuery = buildAggregateWriteQuery(query, attributeValue);
        ObjectChangeSet changeSet = null;
        UnitOfWorkChangeSet uowChangeSet = null;
        if (query.getSession().isUnitOfWork() && (((UnitOfWorkImpl)query.getSession()).getUnitOfWorkChangeSet() != null)) {
            uowChangeSet = (UnitOfWorkChangeSet)((UnitOfWorkImpl)query.getSession()).getUnitOfWorkChangeSet();
            changeSet = (ObjectChangeSet)uowChangeSet.getObjectChangeSetForClone(aggregateQuery.getObject());
        }

        aggregateQuery.setObjectChangeSet(changeSet);
        // aggregates do not actually use a query to write to the database so the pre-write must be called here
        if (changeSet == null) {// then we didn't fire events at calculations
            executeEvent(DescriptorEventManager.PreWriteEvent, aggregateQuery);
            executeEvent(DescriptorEventManager.PreUpdateEvent, aggregateQuery);
        }
        getQueryManager(attributeValue, query.getSession()).preUpdate(aggregateQuery);
    
public voidsetReferenceClass(java.lang.Class aClass)
PUBLIC: This is a reference class whose instances this mapping will store in the domain objects.

        referenceClass = aClass;
    
public voidsetReferenceClassName(java.lang.String aClassName)
INTERNAL: Used by MW.

        referenceClassName = aClassName;
    
protected voidsetReferenceDescriptor(oracle.toplink.essentials.descriptors.ClassDescriptor aDescriptor)
INTERNAL: Set the referenceDescriptor. This is a descriptor which is associated with the reference class.

        referenceDescriptor = aDescriptor;
    
public voidupdateChangeRecord(java.lang.Object sourceClone, 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 the change record with the new value. This is used by attribute change tracking. Only call this method if a different aggregate is being set in the object, if the aggregate itself is being updated then call the update on the corresponding mapping within the aggregate.

        //This method will be called when either the referenced aggregate has 
        //been changed or a component of the referenced aggregate has been changed
        //this case is determined by the value of the sourceClone 
        
        AggregateChangeRecord changeRecord = (AggregateChangeRecord)objectChangeSet.getChangesForAttributeNamed(this.getAttributeName());
        if (changeRecord == null){
            changeRecord = new AggregateChangeRecord(objectChangeSet);
            changeRecord.setAttribute(this.getAttributeName());
            changeRecord.setMapping(this);
            objectChangeSet.addChange(changeRecord);
        }
        
        if ( sourceClone.getClass().equals(objectChangeSet.getClassType(uow)) ) {
            // event was fired on the parent to the aggregate, the attribute value changed.
            ClassDescriptor referenceDescriptor = getReferenceDescriptor(newValue, uow);
            if ( newValue == null ) { // attribute set to null
                changeRecord.setChangedObject(null);
                return;
            }else{ // attribute set to new aggregate
                UnitOfWorkChangeSet uowChangeSet = (UnitOfWorkChangeSet)objectChangeSet.getUOWChangeSet();
                //force comparison change detection to build changeset.
                ObjectChangeSet aggregateChangeSet = (ObjectChangeSet)uowChangeSet.getObjectChangeSetForClone(newValue);
                if (aggregateChangeSet != null) {
                    aggregateChangeSet.clear(); // old differences must be thrown away because difference is between old value and new value
                }
                //force comparison change detection to build changeset.
                changeRecord.setChangedObject(referenceDescriptor.getObjectChangePolicy().createObjectChangeSetThroughComparison(newValue,oldValue, uowChangeSet, (oldValue == null), uow, referenceDescriptor));
                referenceDescriptor.getObjectChangePolicy().setChangeSetOnListener((ObjectChangeSet)changeRecord.getChangedObject(), newValue);

            }
        } else {            
            // not tracked at attribute level, lets force build a changeset then.
            changeRecord.setChangedObject(referenceDescriptor.getObjectChangePolicy().createObjectChangeSetThroughComparison(sourceClone, null, (UnitOfWorkChangeSet)objectChangeSet.getUOWChangeSet(), true, uow, referenceDescriptor));
        }
    
public booleanverifyDelete(java.lang.Object object, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Return whether the specified object and all its components have been deleted.

        return verifyDeleteOfAttributeValue(getAttributeValueFromObject(object), session);
    
protected booleanverifyDeleteOfAttributeValue(java.lang.Object attributeValue, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Return whether the specified object and all its components have been deleted.

        if (attributeValue == null) {
            return true;
        }
        for (Enumeration mappings = getReferenceDescriptor(attributeValue, session).getMappings().elements();
                 mappings.hasMoreElements();) {
            DatabaseMapping mapping = (DatabaseMapping)mappings.nextElement();
            if (!mapping.verifyDelete(attributeValue, session)) {
                return false;
            }
        }
        return true;