Package org.datanucleus.store.mapped.scostore

Source Code of org.datanucleus.store.mapped.scostore.FKArrayStore

/**********************************************************************
Copyright (c) 2005 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.datanucleus.store.mapped.scostore;

import java.lang.reflect.Array;

import org.datanucleus.ClassLoaderResolver;
import org.datanucleus.exceptions.NucleusUserException;
import org.datanucleus.metadata.AbstractMemberMetaData;
import org.datanucleus.metadata.ArrayMetaData;
import org.datanucleus.store.ObjectProvider;
import org.datanucleus.store.mapped.MappedStoreManager;
import org.datanucleus.store.mapped.mapping.MappingConsumer;
import org.datanucleus.util.ClassUtils;
import org.datanucleus.util.NucleusLogger;

/**
* Backing store for an array that is formed by a foreign key in the table of the
* element type. Only supported when the element is a PersistenceCapable type (since
* that has its own element table, capable of having a FK!)
*/
public abstract class FKArrayStore extends AbstractArrayStore
{
    /**
     * Constructor.
     * @param fmd Field MetaData for the field that this represents
     * @param storeMgr The Store Manager in use
     * @param clr The ClassLoaderResolver
     */
    public FKArrayStore(AbstractMemberMetaData fmd, MappedStoreManager storeMgr, ClassLoaderResolver clr,
                        FKArrayStoreSpecialization specialization)
    {
        super(storeMgr, clr, specialization);

        setOwner(fmd, clr);
        ArrayMetaData arrmd = fmd.getArray();
        if (arrmd == null)
        {
            throw new NucleusUserException(LOCALISER.msg("056000", fmd.getFullFieldName()));
        }

        // Load the element class
        elementType = fmd.getType().getComponentType().getName();
        Class element_class = clr.classForName(elementType);

        if (ClassUtils.isReferenceType(element_class))
        {
            // Take the metadata for the first implementation of the reference type
            emd = storeMgr.getNucleusContext().getMetaDataManager().getMetaDataForImplementationOfReference(element_class,null,clr);
            if (emd != null)
            {
                // Pretend we have a relationship with this one implementation
                elementType = emd.getFullClassName();
            }
        }
        else
        {
            // Check that the element class has MetaData
            emd = storeMgr.getNucleusContext().getMetaDataManager().getMetaDataForClass(element_class, clr);
        }
        if (emd == null)
        {
            throw new NucleusUserException(LOCALISER.msg("056003", element_class.getName(), fmd.getFullFieldName()));
        }

        elementInfo = getElementInformationForClass();
        if (elementInfo != null && elementInfo.length > 1)
        {
            throw new NucleusUserException(LOCALISER.msg("056045",
                ownerMemberMetaData.getFullFieldName()));
        }

        elementMapping = elementInfo[0].getDatastoreClass().getIdMapping(); // Just use the first element type as the guide for the element mapping
        elementsAreEmbedded = false; // Can't embed element when using FK relation
        elementsAreSerialised = false; // Can't serialise element when using FK relation

        // Get the field in the element table (if any)
        String mappedByFieldName = fmd.getMappedBy();
        if (mappedByFieldName != null)
        {
            // 1-N FK bidirectional
            // The element class has a field for the owner.
            AbstractMemberMetaData eofmd = storeMgr.getNucleusContext().getMetaDataManager().getMetaDataForMember(element_class, clr, mappedByFieldName);
            if (eofmd == null)
            {
                throw new NucleusUserException(LOCALISER.msg("056024", fmd.getFullFieldName(),
                    mappedByFieldName, element_class.getName()));
            }

            // Check that the type of the element "mapped-by" field is consistent with the owner type
            if (!clr.isAssignableFrom(eofmd.getType(), fmd.getAbstractClassMetaData().getFullClassName()))
            {
                throw new NucleusUserException(LOCALISER.msg("056025", fmd.getFullFieldName(),
                    eofmd.getFullFieldName(), eofmd.getTypeName(), fmd.getAbstractClassMetaData().getFullClassName()));
            }

            String ownerFieldName = eofmd.getName();
            ownerMapping = elementInfo[0].getDatastoreClass().getMemberMapping(eofmd);
            if (ownerMapping == null)
            {
                throw new NucleusUserException(LOCALISER.msg("056046",
                    fmd.getAbstractClassMetaData().getFullClassName(), fmd.getName(), elementType, ownerFieldName));
            }
            if (isEmbeddedMapping(ownerMapping))
            {
                throw new NucleusUserException(LOCALISER.msg("056026",
                    ownerFieldName, elementType, eofmd.getTypeName(), fmd.getClassName()));
            }
        }
        else
        {
            // 1-N FK unidirectional
            // The element class knows nothing about the owner (but the table has external mappings)
            ownerMapping = elementInfo[0].getDatastoreClass().getExternalMapping(fmd, MappingConsumer.MAPPING_TYPE_EXTERNAL_FK);
            if (ownerMapping == null)
            {
                throw new NucleusUserException(LOCALISER.msg("056047",
                    fmd.getAbstractClassMetaData().getFullClassName(), fmd.getName(), elementType));
            }
        }

        orderMapping = elementInfo[0].getDatastoreClass().getExternalMapping(fmd, MappingConsumer.MAPPING_TYPE_EXTERNAL_INDEX);
        if (orderMapping == null)
        {
            throw new NucleusUserException(LOCALISER.msg("056048",
                fmd.getAbstractClassMetaData().getFullClassName(), fmd.getName(), elementType));
        }

        relationDiscriminatorMapping = elementInfo[0].getDatastoreClass().getExternalMapping(fmd, MappingConsumer.MAPPING_TYPE_EXTERNAL_FK_DISCRIM);
        if (relationDiscriminatorMapping != null)
        {
            relationDiscriminatorValue = fmd.getValueForExtension("relation-discriminator-value");
            if (relationDiscriminatorValue == null)
            {
                // No value defined so just use the field name
                relationDiscriminatorValue = fmd.getFullFieldName();
            }
        }

        // TODO Cater for multiple element tables
        containerTable = elementInfo[0].getDatastoreClass();
        if (fmd.getMappedBy() != null && ownerMapping.getDatastoreContainer() != containerTable)
        {
            // Element and owner don't have consistent tables so use the one with the mapping
            // e.g collection is of subclass, yet superclass has the link back to the owner
            containerTable = ownerMapping.getDatastoreContainer();
        }
    }

