Package org.jpox.store.fieldmanager

Source Code of org.jpox.store.fieldmanager.AttachFieldManager

/**********************************************************************
Copyright (c) 2004 Erik Bengtson 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:
2005 Andy Jefferson - cater for object not being persistent
2007 Andy Jefferson - attach in-situ
    ...
**********************************************************************/
package org.jpox.store.fieldmanager;

import java.util.Collection;
import java.util.Map;

import org.jpox.ObjectManagerFactoryImpl;
import org.jpox.StateManager;
import org.jpox.api.ApiAdapter;
import org.jpox.metadata.AbstractClassMetaData;
import org.jpox.metadata.AbstractMemberMetaData;
import org.jpox.sco.SCO;
import org.jpox.sco.SCOContainer;
import org.jpox.sco.SCOUtils;
import org.jpox.util.JPOXLogger;
import org.jpox.util.Localiser;
import org.jpox.util.StringUtils;

/**
* Utility class to handle the attach of fields.
* The attachment process has 2 distinct cases to cater for.
* <OL>
* <LI>The object was detached, has been updated, and needs reattaching.</LI>
* <LI>The object was detached from a different datastore, and is being attached here.</LI>
* </OL>
* In the first case, the fields which are dirty have their values (and dirty flags) updated.
* In the second case, all fields have their fields (and dirty flags) updated.
* In addition this field manager allows attaching a copy, or attaching in-situ
*
* @version $Revision: 1.14 $
*/
public class AttachFieldManager extends AbstractFieldManager
{
    /** Localiser for internationalisation. */
    protected static final Localiser LOCALISER = Localiser.getInstance("org.jpox.Localisation",
        ObjectManagerFactoryImpl.class.getClassLoader());

    /** the attached instance */
    private final StateManager smAttached;

    /** The second class mutable fields. */
    private final boolean[] secondClassMutableFields;

    /** The dirty fields. */
    private final boolean dirtyFields[];

    /** Whether the attached instance is persistent yet. */
    private final boolean persistent;

    /** Whether to cascade the attach to related fields. */
    private final boolean cascadeAttach;

    /** Whether we should create attached copies, or attach in situ. */
    boolean copy = true;

    /**
     * Constructor.
     * @param smAttached the attached instance
     * @param secondClassMutableFields second class mutable field flags
     * @param dirtyFields dirty field flags
     * @param persistent whether the object is persistent
     * @param cascadeAttach Whether to cascade any attach calls to related fields
     */
    public AttachFieldManager(StateManager smAttached,
                              boolean secondClassMutableFields[],
                              boolean dirtyFields[],
                              boolean persistent,
                              boolean cascadeAttach,
                              boolean copy)
    {
        this.smAttached = smAttached;
        this.secondClassMutableFields = secondClassMutableFields;
        this.dirtyFields = dirtyFields;
        this.persistent = persistent;
        this.cascadeAttach = cascadeAttach;
        this.copy = copy;
    }

