Package org.jpox.state

Source Code of org.jpox.state.RelationshipManager$RelationChange

/**********************************************************************
Copyright (c) 2007 Andy Jefferson and others. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Contributors:
    ...
**********************************************************************/
package org.jpox.state;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.jpox.ClassLoaderResolver;
import org.jpox.ObjectManager;
import org.jpox.ObjectManagerFactoryImpl;
import org.jpox.StateManager;
import org.jpox.exceptions.JPOXUserException;
import org.jpox.metadata.AbstractClassMetaData;
import org.jpox.metadata.AbstractMemberMetaData;
import org.jpox.metadata.Relation;
import org.jpox.sco.SCOCollection;
import org.jpox.util.JPOXLogger;
import org.jpox.util.Localiser;
import org.jpox.util.StringUtils;

/**
* Manager for relationships of a class.
* Performs management of (bidirectional) relations.
* If one side is set yet the other isnt, corrects the other side.
*
* @version $Revision$
*/
public class RelationshipManager
{
    /** Localiser for messages. */
    protected static final Localiser LOCALISER = Localiser.getInstance("org.jpox.Localisation",
        ObjectManagerFactoryImpl.class.getClassLoader());

    /** StateManager for the object we are managing the relationships for. */
    final StateManager ownerSM;

    /** Object being managed. */
    final Object pc;

    /**
     * Map of bidirectional field "changes".
     * For 1-1, N-1 fields the "change" is actually the original value (for later comparison).
     * For 1-N, M-N fields the "change" is an ArrayList of RelationChange objects.
     */
    final Map fieldChanges;

    /**
     * Constructor.
     * @param sm StateManager for the object that we are managing relations for.
     */
    public RelationshipManager(StateManager sm)
    {
        this.ownerSM = sm;
        this.pc = sm.getObject();
        this.fieldChanges = new HashMap();

        // Mark the StateManager as having its relations managed
        ownerSM.getObjectManager().markManagedRelationDirty(sm);
    }

    private static final int ADD_OBJECT = 1; // Element added to a collection
    private static final int REMOVE_OBJECT = 2; // Element removed from a collection

    /**
     * Definition of a change in a relation.
     * @version $Revision$
     */
    private class RelationChange
    {
        int type;
        Object value;
        public RelationChange(int type, Object val)
        {
            this.type = type;
            this.value = val;
        }
    }

    /**
     * Convenience method to clear all fields from being managed.
     */
    public void clearFields()
    {
        fieldChanges.clear();
    }