    private FKArrayStoreSpecialization getSpecialization()
    {
        return (FKArrayStoreSpecialization) specialization;
    }

    /**
     * Update a FK and element position in the element.
     * @param ownerSM StateManager for the owner
     * @param element The element to update
     * @param owner The owner object to set in the FK
     * @param index The index position (or -1 if not known)
     * @return Whether it was performed successfully
     */
    private boolean updateElementFk(ObjectProvider ownerSM, Object element, Object owner, int index)
    {
        if (element == null)
        {
            return false;
        }

        return getSpecialization().getUpdateElementFk(ownerSM, element, owner, index, this);
    }

    /**
     * Method to clear the Array.
     * This is called when the container object is being deleted and the elements are to be removed (maybe for dependent field).
     * @param ownerSM The state manager
     **/
    public void clear(ObjectProvider ownerSM)
    {
        boolean deleteElements = false;
        if (ownerMemberMetaData.getArray().isDependentElement())
        {
            // Elements are dependent and can't exist on their own, so delete them all
            NucleusLogger.DATASTORE.debug(LOCALISER.msg("056034"));
            deleteElements = true;
        }
        else
        {
            if (ownerMapping.isNullable() && orderMapping.isNullable())
            {
                // Field is not dependent, and nullable so we null the FK
                NucleusLogger.DATASTORE.debug(LOCALISER.msg("056036"));
                deleteElements = false;
            }
            else
            {
                // Field is not dependent, and not nullable so we just delete the elements
                NucleusLogger.DATASTORE.debug(LOCALISER.msg("056035"));
                deleteElements = true;
            }
        }

        if (deleteElements)
        {
            ownerSM.getExecutionContext().getApiAdapter().isLoaded(ownerSM, ownerMemberMetaData.getAbsoluteFieldNumber()); // Make sure the field is loaded
            Object[] value = (Object[]) ownerSM.provideField(ownerMemberMetaData.getAbsoluteFieldNumber());
            if (value != null && value.length > 0)
            {
                ownerSM.getExecutionContext().deleteObjects(value);
            }
        }
        else
        {
            getSpecialization().clear(ownerSM, this);
        }
    }

    /**
     * Method to set the array for the specified owner to the passed value.
     * @param ownerSM State Manager for the owner
     * @param array the array
     * @return Whether the array was updated successfully
     */
    public boolean set(ObjectProvider ownerSM, Object array)
    {
        if (array == null)
        {
            return true;
        }

        // Check that all elements are inserted
        for (int i=0;i<Array.getLength(array);i++)
        {
            validateElementForWriting(ownerSM, Array.get(array, i), null);
        }

        // Update the FK and position of all elements
        int length = Array.getLength(array);
        for (int i=0;i<length;i++)
        {
            Object obj = Array.get(array, i);
            updateElementFk(ownerSM, obj, ownerSM.getObject(), i);
        }

        return true;
    }
}
TOP

Related Classes of org.datanucleus.store.mapped.scostore.FKArrayStore

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.