    /**
     * Method to store an object field into the attached instance.
     * @param fieldNumber Number of the field to store
     * @param value the value in the detached instance
     */
    public void storeObjectField(int fieldNumber, Object value)
    {
        // Note : when doing updates always do replaceField first and makeDirty after since the replaceField
        // can cause flush() to be called meaning that an update with null would be made before the new value
        // makes it into the field
        ApiAdapter api = smAttached.getObjectManager().getApiAdapter();
        if (value == null)
        {
            Object oldValue = null;
            AbstractClassMetaData cmd = smAttached.getClassMetaData();
            AbstractMemberMetaData fmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber);
            if (fmd.isDependent())
            {
                try
                {
                    // Get any old value of this field so we can do cascade-delete if being nulled
                    smAttached.loadFieldFromDatastore(fieldNumber);
                }
                catch (Exception e)
                {
                    // Error loading the field so didnt exist before attaching anyway
                }
                oldValue = smAttached.provideField(fieldNumber);
            }

            if (dirtyFields[fieldNumber] || !persistent)
            {
                smAttached.replaceField(fieldNumber, null, true);
                smAttached.makeDirty(fieldNumber);
            }

            if (fmd.isDependent() && !fmd.isEmbedded() &&
                oldValue != null && value == null && api.isPersistable(oldValue))
            {
                // Check for a field storing a PC where it is being nulled and the other object is dependent
                smAttached.flush(); // Flush the nulling of the field
                JPOXLogger.PERSISTENCE.debug(LOCALISER.msg("026026", oldValue, fmd.getFullFieldName()));
                smAttached.getObjectManager().deleteObjectInternal(oldValue);
            }
        }
        else if (secondClassMutableFields[fieldNumber])
        {
            AbstractMemberMetaData fmd =
                smAttached.getClassMetaData().getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber);
            if (fmd.isSerialized())
            {
                // SCO Field is serialised so just update the column with this new value - dont do comparisons yet
                smAttached.replaceField(fieldNumber, value, true);
                smAttached.makeDirty(fieldNumber);
            }
            else
            {
                // Make sure that the value is a SCO wrapper
                Object oldValue = smAttached.provideField(fieldNumber);
                SCO sco;
                if (oldValue == null || (oldValue != null && !(oldValue instanceof SCO)))
                {
                    // The field wasn't initialised at creation, so create an empty SCO wrapper and copy the new values in
                    if (JPOXLogger.JDO.isDebugEnabled())
                    {
                        JPOXLogger.JDO.debug(LOCALISER.msg("026029", StringUtils.toJVMIDString(smAttached.getObject()),
                            smAttached.getInternalObjectId(), fmd.getName()));
                    }
                    sco = SCOUtils.newSCOInstance(smAttached, fmd, fmd.getType(), null, null, false, false, false);
                    if (sco instanceof SCOContainer)
                    {
                        // Load any containers to avoid update issues
                        ((SCOContainer)sco).load();
                    }
                    smAttached.replaceField(fieldNumber, sco, true);
                }
                else
                {
                    // The field is already a SCO wrapper, so just copy the new values to it
                    sco = (SCO) oldValue;
                }

                if (cascadeAttach)
                {
                    // Only trigger the cascade when required
                    if (copy)
                    {
                        // Attach copy of the SCO
                        sco.attachCopy(value);
                    }
                    else
                    {
                        // Attach SCO in-situ
                        if (sco instanceof Collection)
                        {
                            // Attach all PC elements of the collection
                            boolean elementsWithoutIdentity = SCOUtils.collectionHasElementsWithoutIdentity(fmd);
                            SCOUtils.attachForCollection(smAttached, ((Collection)sco).toArray(), elementsWithoutIdentity);
                            sco.unsetOwner();
                        }
                        else if (sco instanceof Map)
                        {
                            // Attach all PC keys/values of the map
                            boolean keysWithoutIdentity = SCOUtils.mapHasKeysWithoutIdentity(fmd);
                            boolean valuesWithoutIdentity = SCOUtils.mapHasValuesWithoutIdentity(fmd);
                            SCOUtils.attachForMap(smAttached, ((Map)sco).entrySet(), keysWithoutIdentity, valuesWithoutIdentity);
                            sco.unsetOwner();
                        }
                        else
                        {
                            // Initialise the SCO with the new value
                            sco.initialise(value, false, false);
                        }
                    }
                }

                if (dirtyFields[fieldNumber] || !persistent)
                {
                    smAttached.makeDirty(fieldNumber);
                }
            }
        }
        else if (api.isPersistable(value))
        {
            // Field containing PC object
            if (cascadeAttach)
            {
                // Determine if field is "second-class" (no identity) - if has "embedded" info or serialised
                AbstractMemberMetaData fmd =
                    smAttached.getClassMetaData().getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber);
                boolean sco = (fmd.getEmbeddedMetaData() != null || fmd.isSerialized() || fmd.isEmbedded());

                if (copy)
                {
                    // Attach copy of the PC
                    Object pcObj = smAttached.getObjectManager().attachObjectCopy(value, sco);
                    smAttached.replaceField(fieldNumber, pcObj, true);
                }
                else
                {
                    // Attach PC in-situ
                    smAttached.getObjectManager().attachObject(value, sco);
                }

                // Make sure the field is marked as dirty
                if (dirtyFields[fieldNumber] || !persistent)
                {
                    smAttached.makeDirty(fieldNumber);
                }
                else if (sco && value != null && smAttached.getObjectManager().getApiAdapter().isDirty(value))
                {
                    smAttached.makeDirty(fieldNumber);
                }
            }
            else if (dirtyFields[fieldNumber] || !persistent)
            {
                smAttached.makeDirty(fieldNumber);
            }
        }
        else
        {
            if (dirtyFields[fieldNumber] || !persistent)
            {
                smAttached.replaceField(fieldNumber, value, true);
                smAttached.makeDirty(fieldNumber);
            }
        }
    }

    /*
     * (non-Javadoc)
     * @see FieldConsumer#storeBooleanField(int, boolean)
     */
    public void storeBooleanField(int fieldNumber, boolean value)
    {
        if (dirtyFields[fieldNumber] || !persistent)
        {
            SingleValueFieldManager sfv = new SingleValueFieldManager();
            sfv.storeBooleanField(fieldNumber, value);
            smAttached.replaceFields(new int[]{fieldNumber}, sfv);
            smAttached.makeDirty(fieldNumber);
        }
    }

    /*
     * (non-Javadoc)
     * @see FieldConsumer#storeByteField(int, byte)
     */
    public void storeByteField(int fieldNumber, byte value)
    {
        if (dirtyFields[fieldNumber] || !persistent)
        {
            SingleValueFieldManager sfv = new SingleValueFieldManager();
            sfv.storeByteField(fieldNumber, value);
            smAttached.replaceFields(new int[]{fieldNumber}, sfv);
            smAttached.makeDirty(fieldNumber);
        }
    }

    /*
     * (non-Javadoc)
     * @see FieldConsumer#storeCharField(int, char)
     */
    public void storeCharField(int fieldNumber, char value)
    {
        if (dirtyFields[fieldNumber] || !persistent)
        {
            SingleValueFieldManager sfv = new SingleValueFieldManager();
            sfv.storeCharField(fieldNumber, value);
            smAttached.replaceFields(new int[]{fieldNumber}, sfv);
            smAttached.makeDirty(fieldNumber);
        }
    }

    /*
     * (non-Javadoc)
     * @see FieldConsumer#storeDoubleField(int, double)
     */
    public void storeDoubleField(int fieldNumber, double value)
    {
        if (dirtyFields[fieldNumber] || !persistent)
        {
            SingleValueFieldManager sfv = new SingleValueFieldManager();
            sfv.storeDoubleField(fieldNumber, value);
            smAttached.replaceFields(new int[]{fieldNumber}, sfv);
            smAttached.makeDirty(fieldNumber);
        }
    }

    /*
     * (non-Javadoc)
     * @see FieldConsumer#storeFloatField(int, float)
     */
    public void storeFloatField(int fieldNumber, float value)
    {
        if (dirtyFields[fieldNumber] || !persistent)
        {
            SingleValueFieldManager sfv = new SingleValueFieldManager();
            sfv.storeFloatField(fieldNumber, value);
            smAttached.replaceFields(new int[]{fieldNumber}, sfv);
            smAttached.makeDirty(fieldNumber);
        }
    }

    /*
     * (non-Javadoc)
     * @see FieldConsumer#storeIntField(int, int)
     */
    public void storeIntField(int fieldNumber, int value)
    {
        if (dirtyFields[fieldNumber] || !persistent)
        {
            SingleValueFieldManager sfv = new SingleValueFieldManager();
            sfv.storeIntField(fieldNumber, value);
            smAttached.replaceFields(new int[]{fieldNumber}, sfv);
            smAttached.makeDirty(fieldNumber);
        }
    }

    /*
     * (non-Javadoc)
     * @see FieldConsumer#storeLongField(int, long)
     */
    public void storeLongField(int fieldNumber, long value)
    {
        if (dirtyFields[fieldNumber] || !persistent)
        {
            SingleValueFieldManager sfv = new SingleValueFieldManager();
            sfv.storeLongField(fieldNumber, value);
            smAttached.replaceFields(new int[]{fieldNumber}, sfv);
            smAttached.makeDirty(fieldNumber);
        }
    }

    /*
     * (non-Javadoc)
     * @see FieldConsumer#storeShortField(int, short)
     */
    public void storeShortField(int fieldNumber, short value)
    {
        if (dirtyFields[fieldNumber] || !persistent)
        {
            SingleValueFieldManager sfv = new SingleValueFieldManager();
            sfv.storeShortField(fieldNumber, value);
            smAttached.replaceFields(new int[]{fieldNumber}, sfv);
            smAttached.makeDirty(fieldNumber);
        }
    }

    /*
     * (non-Javadoc)
     * @see FieldConsumer#storeStringField(int, java.lang.String)
     */
    public void storeStringField(int fieldNumber, String value)
    {
        if (dirtyFields[fieldNumber] || !persistent)
        {
            SingleValueFieldManager sfv = new SingleValueFieldManager();
            sfv.storeStringField(fieldNumber, value);
            smAttached.replaceFields(new int[]{fieldNumber}, sfv);
            smAttached.makeDirty(fieldNumber);
        }
    }
}
TOP

Related Classes of org.jpox.store.fieldmanager.AttachFieldManager

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.