    /**
     * Method that is called when the user calls setXXX() on a field.
     * @param fieldNumber Number of the field
     * @param oldValue The old value
     * @param newValue The new value
     */
    public void relationChange(int fieldNumber, Object oldValue, Object newValue)
    {
        if (ownerSM.getObjectManager().isManagingRelations())
        {
            return;
        }

        Integer fieldKey = new Integer(fieldNumber);
        if (!fieldChanges.containsKey(fieldKey))
        {
            // Store the original value only - only good for PC fields really
            AbstractClassMetaData cmd = ownerSM.getClassMetaData();
            AbstractMemberMetaData mmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber);
            int relationType = mmd.getRelationType(ownerSM.getObjectManager().getClassLoaderResolver());
            if (relationType == Relation.ONE_TO_ONE_BI || relationType == Relation.MANY_TO_ONE_BI)
            {
                // Only allow for set of PC field (ignore set of Collection fields)
                fieldChanges.put(fieldKey, oldValue);
            }
        }
    }

    /**
     * Method to register a change in the contents of a container field, with an object being added.
     * @param fieldNumber Number of the field
     * @param val Value being added
     */
    public void relationAdd(int fieldNumber, Object val)
    {
        if (ownerSM.getObjectManager().isManagingRelations())
        {
            return;
        }

        AbstractClassMetaData cmd = ownerSM.getClassMetaData();
        AbstractMemberMetaData mmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber);
        int relationType = mmd.getRelationType(ownerSM.getObjectManager().getClassLoaderResolver());
        if (relationType != Relation.ONE_TO_MANY_BI && relationType != Relation.MANY_TO_MANY_BI)
        {
            return;
        }

        Integer fieldKey = new Integer(fieldNumber);
        Object changes = fieldChanges.get(fieldKey);
        ArrayList changeList = null;
        if (changes == null)
        {
            changeList = new ArrayList();
        }
        else
        {
            // Assume we have an ArrayList
            changeList = (ArrayList)changes;
        }
        RelationChange change = new RelationChange(ADD_OBJECT, val);
        changeList.add(change);
        fieldChanges.put(fieldKey, changeList);
    }

    /**
     * Method to register a change in the contents of a container field, with an object being removed.
     * @param fieldNumber Number of the field
     * @param val Value being removed
     */
    public void relationRemove(int fieldNumber, Object val)
    {
        if (ownerSM.getObjectManager().isManagingRelations())
        {
            return;
        }

        AbstractClassMetaData cmd = ownerSM.getClassMetaData();
        AbstractMemberMetaData mmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber);
        int relationType = mmd.getRelationType(ownerSM.getObjectManager().getClassLoaderResolver());
        if (relationType != Relation.ONE_TO_MANY_BI && relationType != Relation.MANY_TO_MANY_BI)
        {
            return;
        }

        Integer fieldKey = new Integer(fieldNumber);
        Object changes = fieldChanges.get(fieldKey);
        ArrayList changeList = null;
        if (changes == null)
        {
            changeList = new ArrayList();
        }
        else
        {
            changeList = (ArrayList)changes;
        }
        RelationChange change = new RelationChange(REMOVE_OBJECT, val);
        changeList.add(change);
    }

    /**
     * Accessor for whether a field is being managed.
     * @param fieldNumber Number of the field
     * @return Whether it is currently managed
     */
    private boolean managesField(int fieldNumber)
    {
        return fieldChanges.containsKey(new Integer(fieldNumber));
    }

    /**
     * Method to check for consistency the managed relations of this object with the related objects.
     */
    public void checkConsistency()
    {
        Set entries = fieldChanges.entrySet();
        Iterator iter = entries.iterator();
        AbstractClassMetaData cmd = ownerSM.getClassMetaData();
        ObjectManager om = ownerSM.getObjectManager();
        while (iter.hasNext())
        {
            Map.Entry entry = (Map.Entry)iter.next();
            int fieldNumber = ((Integer)entry.getKey()).intValue();
            AbstractMemberMetaData mmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber);
            ClassLoaderResolver clr = om.getClassLoaderResolver();
            Object oldValue = entry.getValue();
            int relationType = mmd.getRelationType(clr);
            if (relationType == Relation.ONE_TO_ONE_BI)
            {
                // 1-1 bidirectional
                Object newValue = ownerSM.provideField(fieldNumber);
                checkOneToOneBidirectionalRelation(mmd, clr, om, oldValue, newValue);
            }
            else if (relationType == Relation.MANY_TO_ONE_BI)
            {
                // N-1 bidirectional
                Object newValue = ownerSM.provideField(fieldNumber);
                checkManyToOneBidirectionalRelation(mmd, clr, om, oldValue, newValue);
            }
            else if (relationType == Relation.ONE_TO_MANY_BI)
            {
                // 1-N bidirectional
                ArrayList changes = (ArrayList)oldValue;
                checkOneToManyBidirectionalRelation(mmd, clr, om, changes);
            }
            else if (relationType == Relation.MANY_TO_MANY_BI)
            {
                // M-N bidirectional
                ArrayList changes = (ArrayList)oldValue;
                checkManyToManyBidirectionalRelation(mmd, clr, om, changes);
            }
        }
    }

    /**
     * Method to process the (bidirectional) relations for this object.
     */
    public void process()
    {
        Set entries = fieldChanges.entrySet();
        Iterator iter = entries.iterator();
        AbstractClassMetaData cmd = ownerSM.getClassMetaData();
        ObjectManager om = ownerSM.getObjectManager();
        while (iter.hasNext())
        {
            Map.Entry entry = (Map.Entry)iter.next();
            int fieldNumber = ((Integer)entry.getKey()).intValue();
            AbstractMemberMetaData mmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber);
            ClassLoaderResolver clr = om.getClassLoaderResolver();
            Object oldValue = entry.getValue();
            int relationType = mmd.getRelationType(clr);
            if (relationType == Relation.ONE_TO_ONE_BI)
            {
                // 1-1 bidirectional
                Object newValue = ownerSM.provideField(fieldNumber);
                processOneToOneBidirectionalRelation(mmd, clr, om, oldValue, newValue);
            }
            else if (relationType == Relation.MANY_TO_ONE_BI)
            {
                // N-1 bidirectional
                Object newValue = ownerSM.provideField(fieldNumber);
                processManyToOneBidirectionalRelation(mmd, clr, om, oldValue, newValue);
            }
            else if (relationType == Relation.ONE_TO_MANY_BI)
            {
                // 1-N bidirectional
                ArrayList changes = (ArrayList)oldValue;
                processOneToManyBidirectionalRelation(mmd, clr, om, changes);
            }
            else if (relationType == Relation.MANY_TO_MANY_BI)
            {
                // M-N bidirectional
                ArrayList changes = (ArrayList)oldValue;
                processManyToManyBidirectionalRelation(mmd, clr, om, changes);
            }
        }
    }

    /**
     * Method to check the consistency of the passed field as 1-1.
     * Processes the case where we had a 1-1 field set at this side previously to some value and now to
     * some other value. We need to make sure that all of the affected objects are now related consistently.
     * Taking an example <pre>a.b = b1; a.b = b2;</pre> so A's b field is changed from b1 to b2.
     * The following changes are likely to be necessary
     * <ul>
     * <li>b1.a = null - so we null out the old related objects link back to this object</li>
     * <li>b2.oldA = null - if b2 was previously related to a different A, null out that objects link to b2</li>
     * <li>b2.a = a - set the link from b2 back to a so it is bidirectional</li>
     * </ul>
     * @param mmd MetaData for the field
     * @param clr ClassLoader resolver
     * @param om ObjectManager
     * @param oldValue The old value
     * @param newValue The new value
     */
    protected void checkOneToOneBidirectionalRelation(AbstractMemberMetaData mmd,
            ClassLoaderResolver clr, ObjectManager om, Object oldValue, Object newValue)
    {
        if (newValue != null)
        {
            // Previously had "a.b = b1"; Now have "a.b = b2"
            // Check that the new value hasnt been assigned to something other than this object
            AbstractMemberMetaData relatedMmd = mmd.getRelatedMemberMetaDataForObject(clr, pc, newValue);
            org.jpox.StateManager newSM = om.findStateManager(newValue);
            if (newSM != null && relatedMmd != null)
            {
                newSM.loadField(relatedMmd.getAbsoluteFieldNumber());
                Object newValueFieldValue = newSM.provideField(relatedMmd.getAbsoluteFieldNumber());
                if (newValueFieldValue != pc)
                {
                    RelationshipManager newRelMgr = newSM.getRelationshipManager();
                    if (newRelMgr != null && newRelMgr.managesField(relatedMmd.getAbsoluteFieldNumber()))
                    {
                        // New value has had its side of the relation changed to a different value altogether!
                        if (newValueFieldValue == null)
                        {
                            String msg = LOCALISER.msg("013003",
                                StringUtils.toJVMIDString(pc), mmd.getName(),
                                StringUtils.toJVMIDString(newValue), relatedMmd.getName());
                            JPOXLogger.PERSISTENCE.error(msg);
                            throw new JPOXUserException(msg);
                        }
                        else
                        {
                            String msg = LOCALISER.msg("013002",
                                StringUtils.toJVMIDString(pc), mmd.getName(),
                                StringUtils.toJVMIDString(newValue), relatedMmd.getName(),
                                StringUtils.toJVMIDString(newValueFieldValue));
                            JPOXLogger.PERSISTENCE.error(msg);
                            throw new JPOXUserException(msg);
                        }
                    }
                }
            }
        }
    }

    /**
     * Method to check the consistency of the passed field as 1-N.
     * @param mmd MetaData for the field
     * @param clr ClassLoader resolver
     * @param om ObjectManager
     * @param changes List of changes to the collection
     */
    protected void checkOneToManyBidirectionalRelation(AbstractMemberMetaData mmd,
            ClassLoaderResolver clr, ObjectManager om, ArrayList changes)
    {
        Iterator iter = changes.iterator();
        while (iter.hasNext())
        {
            RelationChange change = (RelationChange)iter.next();
            if (change.type == ADD_OBJECT)
            {
                if (ownerSM.getObjectManager().getApiAdapter().isDeleted(change.value))
                {
                    // The element was added but was then the element object was deleted!
                    throw new JPOXUserException(LOCALISER.msg("013008",
                        StringUtils.toJVMIDString(pc), mmd.getName(), StringUtils.toJVMIDString(change.value)));
                }
                else
                {
                    AbstractMemberMetaData relatedMmd = mmd.getRelatedMemberMetaData(clr)[0];
                    org.jpox.StateManager newElementSM = om.findStateManager(change.value);
                    if (newElementSM != null)
                    {
                        newElementSM.loadField(relatedMmd.getAbsoluteFieldNumber());
                        RelationshipManager newElementRelMgr = newElementSM.getRelationshipManager();
                        if (newElementRelMgr != null && newElementRelMgr.managesField(relatedMmd.getAbsoluteFieldNumber()))
                        {
                            // Element has had the owner set, so make sure it is set to this object
                            Object newValueFieldValue = newElementSM.provideField(relatedMmd.getAbsoluteFieldNumber());
                            if (newValueFieldValue != pc && newValueFieldValue != null)
                            {
                                // The element has a different owner than the PC with this collection
                                // This catches cases where the user has set the wrong owner, and also
                                // will catch cases where the user has added it to two collections
                                throw new JPOXUserException(LOCALISER.msg(
                                    "013009",
                                    StringUtils.toJVMIDString(pc), mmd.getName(),
                                    StringUtils.toJVMIDString(change.value),
                                    StringUtils.toJVMIDString(newValueFieldValue)));
                            }
                        }
                    }
                }
            }
            else if (change.type == REMOVE_OBJECT)
            {
                if (ownerSM.getObjectManager().getApiAdapter().isDeleted(change.value))
                {
                    // The element was removed and was then the element object was deleted so do nothing
                }
                else
                {
                    AbstractMemberMetaData relatedMmd = mmd.getRelatedMemberMetaData(clr)[0];
                    org.jpox.StateManager newElementSM = om.findStateManager(change.value);
                    if (newElementSM != null)
                    {
                        newElementSM.loadField(relatedMmd.getAbsoluteFieldNumber());
                        RelationshipManager newElementRelMgr = newElementSM.getRelationshipManager();
                        if (newElementRelMgr != null && newElementRelMgr.managesField(relatedMmd.getAbsoluteFieldNumber()))
                        {
                            // Element has had the owner set, so make sure it is not set to this object
                            Object newValueFieldValue = newElementSM.provideField(relatedMmd.getAbsoluteFieldNumber());
                            if (newValueFieldValue == pc)
                            {
                                // The element was removed from the collection, but was updated to have its owner
                                // set to the collection owner!
                                throw new JPOXUserException(LOCALISER.msg(
                                    "013010",
                                    StringUtils.toJVMIDString(pc), mmd.getName(),
                                    StringUtils.toJVMIDString(change.value)));
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * Method to check the consistency of the passed field as N-1.
     * Processes the case where we had an N-1 field set at this side previously to some value and now to
     * some other value.That is, this object was in some collection/map originally, and now should be in some
     * other collection/map. So in terms of an example this object "a" was in collection "b1.as" before and is
     * now in "b2.as". The following changes are likely to be necessary
     * <ul>
     * <li>b1.getAs().remove(a) - remove it from b1.as if still present</li>
     * <li>b2.getAs().add(a) - add it to b1.as if not present</li>
     * </ul>
     * @param mmd MetaData for the field
     * @param clr ClassLoader resolver
     * @param om ObjectManager
     * @param oldValue The old value
     * @param newValue The new value
     */
    protected void checkManyToOneBidirectionalRelation(AbstractMemberMetaData mmd,
            ClassLoaderResolver clr, ObjectManager om, Object oldValue, Object newValue)
    {
        // TODO Implement N-1
    }

    /**
     * Method to check consistency of the passed field as M-N.
     * @param mmd MetaData for the field
     * @param clr ClassLoader resolver
     * @param om ObjectManager
     * @param changes List of changes to the collection
     */
    protected void checkManyToManyBidirectionalRelation(AbstractMemberMetaData mmd,
            ClassLoaderResolver clr, ObjectManager om, ArrayList changes)
    {
        // TODO Implement M-N
    }

    /**
     * Method to process all 1-1 bidir fields.
     * Processes the case where we had a 1-1 field set at this side previously to some value and now to
     * some other value. We need to make sure that all of the affected objects are now related consistently.
     * Taking an example <pre>a.b = b1; a.b = b2;</pre> so A's b field is changed from b1 to b2.
     * The following changes are likely to be necessary
     * <ul>
     * <li>b1.a = null - so we null out the old related objects link back to this object</li>
     * <li>b2.oldA = null - if b2 was previously related to a different A, null out that objects link to b2</li>
     * <li>b2.a = a - set the link from b2 back to a so it is bidirectional</li>
     * </ul>
     * @param mmd MetaData for the field
     * @param clr ClassLoader resolver
     * @param om ObjectManager
     * @param oldValue The old value
     * @param newValue The new value
     */
    protected void processOneToOneBidirectionalRelation(AbstractMemberMetaData mmd,
            ClassLoaderResolver clr, ObjectManager om, Object oldValue, Object newValue)
    {
        if (oldValue != null)
        {
            // Previously had "a.b = b1"; "a.b" has been changed
            // Need to remove from the other side if still set
            AbstractMemberMetaData relatedMmd = mmd.getRelatedMemberMetaDataForObject(clr, pc, oldValue);
            org.jpox.StateManager oldSM = om.findStateManager(oldValue);
            if (oldSM != null)
            {
                oldSM.loadField(relatedMmd.getAbsoluteFieldNumber());
                Object oldValueFieldValue = oldSM.provideField(relatedMmd.getAbsoluteFieldNumber());
                if (oldValueFieldValue == null)
                {
                    // Set to null so nothing to do
                }
                else if (oldValueFieldValue == pc)
                {
                    // Still set to this object, so null out the other objects relation
                    if (JPOXLogger.PERSISTENCE.isDebugEnabled())
                    {
                        JPOXLogger.PERSISTENCE.debug(
                            LOCALISER.msg("013004",
                            StringUtils.toJVMIDString(oldValue), relatedMmd.getFullFieldName(),
                            StringUtils.toJVMIDString(pc), StringUtils.toJVMIDString(newValue)));
                    }
                    oldSM.replaceFieldValue(relatedMmd.getAbsoluteFieldNumber(), null);
                }
            }
        }
        if (newValue != null)
        {
            // Previously had "a.b = b1"; Now have "a.b = b2"
            // Need to set the other side if not yet set, and unset any related old value on the other side
            AbstractMemberMetaData relatedMmd = mmd.getRelatedMemberMetaDataForObject(clr, pc, newValue);
            org.jpox.StateManager newSM = om.findStateManager(newValue);
            if (newSM != null && relatedMmd != null)
            {
                newSM.loadField(relatedMmd.getAbsoluteFieldNumber());
                Object newValueFieldValue = newSM.provideField(relatedMmd.getAbsoluteFieldNumber());
                if (newValueFieldValue == null)
                {
                    // Was set to null so set to our object
                    if (JPOXLogger.PERSISTENCE.isDebugEnabled())
                    {
                        JPOXLogger.PERSISTENCE.debug(
                            LOCALISER.msg("013005",
                                StringUtils.toJVMIDString(newValue), relatedMmd.getFullFieldName(),
                                StringUtils.toJVMIDString(pc)));
                    }
                    newSM.replaceFieldValue(relatedMmd.getAbsoluteFieldNumber(), pc);
                }
                else if (newValueFieldValue != pc)
                {
                    // Was set to different object, so null out the other objects relation
                    org.jpox.StateManager newValueFieldSM = om.findStateManager(newValueFieldValue);
                    if (newValueFieldSM != null)
                    {
                        // Null out the field of the related object of the new value
                        newValueFieldSM.loadField(mmd.getAbsoluteFieldNumber());
                        if (JPOXLogger.PERSISTENCE.isDebugEnabled())
                        {
                            JPOXLogger.PERSISTENCE.debug(
                                LOCALISER.msg("013004",
                                StringUtils.toJVMIDString(newValueFieldValue),
                                mmd.getFullFieldName(),
                                StringUtils.toJVMIDString(newValue), StringUtils.toJVMIDString(pc)));
                        }
                        newValueFieldSM.replaceFieldValue(mmd.getAbsoluteFieldNumber(), null);
                    }
                    // Update the field of the new value to our object
                    if (JPOXLogger.PERSISTENCE.isDebugEnabled())
                    {
                        JPOXLogger.PERSISTENCE.debug(
                            LOCALISER.msg("013005",
                                StringUtils.toJVMIDString(newValue), relatedMmd.getFullFieldName(),
                                StringUtils.toJVMIDString(pc)));
                    }
                    newSM.replaceFieldValue(relatedMmd.getAbsoluteFieldNumber(), pc);
                }
            }
        }
    }

    /**
     * Method to process all 1-N bidir fields.
     * @param mmd MetaData for the field
     * @param clr ClassLoader resolver
     * @param om ObjectManager
     * @param changes List of changes to the collection
     */
    protected void processOneToManyBidirectionalRelation(AbstractMemberMetaData mmd,
            ClassLoaderResolver clr, ObjectManager om, ArrayList changes)
    {
        Iterator iter = changes.iterator();
        while (iter.hasNext())
        {
            RelationChange change = (RelationChange)iter.next();
            if (change.type == ADD_OBJECT)
            {
            }
            else if (change.type == REMOVE_OBJECT)
            {  
            }
        }
        // TODO Implement 1-N
    }

    /**
     * Method to process all N-1 bidir fields.
     * Processes the case where we had an N-1 field set at this side previously to some value and now to
     * some other value.That is, this object was in some collection/map originally, and now should be in some
     * other collection/map. So in terms of an example this object "a" was in collection "b1.as" before and is
     * now in "b2.as". The following changes are likely to be necessary
     * <ul>
     * <li>b1.getAs().remove(a) - remove it from b1.as if still present</li>
     * <li>b2.getAs().add(a) - add it to b1.as if not present</li>
     * </ul>
     * @param mmd MetaData for the field
     * @param clr ClassLoader resolver
     * @param om ObjectManager
     * @param oldValue The old value
     * @param newValue The new value
     */
    protected void processManyToOneBidirectionalRelation(AbstractMemberMetaData mmd,
            ClassLoaderResolver clr, ObjectManager om, Object oldValue, Object newValue)
    {
        if (oldValue != null)
        {
            // Has been removed from a Collection/Map
            AbstractMemberMetaData relatedMmd = mmd.getRelatedMemberMetaDataForObject(clr, pc, oldValue);
            org.jpox.StateManager oldSM = om.findStateManager(oldValue);
            if (oldSM != null && relatedMmd != null)
            {
                oldSM.loadField(relatedMmd.getAbsoluteFieldNumber());
                Object oldContainerValue = oldSM.provideField(relatedMmd.getAbsoluteFieldNumber());
                if (oldContainerValue instanceof Collection)
                {
                    Collection oldColl = (Collection)oldContainerValue;
                    if (oldColl.contains(pc))
                    {
                        if (JPOXLogger.PERSISTENCE.isDebugEnabled())
                        {
                            JPOXLogger.PERSISTENCE.debug(
                                LOCALISER.msg("013006",
                                    StringUtils.toJVMIDString(pc), mmd.getFullFieldName(),
                                    relatedMmd.getFullFieldName(), StringUtils.toJVMIDString(oldValue)));
                        }

                        if (oldColl instanceof SCOCollection)
                        {
                            // Avoid any cascade deletes that could have been fired by this action
                            ((SCOCollection)oldColl).remove(pc, false);
                        }
                        else
                        {
                            oldColl.remove(pc);
                        }
                    }
                }
            }
        }
        if (newValue != null)
        {
            // Has been added to a Collection/Map
            AbstractMemberMetaData relatedMmd = mmd.getRelatedMemberMetaDataForObject(clr, pc, newValue);
            org.jpox.StateManager newSM = om.findStateManager(newValue);
            if (newSM != null && relatedMmd != null)
            {
                newSM.loadField(relatedMmd.getAbsoluteFieldNumber());
                Object newContainerValue = newSM.provideField(relatedMmd.getAbsoluteFieldNumber());
                if (newContainerValue instanceof Collection)
                {
                    Collection newColl = (Collection)newContainerValue;
                    if (!newColl.contains(pc))
                    {
                        if (JPOXLogger.PERSISTENCE.isDebugEnabled())
                        {
                            JPOXLogger.PERSISTENCE.debug(
                                LOCALISER.msg("013007",
                                    StringUtils.toJVMIDString(pc), mmd.getFullFieldName(),
                                    relatedMmd.getFullFieldName(), StringUtils.toJVMIDString(newValue)));
                        }
                        newColl.add(pc);
                    }
                }
            }
        }
    }

    /**
     * Method to process all M-N bidir fields.
     * @param mmd MetaData for the field
     * @param clr ClassLoader resolver
     * @param om ObjectManager
     * @param changes List of changes to the collection
     */
    protected void processManyToManyBidirectionalRelation(AbstractMemberMetaData mmd,
            ClassLoaderResolver clr, ObjectManager om, ArrayList changes)
    {
        // TODO Implement M-N
    }
}
TOP

Related Classes of org.jpox.state.RelationshipManager$RelationChange

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.