Package org.datanucleus.store.mapped.scostore

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

/**********************************************************************
Copyright (c) 2002 Mike Martin (TJDO) 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:
2003 Erik Bengtson - removed unused import
2003 Andy Jefferson - coding standards
2003 Andy Jefferson - addition of getGetStatement for inherited values
2004 Andy Jefferson - addition of query methods
2004 Andy Jefferson - moved statements from subclasses
2005 Andy Jefferson - allow for embedded keys/values
    ...
**********************************************************************/
package org.datanucleus.store.mapped.scostore;

import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;

import org.datanucleus.ClassLoaderResolver;
import org.datanucleus.ObjectManager;
import org.datanucleus.StateManager;
import org.datanucleus.metadata.AbstractClassMetaData;
import org.datanucleus.sco.SCOUtils;
import org.datanucleus.store.StoreManager;
import org.datanucleus.store.mapped.DatastoreClass;
import org.datanucleus.store.mapped.DatastoreContainerObject;
import org.datanucleus.store.mapped.DatastoreIdentifier;
import org.datanucleus.store.mapped.expression.LogicSetExpression;
import org.datanucleus.store.mapped.expression.MapStoreQueryable;
import org.datanucleus.store.mapped.expression.QueryExpression;
import org.datanucleus.store.mapped.expression.ScalarExpression;
import org.datanucleus.store.mapped.expression.StringLiteral;
import org.datanucleus.store.mapped.mapping.EmbeddedKeyPCMapping;
import org.datanucleus.store.mapped.mapping.EmbeddedValuePCMapping;
import org.datanucleus.store.mapped.mapping.JavaTypeMapping;
import org.datanucleus.store.scostore.MapStore;

/**
* Abstract representation of the backing store for a Map.
*/
public abstract class AbstractMapStore extends BaseContainerStore implements MapStore, MapStoreQueryable
{
    /** Flag to set whether the iterator statement will use a discriminator or not. */
    protected boolean iterateUsingDiscriminator = false;

    /** Table storing the map relation. May be join table, or key table, or value table. */
    protected DatastoreContainerObject mapTable;

    /** Table storing the values. */
    protected DatastoreClass valueTable;

    /** Metadata for the keys (if persistable). */
    protected AbstractClassMetaData kmd;

    /** Metadata for the values (if persistable). */
    protected AbstractClassMetaData vmd;

    /** Mapping to the key from the mapTable. */
    protected JavaTypeMapping keyMapping;

    /** Mapping to the value from the mapTable. */
    protected JavaTypeMapping valueMapping;

    /** Type of the key. */
    protected String keyType;

    /** Type of the value. */
    protected String valueType;

    /** Whether the keys are embedded. */
    protected boolean keysAreEmbedded;

    /** Whether the keys are serialised. */
    protected boolean keysAreSerialised;

    /** Whether the values are embedded. */
    protected boolean valuesAreEmbedded;

    /** Whether the values are serialised. */
    protected boolean valuesAreSerialised;

    protected final AbstractMapStoreSpecialization specialization;

    /**
     * Constructor.
     * @param storeMgr Manager for the store
     * @param specialization Specialisation for this datastore
     */
    public AbstractMapStore(StoreManager storeMgr, AbstractMapStoreSpecialization specialization)
    {
        super(storeMgr);

        this.specialization = specialization;
    }

    /**
     * Accessor for whether the keys are embedded or not.
     * If they are PC instances then returns false;
     * @return Whether the keys are embedded
     */
    public boolean keysAreEmbedded()
    {
        return keysAreEmbedded;
    }

    /**
     * Accessor for whether the keys are serialised or not.
     * If they are PC instances then returns false;
     * @return Whether the keys are serialised
     */
    public boolean keysAreSerialised()
    {
        return keysAreSerialised;
    }

    /**
     * Accessor for whether the values are embedded or not.
     * If they are PC instances then returns false;
     * @return Whether the values are embedded
     */
    public boolean valuesAreEmbedded()
    {
        return valuesAreEmbedded;
    }

