Package org.datanucleus.store.mapped

Source Code of org.datanucleus.store.mapped.MappedStoreManager

/**********************************************************************
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.datanucleus.store.mapped;

import org.datanucleus.ClassLoaderResolver;
import org.datanucleus.FetchPlan;
import org.datanucleus.OMFContext;
import org.datanucleus.PersistenceConfiguration;
import org.datanucleus.StateManager;
import org.datanucleus.api.ApiAdapter;
import org.datanucleus.metadata.AbstractClassMetaData;
import org.datanucleus.metadata.AbstractMemberMetaData;
import org.datanucleus.metadata.InheritanceStrategy;
import org.datanucleus.sco.IncompatibleFieldTypeException;
import org.datanucleus.sco.SCOUtils;
import org.datanucleus.state.ActivityState;
import org.datanucleus.store.AbstractStoreManager;
import org.datanucleus.store.StoreData;
import org.datanucleus.store.StoreManagerFactory;
import org.datanucleus.store.exceptions.NoTableManagedException;
import org.datanucleus.store.fieldmanager.FieldManager;
import org.datanucleus.store.mapped.mapping.ArrayMapping;
import org.datanucleus.store.mapped.mapping.CollectionMapping;
import org.datanucleus.store.mapped.mapping.DatastoreMapping;
import org.datanucleus.store.mapped.mapping.JavaTypeMapping;
import org.datanucleus.store.mapped.mapping.MapMapping;
import org.datanucleus.store.mapped.mapping.MappingManager;
import org.datanucleus.store.mapped.scostore.FKArrayStore;
import org.datanucleus.store.mapped.scostore.FKListStore;
import org.datanucleus.store.mapped.scostore.FKMapStore;
import org.datanucleus.store.mapped.scostore.FKSetStore;
import org.datanucleus.store.mapped.scostore.JoinArrayStore;
import org.datanucleus.store.mapped.scostore.JoinListStore;
import org.datanucleus.store.mapped.scostore.JoinMapStore;
import org.datanucleus.store.mapped.scostore.JoinSetStore;
import org.datanucleus.store.query.ResultObjectFactory;
import org.datanucleus.store.scostore.ArrayStore;
import org.datanucleus.store.scostore.CollectionStore;
import org.datanucleus.store.scostore.MapStore;
import org.datanucleus.store.scostore.Store;
import org.datanucleus.util.NucleusLogger;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
* Manager for a datastore that has a schema and maps classes to associated objects in the datastore.
* Datastores such as RDBMS will extend this type of StoreManager.
* <p>
* In a "mapped" datastore, a class is associated with a DatastoreClass. Similarly a field of a class is associated
* with a DatastoreField. Where a relation is stored separately this is associated with a DatastoreContainerObject.
* In an RDBMS datastore this will be
* <ul>
* <li>class <-> table</li>
* <li>field <-> column</li>
* <li>relation <-> join-table / foreign-key</li>
* </ul>
* </p>
* <p>
* This type of StoreManager allows creation/validation of the schema. A schema is split into
* "tables", "columns", "constraints" currently. The PMF/EMF allows specification of a set of properties
* that will apply to this type of datastore.
* </p>
*/
public abstract class MappedStoreManager extends AbstractStoreManager
{
    /** Adapter for the datastore being used. */
    protected DatastoreAdapter dba;

    /** Factory for identifiers for this datastore. Really should be on MappedStoreManager. */
    protected IdentifierFactory identifierFactory;

    /** Whether to auto create any tables. */
    protected final boolean autoCreateTables;

    /** Whether to auto create any columns that are missing. */
    protected final boolean autoCreateColumns;

    /** Whether to auto create any constraints */
    protected final boolean autoCreateConstraints;

    /** Whether to warn only when any errors occur on auto-create. */
    protected final boolean autoCreateWarnOnError;

    /** Whether to validate any tables */
    protected final boolean validateTables;

    /** Whether to validate any columns */
    protected final boolean validateColumns;

    /** Whether to validate any constraints */
    protected final boolean validateConstraints;

    /**
     * Map of all managed datastore containers (tables) keyed by the datastore identifier.
     * Only currently used for storing SequenceTable.
     */
    protected Map<DatastoreIdentifier, DatastoreContainerObject> datastoreContainerByIdentifier = new HashMap();

    /** TypeManager for mapped information. */
    protected MappedTypeManager mappedTypeMgr = null;

    /** Manager for the mapping between Java and datastore types. */
    protected MappingManager mappingManager;

    /**
     * Map of DatastoreClass keyed by StateManager, for objects currently being inserted.
     * Defines to what level an object is inserted in the datastore.
     */
    protected Map<StateManager, DatastoreClass> insertedDatastoreClassByStateManager = new HashMap();

    /**
     * Constructor. Stores the basic information required for the datastore management.
     * @param key Key for this StoreManager
     * @param clr the ClassLoaderResolver
     * @param omfContext The corresponding ObjectManagerFactory context.
     * @see StoreManagerFactory
     */
    protected MappedStoreManager(String key, ClassLoaderResolver clr, OMFContext omfContext)
    {
        super(key, clr, omfContext);

        PersistenceConfiguration conf = omfContext.getPersistenceConfiguration();
        if (readOnlyDatastore || fixedDatastore)
        {
            autoCreateTables = false;
            autoCreateColumns = false;
            autoCreateConstraints = false;
        }
        else
        {
            boolean autoCreateSchema = conf.getBooleanProperty("datanucleus.autoCreateSchema");
            if (autoCreateSchema)
            {
                autoCreateTables = true;
                autoCreateColumns = true;
                autoCreateConstraints = true;
            }
            else
            {
                autoCreateColumns = conf.getBooleanProperty("datanucleus.autoCreateColumns");
                autoCreateTables = conf.getBooleanProperty("datanucleus.autoCreateTables");
                autoCreateConstraints = conf.getBooleanProperty("datanucleus.autoCreateConstraints");
            }
        }
        autoCreateWarnOnError = conf.getBooleanProperty("datanucleus.autoCreateWarnOnError");

        validateTables = conf.getBooleanProperty("datanucleus.validateTables");
        if (!validateTables)
        {
            validateColumns = false;
        }
        else
        {
            validateColumns = conf.getBooleanProperty("datanucleus.validateColumns");
        }
        validateConstraints = conf.getBooleanProperty("datanucleus.validateConstraints");

        mappedTypeMgr = new MappedTypeManager(omfContext);
    }

    /* (non-Javadoc)
     * @see org.datanucleus.store.StoreManager#close()
     */
    public void close()
    {
        dba = null;
        super.close();
    }

    /**
     * Accessor for whether this value strategy is supported.
     * Overrides the setting in the superclass for identity/sequence if the adapter doesn't
     * support them.
     * @param strategy The strategy
     * @return Whether it is supported.
     */
    public boolean supportsValueStrategy(String strategy)
    {
        // "identity" doesn't have an explicit entry in plugin since uses datastore capabilities
        if (strategy.equalsIgnoreCase("IDENTITY") || super.supportsValueStrategy(strategy))
        {
            if (strategy.equalsIgnoreCase("IDENTITY") && !dba.supportsOption(DatastoreAdapter.IDENTITY_COLUMNS))
            {
                return false; // adapter doesn't support identity so we don't
            }
            else if (strategy.equalsIgnoreCase("SEQUENCE") && !dba.supportsOption(DatastoreAdapter.SEQUENCES))
            {
                return false; // adapter doesn't support sequences so we don't
            }
            return true;
        }
        return false;
    }

    /**
     * Accessor for the manager of mapped type information.
     * @return MappedTypeManager
     */
    public MappedTypeManager getMappedTypeManager()
    {
        return mappedTypeMgr;
    }

    /**
     * Accessor for the factory for creating identifiers (table/column names etc).
     * @return Identifier factory
     */
    public IdentifierFactory getIdentifierFactory()
    {
        return identifierFactory;
    }

    /**
     * Gets the DatastoreAdapter to use for this store.
     * @return Returns the DatastoreAdapter
     */
    public DatastoreAdapter getDatastoreAdapter()
    {
        return dba;
    }

    /**
     * Gets the MappingManager to use for this store.
     * @return Returns the MappingManager.
     */
    public MappingManager getMappingManager()
    {
        if (mappingManager == null)
        {
            mappingManager = dba.getMappingManager(this);
        }
        return mappingManager;
    }