    /**
     * Accessor for whether the values are serialised or not.
     * If they are PC instances then returns false;
     * @return Whether the values are serialised
     */
    public boolean valuesAreSerialised()
    {
        return valuesAreSerialised;
    }

    /**
     * Accessor for the key type for storing in this Map.
     * @return The type of the key
     */
    public String getKeyType()
    {
        return keyType;
    }

    /**
     * Accessor for the value type for storing in this Map.
     * Types inherited from this (base) type can also be stored as values.
     * @return The type of the value (base class).
     */
    public String getValueType()
    {
        return valueType;
    }

    // ------------------------- Public Methods --------------------------------
    /**
     * Method to check if a key exists in the Map.
     * @param sm State Manager for the map
     * @param key The key to check for.
     * @return Whether the key exists in the Map.
     */
    public boolean containsKey(StateManager sm, Object key)
    {
        if( key == null )
        {
            //nulls not allowed
            return false;
        }
        try
        {
            getValue(sm, key);
            return true;
        }
        catch (NoSuchElementException e)
        {
            return false;
        }
    }

    /**
     * Method to check if a value exists in the Map.
     * @param sm State Manager for the map
     * @param value The value to check for.
     * @return Whether the value exists in the Map.
     */
    public boolean containsValue(StateManager sm, Object value)
    {
        if( value == null )
        {
            //nulls not allowed
            return false;
        }
        if (!validateValueForReading(sm, value))
        {
            return false;
        }
        return specialization.containsValue(sm, value, this);
    }

    /**
     * Method to return the value for a key.
     * @param sm State Manager for the Map.
     * @param key The key of the object to retrieve.
     * @return The value for this key.
     */
    public Object get(StateManager sm, Object key)
    {
        try
        {
            return getValue(sm, key);
        }
        catch (NoSuchElementException e)
        {
            return null;
        }
    }

    /**
     * Method to put all elements from a Map into our Map.
     * @param sm State Manager for the Map
     * @param m The Map to add
     */
    public void putAll(StateManager sm, Map m)
    {
        Iterator i = m.entrySet().iterator();

        while (i.hasNext())
        {
            Map.Entry e = (Map.Entry)i.next();
            put(sm, e.getKey(), e.getValue());
        }
    }

    // --------------------------- Utility Methods -----------------------------
    /**
     * Utility to validate the type of a key for storing in the Map.
     * @param clr The ClassLoaderResolver
     * @param key The key to check.
     */
    protected void validateKeyType(ClassLoaderResolver clr, Object key)
    {
        if (key == null)
        {
            throw new NullPointerException(LOCALISER.msg("056062"));
        }

        if (!clr.isAssignableFrom(keyType, key.getClass()))
        {
            throw new ClassCastException(LOCALISER.msg("056064",key.getClass().getName(),keyType));
        }
    }

    /**
     * Utility to validate the type of a value for storing in the Map.
     * @param clr The ClassLoaderResolver
     * @param value The value to check.
     */
    protected void validateValueType(ClassLoaderResolver clr, Object value)
    {
        if (value != null && !clr.isAssignableFrom(valueType, value.getClass()))
        {
            throw new ClassCastException(LOCALISER.msg("056065",value.getClass().getName(),valueType));
        }
    }

    /**
     * Utility to validate a key is ok for reading.
     * @param sm State Manager for the map.
     * @param key The key to check.
     * @return Whether it is validated.
     */
    protected boolean validateKeyForReading(StateManager sm, Object key)
    {
        validateKeyType(sm.getObjectManager().getClassLoaderResolver(), key);

        if (!keysAreEmbedded && !keysAreSerialised)
        {
            ObjectManager om = sm.getObjectManager();
            if (key!=null && (!om.getApiAdapter().isPersistent(key) ||
                om != om.getApiAdapter().getObjectManager(key)) && !om.getApiAdapter().isDetached(key))
            {
                return false;
            }
        }

        return true;
    }