    /**
     * Called by Mapping objects to request the creation of a DatastoreObject (table).
     * @param fmd The field metadata describing the field.
     * @param clr The ClassLoaderResolver
     * @return The DatastoreContainerObject
     */
    public abstract DatastoreContainerObject newJoinDatastoreContainerObject(AbstractMemberMetaData fmd,
            ClassLoaderResolver clr);

    /**
     * Utility to return all StoreData for a Datastore Container identifier.
     * Returns StoreData with this table identifier and where the class is the owner of the table.
     * @param tableIdentifier Identifier for the table
     * @return The StoreData for this table (if managed).
     */
    public synchronized StoreData[] getStoreDataForDatastoreContainerObject(DatastoreIdentifier tableIdentifier)
    {
        return storeDataMgr.getStoreDataForProperties("tableId", tableIdentifier, "table-owner", "true");
    }

    /**
     * Returns the datastore container (table) for the specified field.
     * Returns 'null' if the field is not (yet) known to the store manager.
     * @param fmd The metadata for the field.
     * @return The corresponding datastore container, or 'null'.
     */
    public synchronized DatastoreContainerObject getDatastoreContainerObject(AbstractMemberMetaData fmd)
    {
        StoreData sd = storeDataMgr.get(fmd);
        if (sd != null && sd instanceof MappedStoreData)
        {
            return ((MappedStoreData)sd).getDatastoreContainerObject();
        }
        else
        {
            return null;
        }
    }

    /**
     * Method to add a datastore container to the managed datastore classes.
     * @param table The datastore container
     */
    public void addDatastoreContainer(DatastoreContainerObject table)
    {
        if (table != null && datastoreContainerByIdentifier.get(table.getIdentifier()) == null)
        {
            datastoreContainerByIdentifier.put(table.getIdentifier(), table);
        }
    }

    /**
     * Returns the primary datastore table serving as backing for the given class.
     * If the class is not yet known to the store manager, {@link #addClass}is called
     * to add it. Classes which have inheritance strategy of "new-table" and
     * "superclass-table" will return a table here, whereas "subclass-table" will
     * return null since it doesn't have a table as such.
     * <p>
     * @param className Name of the class whose table is be returned.
     * @param clr The ClassLoaderResolver
     * @return The corresponding class table.
     * @exception NoTableManagedException If the given class has no table managed in the database.
     */
    public DatastoreClass getDatastoreClass(String className, ClassLoaderResolver clr)
    {
        DatastoreClass ct = null;
        if (className == null)
        {
            NucleusLogger.PERSISTENCE.error(LOCALISER.msg("032015"));
            return null;
        }

        StoreData sd = storeDataMgr.get(className);
        if (sd != null && sd instanceof MappedStoreData)
        {
            ct = (DatastoreClass) ((MappedStoreData)sd).getDatastoreContainerObject();
            if (ct != null)
            {
                // Class known about
                return ct;
            }
        }

        // Class not known so consider adding it to our list of supported classes.
        // Currently we only consider PC classes
        boolean toBeAdded = false;
        if (clr != null)
        {
            Class cls = clr.classForName(className);
            ApiAdapter api = getApiAdapter();
            if (cls != null && !cls.isInterface() && api.isPersistable(cls))
            {
                toBeAdded = true;
            }
        }
        else
        {
            toBeAdded = true;
        }

        boolean classKnown = false;
        if (toBeAdded)
        {
            // Add the class to our supported list
            addClass(className, clr);

            // Retry
            synchronized (storeDataMgr)
            {
                sd = storeDataMgr.get(className);
                if (sd != null && sd instanceof MappedStoreData)
                {
                    classKnown = true;
                    ct = (DatastoreClass) ((MappedStoreData)sd).getDatastoreContainerObject();
                }
            }
        }

        // Throw an exception if class still not known and no table
        // Note : "subclass-table" inheritance strategies will return null from this method
        if (!classKnown && ct == null)
        {
            throw new NoTableManagedException(className);
        }

        return ct;
    }