    /**
     * Utility to validate a value is ok for reading.
     * @param sm State Manager for the map.
     * @param value The value to check.
     * @return Whether it is validated.
     */
    protected boolean validateValueForReading(StateManager sm, Object value)
    {
        validateValueType(sm.getObjectManager().getClassLoaderResolver(), value);

        if (!valuesAreEmbedded && !valuesAreSerialised)
        {
            ObjectManager om = sm.getObjectManager();
            if (value != null && (!om.getApiAdapter().isPersistent(value) ||
                om != om.getApiAdapter().getObjectManager(value)) && !om.getApiAdapter().isDetached(value))
            {
                return false;
            }
        }

        return true;
    }

    /**
     * Utility to validate a key is ok for writing (present in the datastore).
     * @param sm State Manager for the map.
     * @param key The key to check.
     */
    protected void validateKeyForWriting(StateManager sm, Object key)
    {
        validateKeyType(sm.getObjectManager().getClassLoaderResolver(), key);

        if (!keysAreEmbedded && !keysAreSerialised)
        {
            ObjectManager om = sm.getObjectManager();
            SCOUtils.validateObjectForWriting(om, key, null);
        }
    }

    /**
     * Utility to validate a value is ok for writing (present in the datastore).
     * @param sm State Manager for the map.
     * @param value The value to check.
     */
    protected void validateValueForWriting(StateManager sm, Object value)
    {
        validateValueType(sm.getObjectManager().getClassLoaderResolver(), value);
        if (!valuesAreEmbedded && !valuesAreSerialised)
        {
            ObjectManager om = sm.getObjectManager();
            SCOUtils.validateObjectForWriting(om, value, null);
        }
    }

    /**
     * Method to retrieve a value from the Map given the key.
     * @param sm State Manager for the map.
     * @param key The key to retrieve the value for.
     * @return The value for this key
     * @throws NoSuchElementException if the value for the key was not found
     */
    protected abstract Object getValue(StateManager sm, Object key)
    throws NoSuchElementException;

    /**
     * Method to update a field of an embedded key.
     * @param sm State Manager of the owner
     * @param key The key to update
     * @param fieldNumber The number of the field to update
     * @param newValue The new value
     */
    public boolean updateEmbeddedKey(StateManager sm, Object key, int fieldNumber, Object newValue)
    {
        boolean modified = false;
        if (keyMapping != null && keyMapping instanceof EmbeddedKeyPCMapping)
        {
            String fieldName = vmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber).getName();
            if (fieldName == null)
            {
                // We have no mapping for this field so presumably is the owner field or a PK field
                return false;
            }
            JavaTypeMapping fieldMapping = ((EmbeddedKeyPCMapping)keyMapping).getJavaTypeMapping(fieldName);
            if (fieldMapping == null)
            {
                // We have no mapping for this field so presumably is the owner field or a PK field
                return false;
            }
            modified = specialization.updatedEmbeddedKey(sm, key, fieldNumber, newValue, fieldMapping, this);
        }

        return modified;
    }

    /**
     * Method to update a field of an embedded key.
     * @param sm State Manager of the owner
     * @param value The value to update
     * @param fieldNumber The number of the field to update
     * @param newValue The new value
     */
    public boolean updateEmbeddedValue(StateManager sm, Object value, int fieldNumber, Object newValue)
    {
        boolean modified = false;
        if (valueMapping != null && valueMapping instanceof EmbeddedValuePCMapping)
        {
            String fieldName = vmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber).getName();
            if (fieldName == null)
            {
                // We have no mapping for this field so presumably is the owner field or a PK field
                return false;
            }
            JavaTypeMapping fieldMapping = ((EmbeddedValuePCMapping)valueMapping).getJavaTypeMapping(fieldName);
            if (fieldMapping == null)
            {
                // We have no mapping for this field so presumably is the owner field or a PK field
                return false;
            }
            modified = specialization.updateEmbeddedValue(sm, value, fieldNumber, newValue, fieldMapping, this);
        }

        return modified;
    }

    public JavaTypeMapping getValueMapping()
    {
        return valueMapping;
    }

    public JavaTypeMapping getKeyMapping()
    {
        return keyMapping;
    }

    public boolean isValuesAreEmbedded()
    {
        return valuesAreEmbedded;
    }

    public boolean isValuesAreSerialised()
    {
        return valuesAreSerialised;
    }

    public DatastoreContainerObject getMapTable()
    {
        return mapTable;
    }

    public AbstractClassMetaData getKmd()
    {
        return kmd;
    }

    public AbstractClassMetaData getVmd()
    {
        return vmd;
    }

    // ---------------------------- JDOQL Query methods ---------------------------------

    /**
     * Method used where a Query uses map.isEmpty().
     * @param qs The QueryStatement
     * @param mapping The mapping of the java type
     * @param ownerTe The owner table expression
     * @param mapTableAlias The alias for the "Map" table.
     * @return A subquery
     */
    public QueryExpression getExistsSubquery(QueryExpression qs, JavaTypeMapping mapping,
            LogicSetExpression ownerTe, DatastoreIdentifier mapTableAlias)
    {
        QueryExpression stmt = dba.newQueryStatement(mapTable, mapTableAlias, qs.getClassLoaderResolver());
        stmt.setParent(qs);

        // Join to the owner
        ScalarExpression ownerExpr = mapping.newScalarExpression(stmt, ownerTe);
        ScalarExpression ownerInMapExpr = ownerMapping.newScalarExpression(stmt, stmt.getTableExpression(mapTableAlias));
        stmt.andCondition(ownerExpr.eq(ownerInMapExpr));

        stmt.select(mapTableAlias, valueMapping);

        return stmt;
    }

    /**
     * Query utility to generate a subquery for the size() of the map.
     * @param qs The query statement
     * @param mapping mapping of the field
     * @param ownerTe Expression for the table
     * @param mapTableAlias alias for the map table
     * @return The query statement
     */
    public QueryExpression getSizeSubquery(QueryExpression qs, JavaTypeMapping mapping,
            LogicSetExpression ownerTe, DatastoreIdentifier mapTableAlias)
    {
        QueryExpression stmt = dba.newQueryStatement(mapTable, mapTableAlias, qs.getClassLoaderResolver());
        stmt.setParent(qs);

        // Join for the owner
        ScalarExpression ownerExpr = mapping.newScalarExpression(stmt, ownerTe);
        ScalarExpression ownerInCollectionExpr = ownerMapping.newScalarExpression(stmt, stmt.getTableExpression(mapTableAlias));
        stmt.andCondition(ownerExpr.eq(ownerInCollectionExpr));

        // Select COUNT(*)
        JavaTypeMapping m = storeMgr.getMappingManager().getMapping(String.class);
        StringLiteral lit = (StringLiteral)m.newLiteral(stmt, "COUNT(*)");
        lit.generateStatementWithoutQuotes();
        stmt.selectScalarExpression(lit);

        return stmt;
    }

    /**
     * Used as part of the Querying of Maps where a get(Key) is used.
     * @param stmt The Query Statement to apply the join
     * @param parentStmt the parent Query Statement. If there is no parent,
     *     <code>parentStmt</code> must be equal to <code>stmt</code>
     * @param ownerMapping Mapping for the owner.
     * @param te Table Expression for the owner
     * @param mapTableAlias  The SQL alias to assign to the expression or to the main table.
     * @param filteredKeyType The Class Type for the filtered key
     * @param keyTableAlias  The SQL alias to assign to the expression or to the key table.
     * @param valueTableAlias The SQL alias to assign to the expression or to the value table.
     * @return an array with 2 elements of QueryColumnList. The first element
     * contains the columns from the key mapping and the second element the
     * columns from the value mapping
     */
    public ScalarExpression[] joinKeysToGet(QueryExpression stmt, QueryExpression parentStmt,
            JavaTypeMapping ownerMapping, LogicSetExpression te, DatastoreIdentifier mapTableAlias,
            Class filteredKeyType, DatastoreIdentifier keyTableAlias, DatastoreIdentifier valueTableAlias)
    {
        ClassLoaderResolver clr = stmt.getClassLoaderResolver();
        Class value_class = clr.classForName(valueType);

        return joinKeysValuesTo(stmt, parentStmt, ownerMapping, te, mapTableAlias, filteredKeyType,
            value_class, null, null, keyTableAlias, valueTableAlias);
    }
}
TOP

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

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.