    /**
     * Returns the datastore table having the given SQL identifier.
     * Returns 'null' if no such table is (yet) known to the store manager.
     * @param name The identifier name of the table.
     * @return The corresponding JDO table, or 'null'
     */
    public synchronized DatastoreClass getDatastoreClass(DatastoreIdentifier name)
    {
        Iterator iterator = storeDataMgr.getManagedStoreData().iterator();
        while (iterator.hasNext())
        {
            StoreData sd = (StoreData) iterator.next();
            if (sd instanceof MappedStoreData)
            {
                MappedStoreData tsd = (MappedStoreData)sd;
                if (tsd.hasTable() && tsd.getDatastoreIdentifier().equals(name))
                {
                    return (DatastoreClass) tsd.getDatastoreContainerObject();
                }
            }
        }
        return null;
    }

    /**
     * Utility to navigate the inheritance hierarchy to find the base class that defines the primary keys
     * for this tree. This will either go up to the next class in the hierarchy that has a table
     * OR go up to the base class, whichever is first.
     * @param cmd AbstractClassMetaData for this class
     * @param clr The ClassLoaderResolver
     * @return The AbstractClassMetaData for the class defining the primary keys
     */
    public AbstractClassMetaData getClassWithPrimaryKeyForClass(AbstractClassMetaData cmd, ClassLoaderResolver clr)
    {
        if (cmd == null)
        {
            return null;
        }

        // Base class will have primary key fields
        if (cmd.getSuperAbstractClassMetaData() == null)
        {
            return cmd;
        }
        // Class has its own table so has the PK fields already
        else if (getDatastoreClass(cmd.getFullClassName(), clr) != null)
        {
            return cmd;
        }

        return getClassWithPrimaryKeyForClass(cmd.getSuperAbstractClassMetaData(), clr);
    }

    /**
     * Method to return the class(es) that has a table managing the persistence of
     * the fields of the supplied class. For the 3 inheritance strategies, the following
     * occurs :-
     * <UL>
     * <LI>new-table : will return the same ClassMetaData</LI>
     * <LI>subclass-table : will return all subclasses that have a table managing its fields</LI>
     * <LI>superclass-table : will return the next superclass that has a table</LI>
     * </UL>
     * @param cmd The supplied class.
     * @param clr ClassLoader resolver
     * @return The ClassMetaData's managing the fields of the supplied class
     */
    public AbstractClassMetaData[] getClassesManagingTableForClass(AbstractClassMetaData cmd, ClassLoaderResolver clr)
    {
        // Null input, so just return null;
        if (cmd == null)
        {
            return null;
        }

        if (cmd.getInheritanceMetaData().getStrategy() == InheritanceStrategy.COMPLETE_TABLE ||
            cmd.getInheritanceMetaData().getStrategy() == InheritanceStrategy.NEW_TABLE)
        {
            // Class manages a table so return the classes metadata.
            return new AbstractClassMetaData[] {cmd};
        }
        else if (cmd.getInheritanceMetaData().getStrategy() == InheritanceStrategy.SUBCLASS_TABLE)
        {
            // Check the subclasses that we have metadata for and make sure they are managed before proceeding
            String[] subclasses = getMetaDataManager().getSubclassesForClass(cmd.getFullClassName(), true);
            if (subclasses != null)
            {
                for (int i=0;i<subclasses.length;i++)
                {
                    if (!storeDataMgr.managesClass(subclasses[i]))
                    {
                        addClass(subclasses[i], clr);
                    }
                }
            }

            // Find subclasses who manage the tables winto which our class is persisted
            HashSet managingClasses=new HashSet();
            Iterator managedClassesIter = storeDataMgr.getManagedStoreData().iterator();
            while (managedClassesIter.hasNext())
            {
                StoreData data = (StoreData)managedClassesIter.next();
                if (data.isFCO() && ((AbstractClassMetaData)data.getMetaData()).getSuperAbstractClassMetaData() != null &&
                    ((AbstractClassMetaData)data.getMetaData()).getSuperAbstractClassMetaData().getFullClassName().equals(cmd.getFullClassName()))
                {
                    AbstractClassMetaData[] superCmds = getClassesManagingTableForClass((AbstractClassMetaData)data.getMetaData(), clr);
                    if (superCmds != null)
                    {
                        for (int i=0;i<superCmds.length;i++)
                        {
                            managingClasses.add(superCmds[i]);
                        }
                    }
                }
            }

            Iterator managingClassesIter = managingClasses.iterator();
            AbstractClassMetaData managingCmds[] = new AbstractClassMetaData[managingClasses.size()];
            int i=0;
            while (managingClassesIter.hasNext())
            {
                managingCmds[i++] = (AbstractClassMetaData)(managingClassesIter.next());
            }
            return managingCmds;
        }
        else if (cmd.getInheritanceMetaData().getStrategy() == InheritanceStrategy.SUPERCLASS_TABLE)
        {
            // Fields managed by superclass, so recurse to that
            return getClassesManagingTableForClass(cmd.getSuperAbstractClassMetaData(), clr);
        }
        return null;
    }

    /**
     * Accessor for whether the specified field of the object is inserted in the datastore yet.
     * @param sm StateManager for the object
     * @param fieldNumber (Absolute) field number for the object
     * @return Whether it is persistent
     */
    public boolean isObjectInserted(StateManager sm, int fieldNumber)
    {
        if (sm == null)
        {
            return false;
        }
        if (!sm.isInserting())
        {
            // StateManager isn't inserting so must be persistent
            return true;
        }

        DatastoreClass latestTable = insertedDatastoreClassByStateManager.get(sm);
        if (latestTable == null)
        {
            // Not yet inserted anything
            return false;
        }

        AbstractMemberMetaData fmd = sm.getClassMetaData().getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber);
        if (fmd == null)
        {
            // Specified field doesn't exist for this object type!
            return false;
        }

        String className = fmd.getClassName();
        if (fmd.isPrimaryKey())
        {
            // PK field so need to check if the latestTable manages the actual class here
            className = sm.getObject().getClass().getName();
        }

        DatastoreClass datastoreCls = latestTable;
        while (datastoreCls != null)
        {
            if (datastoreCls.managesClass(className))
            {
                return true; // This datastore class manages the specified class so it is inserted
            }
            datastoreCls = datastoreCls.getSuperDatastoreClass();
        }
        return false;
    }

    /**
     * Returns whether this object is inserted in the datastore far enough to be considered to be the
     * supplied type. For example if we have base class A, B extends A and this object is a B, and we
     * pass in A here then this returns whether the A part of the object is now inserted.
     * @param sm StateManager for the object
     * @param className Name of class that we want to check the insertion level for.
     * @return Whether the object is inserted in the datastore to this level
     */
    public boolean isObjectInserted(StateManager sm, String className)
    {
        if (sm == null)
        {
            return false;
        }
        if (!sm.isInserting())
        {
            return false;
        }

        DatastoreClass latestTable = insertedDatastoreClassByStateManager.get(sm);
        if (latestTable != null)
        {
            DatastoreClass datastoreCls = latestTable;
            while (datastoreCls != null)
            {
                if (datastoreCls.managesClass(className))
                {
                    return true; // This datastore class manages the specified class so it is inserted
                }
                datastoreCls = datastoreCls.getSuperDatastoreClass();
            }
        }

        return false;
    }

    /**
     * Method to set that the specified object is inserted down to the defined datastore class.
     * When the object is fully inserted (the table is the primary table for this object type)
     * it is removed from the map of objects being inserted.
     * @param sm StateManager for the object
     * @param table Table to which it is now inserted
     */
    public void setObjectIsInsertedToLevel(StateManager sm, DatastoreClass table)
    {
        insertedDatastoreClassByStateManager.put(sm, table);

        if (table.managesClass(sm.getClassMetaData().getFullClassName()))
        {
            // Full insertion has just completed so update activity state in StateManager
            sm.changeActivityState(ActivityState.INSERTING_CALLBACKS);
            insertedDatastoreClassByStateManager.remove(sm);
        }
    }

    /**
     * Accessor for the backing store for the specified field.
     * @param clr The ClassLoaderResolver
     * @param fmd the field to be persisted by this Store
     * @param type instantiated type or prefered type
     * @return The backing store
     */
    public Store getBackingStoreForField(ClassLoaderResolver clr, AbstractMemberMetaData fmd, Class type)
    {
        if (fmd != null && fmd.isSerialized())
        {
            return null;
        }

        if (fmd.getMap() != null)
        {
            assertCompatibleFieldType(fmd, clr, type, MapMapping.class);
            return getBackingStoreForMap(fmd, clr);
        }
        if (fmd.getArray() != null)
        {
            assertCompatibleFieldType(fmd, clr, type, ArrayMapping.class);
            return getBackingStoreForArray(fmd, clr);
        }
        assertCompatibleFieldType(fmd, clr, type, CollectionMapping.class);

        return getBackingStoreForCollection(fmd, clr, type);
    }

    /**
     * Asserts the current mapping for the field is the one expected.
     * @param fmd MetaData for the field.
     * @param clr ClassLoader resolver
     * @param type Type of object
     * @param expectedMappingType Mapping type expected
     */
    private void assertCompatibleFieldType(AbstractMemberMetaData fmd, ClassLoaderResolver clr, Class type,
            Class expectedMappingType)
    {
        DatastoreClass ownerTable = getDatastoreClass(fmd.getClassName(), clr);
        if (ownerTable == null)
        {
            // Class doesn't manage its own table (uses subclass-table, or superclass-table?)
            AbstractClassMetaData fieldTypeCmd = getMetaDataManager().getMetaDataForClass(fmd.getClassName(), clr);
            AbstractClassMetaData[] tableOwnerCmds = getClassesManagingTableForClass(fieldTypeCmd, clr);
            if (tableOwnerCmds != null && tableOwnerCmds.length == 1)
            {
                ownerTable = getDatastoreClass(tableOwnerCmds[0].getFullClassName(), clr);
            }
        }

        if (ownerTable != null)
        {
            JavaTypeMapping m = ownerTable.getMemberMapping(fmd);
            if (!expectedMappingType.isAssignableFrom(m.getClass()))
            {
                throw new IncompatibleFieldTypeException(fmd.getFullFieldName(),
                    type.getName(), fmd.getTypeName());
            }
        }
    }

    /**
     * Method to return a backing store for a Collection, consistent with this store and the instantiated type.
     * @param mmd MetaData for the field that has this collection
     * @param clr ClassLoader resolver
     * @return The backing store of this collection in this store
     */
    private CollectionStore getBackingStoreForCollection(AbstractMemberMetaData mmd,
            ClassLoaderResolver clr, Class type)
    {
        CollectionStore store = null;
        DatastoreContainerObject datastoreTable = getDatastoreContainerObject(mmd);
        if (type == null)
        {
            // No type to base it on so create it based on the field declared type
            if (datastoreTable == null)
            {
                // We need a "FK" relation.
                if (List.class.isAssignableFrom(mmd.getType()))
                {
                    store = newFKListStore(mmd, clr);
                }
                else
                {
                    store = newFKSetStore(mmd, clr);
                }
            }
            else
            {
                // We need a "JoinTable" relation.
                if (List.class.isAssignableFrom(mmd.getType()))
                {
                    store = newJoinListStore(mmd, clr, datastoreTable);
                }
                else
                {
                    store = newJoinSetStore(mmd, clr, datastoreTable);
                }
            }
        }
        else
        {
            // Instantiated type specified so use it to pick the associated backing store
            if (datastoreTable == null)
            {
                if (SCOUtils.isListBased(type))
                {
                    // List required
                    store = newFKListStore(mmd, clr);
                }
                else
                {
                    // Set required
                    store = newFKSetStore(mmd, clr);
                }
            }
            else
            {
                if (SCOUtils.isListBased(type))
                {
                    // List required
                    store = newJoinListStore(mmd, clr, datastoreTable);
                }
                else
                {
                    // Set required
                    store = newJoinSetStore(mmd, clr, datastoreTable);
                }
            }
        }
        return store;
    }

    /**
     * Method to return a backing store for a Map, consistent with this store and the instantiated type.
     * @param mmd MetaData for the field that has this map
     * @param clr ClassLoader resolver
     * @return The backing store of this map in this store
     */
    private MapStore getBackingStoreForMap(AbstractMemberMetaData mmd, ClassLoaderResolver clr)
    {
        MapStore store = null;
        DatastoreContainerObject datastoreTable = getDatastoreContainerObject(mmd);
        if (datastoreTable == null)
        {
            store = newFKMapStore(mmd, clr);
        }
        else
        {
            store = newJoinMapStore(mmd, clr, datastoreTable);
        }
        return store;
    }

    /**
     * Method to return a backing store for an array, consistent with this store and the instantiated type.
     * @param mmd MetaData for the field/property that has this array
     * @param clr ClassLoader resolver
     * @return The backing store of this array in this store
     */
    private ArrayStore getBackingStoreForArray(AbstractMemberMetaData mmd, ClassLoaderResolver clr)
    {
        ArrayStore store;
        DatastoreContainerObject datastoreTable = getDatastoreContainerObject(mmd);
        if (datastoreTable != null)
        {
            store = newJoinArrayStore(mmd, clr, datastoreTable);
        }
        else
        {
            store = newFKArrayStore(mmd, clr);
        }
        return store;
    }

    /**
     * Method to return a FieldManager for extracting information from the supplied results.
     * @param sm StateManager for the object
     * @param resultSet The results
     * @param resultMappings Mappings of the results for this class
     * @return FieldManager to use
     */
    public abstract FieldManager getFieldManagerForResultProcessing(StateManager sm, Object resultSet,
            StatementClassMapping resultMappings);

    /**
     * Method to return a FieldManager for populating information in statements.
     * @param sm The state manager for the object.
     * @param stmt The input Statement to set values on.
     * @param stmtMappings Mappings of the input parameters
     * @param checkNonNullable Whether to check for nullability
     * @return The FieldManager to use
     */
    public abstract FieldManager getFieldManagerForStatementGeneration(StateManager sm, Object stmt,
            StatementClassMapping stmtMappings, boolean checkNonNullable);

    /**
     * Method to return the value from the results at the specified position.
     * @param resultSet The results
     * @param mapping The mapping
     * @param position The position
     * @return The value at that position
     */
    public abstract Object getResultValueAtPosition(Object resultSet, JavaTypeMapping mapping, int position);

    /**
     * Accessor for whether this mapping requires values inserting on an INSERT.
     * @param datastoreMapping The datastore mapping
     * @return Whether values are to be inserted into this mapping on an INSERT
     */
    public abstract boolean insertValuesOnInsert(DatastoreMapping datastoreMapping);

    /**
     * Convenience method to return if the datastore supports batching and the user wants batching.
     * @return If batching of statements is permissible
     */
    public abstract boolean allowsBatching();

    /**
     * Factory method for allocating a {@link ResultObjectFactory} of the appropriate concrete type.
     * @param table Table being selected from
     * @param acmd MetaData for the class
     * @param mappingDefinition Mapping of the class from the result set
     * @param ignoreCache Whether to ignore the cache
     * @param discriminator Whether we use a discriminator column to distinguish object types
     * @param fetchPlan the Fetch Plan
     * @param persistentClass Class that this factory will create instances of (or subclasses)
     */
    public abstract ResultObjectFactory newResultObjectFactory(
        DatastoreClass table, AbstractClassMetaData acmd, StatementClassMapping mappingDefinition,
        boolean ignoreCache, boolean discriminator, FetchPlan fetchPlan,
        Class persistentClass);

    /**
     * Method to create a new fetch statement for the passed table.
     * TODO Remove this when we factor out the TJDO-style expression package.
     * @param table The table to fetch from
     * @return The fetch statement
     */
    public abstract FetchStatement getFetchStatement(DatastoreContainerObject table);

    protected abstract FKArrayStore newFKArrayStore(AbstractMemberMetaData clr, ClassLoaderResolver amd);
    protected abstract FKListStore newFKListStore(AbstractMemberMetaData clr, ClassLoaderResolver amd);
    protected abstract FKSetStore newFKSetStore(AbstractMemberMetaData clr, ClassLoaderResolver mmd);
    protected abstract FKMapStore newFKMapStore(AbstractMemberMetaData clr, ClassLoaderResolver amd);
    protected abstract JoinArrayStore newJoinArrayStore(AbstractMemberMetaData amd, ClassLoaderResolver clr,
            DatastoreContainerObject arrayTable);
    protected abstract JoinMapStore newJoinMapStore(AbstractMemberMetaData amd, ClassLoaderResolver clr,
            DatastoreContainerObject mapTable);
    protected abstract JoinListStore newJoinListStore(AbstractMemberMetaData amd, ClassLoaderResolver clr,
            DatastoreContainerObject listTable);
    protected abstract JoinSetStore newJoinSetStore(AbstractMemberMetaData amd, ClassLoaderResolver clr,
            DatastoreContainerObject setTable);
}
TOP

Related Classes of org.datanucleus.store.mapped.MappedStoreManager

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.