Package org.jpox.store.rdbms.scostore

Source Code of org.jpox.store.rdbms.scostore.MapKeySetStore

/**********************************************************************
Copyright (c) 2002 Kelly Grizzle (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:
2002 Mike Martin (TJDO)
2003 Erik Bengtson - removed unused variable and import
2003 Andy Jefferson - coding standards
2004 Andy Jefferson - moved statements to AbstractSetStore
    ...
**********************************************************************/
package org.jpox.store.rdbms.scostore;

import java.util.Collection;

import org.jpox.ClassLoaderResolver;
import org.jpox.StateManager;
import org.jpox.exceptions.JPOXUserException;
import org.jpox.metadata.AbstractMemberMetaData;
import org.jpox.metadata.DiscriminatorStrategy;
import org.jpox.store.mapped.DatastoreClass;
import org.jpox.store.mapped.DatastoreContainerObject;
import org.jpox.store.mapped.DatastoreIdentifier;
import org.jpox.store.mapped.IdentifierFactory;
import org.jpox.store.mapped.expression.LogicSetExpression;
import org.jpox.store.mapped.expression.QueryExpression;
import org.jpox.store.mapped.expression.ScalarExpression;
import org.jpox.store.mapped.mapping.JavaTypeMapping;
import org.jpox.store.rdbms.query.DiscriminatorIteratorStatement;
import org.jpox.store.rdbms.query.UnionIteratorStatement;
import org.jpox.store.rdbms.table.MapTable;
import org.jpox.store.rdbms.table.SCOTable;

/**
* Representation of the backing store for a MapKey Set.
* This is used where the user calls Map.keySet() and then wants to perform
* some operation on the resulting Collection.
* The keys for a Map can be stored in several ways. There are four
* possibilities
* <UL>
* <LI><B>Primitive key, Normal Map</B> - The container has its FCO table,
* and there is a join table (SCO) that will contain the key object.</LI>
* <LI><B>Primitive key, Inverse Map</B> - The container has its FCO table,
* and the key is stored in the FCO table of the element</LI>
* <LI><B>Non-primitive key, Normal Map</B> - The container has its FCO table,
* and the key has its own FCO table. There is an SCO join table, and this join
* table has a FK (..._ID_KID) to the id of the key FCO table.</LI>
* <LI><B>Non-primitive key, Inverse Map</B> - The container has its FCO table,
* and the key has its own FCO table. The value is stored in a table, and this
* table has a FK (KEY_...._ID_OID) to the key FCO table.</LI>
* </UL>
* TODO Cater for embedded keys
*
* @version $Revision: 1.55 $
**/
public class MapKeySetStore extends AbstractSetStore
{
    private DatastoreIdentifier valueIdentifier;

    /** Indicator for a map that is managed by a join table. */
    protected static final int MAP_TYPE_JOIN = 0;

    /** Indicator for a map that is managed by storing the key as a field in the value. */
    protected static final int MAP_TYPE_KEY_IN_VALUE = 1;

    /** Indicator for a map that is managed by storing the value as a field in the key. */
    protected static final int MAP_TYPE_VALUE_IN_KEY = 2;

    /** Type of map being managed by this key store. */
    private final int mapType;

    /**
     * Constructor where a join table is used to store the map relation.
     * @param mapTable The table for the map (join table)
     * @param clr The ClassLoaderResolver
     */
    public MapKeySetStore(MapTable mapTable, ClassLoaderResolver clr)
    {
        super(mapTable.getStoreManager(), clr);

        containerTable = mapTable;
        setName = "keys";
        ownerMemberMetaData = mapTable.getOwnerFieldMetaData();
        mapType = MAP_TYPE_JOIN;

        ownerMapping   = mapTable.getOwnerMapping();
        elementMapping = mapTable.getKeyMapping();

        initialize(clr);
       
        valueIdentifier = storeMgr.getIdentifierFactory().newIdentifier(IdentifierFactory.TABLE, "VALUE");
    }

    /**
     * Constructor where either the key is stored in the value table or the value is stored in the key table.
     * @param valueTable The table for the "value" of the map
     * @param ownerMapping The mapping for this table to the owner table
     * @param keyMapping The mapping for this table to the key table/column
     * @param clr The ClassLoaderResolver
     * @param fmd FieldMetaData for the owning "map" field
     */
    public MapKeySetStore(DatastoreContainerObject valueTable, JavaTypeMapping ownerMapping, JavaTypeMapping keyMapping,
            ClassLoaderResolver clr, AbstractMemberMetaData fmd)
    {
        super(valueTable.getStoreManager(), clr);

        containerTable = valueTable;
        setName = "keys";
        this.ownerMemberMetaData = fmd;
        if (ownerMemberMetaData.getValueMetaData() != null && ownerMemberMetaData.getValueMetaData().getMappedBy() != null)
        {
            mapType = MAP_TYPE_VALUE_IN_KEY;
        }
        else
        {
            mapType = MAP_TYPE_KEY_IN_VALUE;
        }

        this.ownerMapping = ownerMapping;
        this.elementMapping = keyMapping;

        initialize(clr);

        removeStmt = null;
        clearStmt  = null;
    }

    /**
     * Initialisation method.
     */
    private void initialize(ClassLoaderResolver clr)
    {
        elementType = elementMapping.getType();
        elementsAreEmbedded = isEmbeddedMapping(elementMapping);
        elementsAreSerialised = isEmbeddedMapping(elementMapping);

        // Load the element class
        Class element_class = clr.classForName(elementType);

        if (storeMgr.getOMFContext().getTypeManager().isReferenceType(element_class))
        {
            emd = storeMgr.getOMFContext().getMetaDataManager().getMetaDataForImplementationOfReference(element_class, null, clr);
        }
        else
        {
            emd = storeMgr.getOMFContext().getMetaDataManager().getMetaDataForClass(element_class, clr);
        }
        if (emd != null)
        {
            elementType = emd.getFullClassName();
            elementInfo = getElementInformationForClass();
        }

        valueIdentifier = storeMgr.getIdentifierFactory().newIdentifier(IdentifierFactory.TABLE, "VALUE")
    }

    /**
     * Method to create an iterator for the map keys.
     * @param ownerSM StateManager for the map
     * @return the QueryStatement
     */
    protected QueryExpression getIteratorStatement(StateManager ownerSM)
    {
        final ClassLoaderResolver clr = ownerSM.getObjectManager().getClassLoaderResolver();
        final Class elementCls = clr.classForName(elementType);
        QueryExpression stmt = null;
        if (emd != null &&
            emd.getDiscriminatorStrategy() != null &&
            emd.getDiscriminatorStrategy() != DiscriminatorStrategy.NONE &&
            containerTable instanceof DatastoreClass)
        {
            // Inverse Map where Key is PC and uses discriminator
            if (storeMgr.getOMFContext().getTypeManager().isReferenceType(clr.classForName(elementType)))
            {
                // Take the metadata for the first implementation of the reference type
                String[] clsNames = storeMgr.getOMFContext().getMetaDataManager().getClassesImplementingInterface(elementType, clr);
                Class[] cls = new Class[clsNames.length];
                for (int j=0; j<clsNames.length; j++)
                {
                    cls[j] = clr.classForName(clsNames[j]);
                }
                stmt = new DiscriminatorIteratorStatement(clr,
                    cls, true, this.storeMgr, true).getQueryStatement(null);
            }
            else
            {
                stmt = new DiscriminatorIteratorStatement(clr, new Class[] {elementCls},
                    true, this.storeMgr, true).getQueryStatement(null);
            }
            iterateUsingDiscriminator = true;

            // Add inner join to the container table
            DatastoreClass sourceTable = storeMgr.getDatastoreClass(elementType, clr);
            ScalarExpression sourceExpr = sourceTable.getIDMapping().newScalarExpression(stmt, stmt.getMainTableExpression());
            LogicSetExpression teTargetElement = stmt.newTableExpression(containerTable, valueIdentifier);
            ScalarExpression targetExpr = elementMapping.newScalarExpression(stmt, teTargetElement);
            stmt.innerJoin(sourceExpr, targetExpr, teTargetElement, true);
        }
        else
        {
            // Join to key table if this is join table, or value table
            boolean sourceJoin = (mapType == MAP_TYPE_JOIN || mapType == MAP_TYPE_KEY_IN_VALUE);
            stmt = new UnionIteratorStatement(clr, elementCls, true, this.storeMgr,
                elementCls, elementMapping, containerTable, sourceJoin, null,
                true, false).getQueryStatement(null);
        }

        // Apply condition on owner field to filter by owner
        if (containerTable instanceof SCOTable || storeMgr.getOMFContext().getTypeManager().isSupportedType(elementType) ||
            mapType == MAP_TYPE_VALUE_IN_KEY)
        {
            // SCO cases/primitiveKeys just provide the owner id on their table
            ScalarExpression ownerExpr = ownerMapping.newScalarExpression(stmt, stmt.getMainTableExpression());
            ScalarExpression ownerVal = ownerMapping.newLiteral(stmt, ownerSM.getObject());
            stmt.andCondition(ownerExpr.eq(ownerVal), true);
        }
        else
        {
            // FCO cases/non-primitiveKeys provide the owner id on the value table
            ScalarExpression ownerExpr = ownerMapping.newScalarExpression(stmt, stmt.getTableExpression(valueIdentifier));
            ScalarExpression ownerVal = ownerMapping.newLiteral(stmt, ownerSM.getObject());
            stmt.andCondition(ownerExpr.eq(ownerVal), true);
        }

        return stmt;
    }

    /**
     * Method to add an element. Overridden because we want to prevent it.
     * @param sm State Manager of collection.
     * @param element Element to add.
     * @return Whether it was successful
     **/
    public boolean add(StateManager sm, Object element, int size)
    {
        throw new UnsupportedOperationException("Cannot add to a map through its key set");
    }

    /**
     * Method to add a collection of elements. Overridden because we want to prevent it.
     * @param sm State Manager of collection.
     * @param elements Elements to add.
     * @return Whether it was successful
     **/
    public boolean addAll(StateManager sm, Collection elements, int size)
    {
        throw new UnsupportedOperationException("Cannot add to a map through its key set");
    }

    /**
     * Method to remove an element. Overridden because we want to prevent it.
     * @param sm State Manager of collection.
     * @param element Element to remove.
     * @return Whether it was successful
     **/
    public boolean remove(StateManager sm, Object element, int size, boolean allowDependentField)
    {
        if (removeStmt == null)
        {
            throw new UnsupportedOperationException("Cannot remove from an inverse map through its key set");
        }

        return super.remove(sm, element, size, allowDependentField);
    }

    /**
     * Method to remove a collection of elements. Overridden because we want to prevent it.
     * @param sm State Manager of collection.
     * @param elements Elements to remove.
     * @return Whether it was successful
     **/
    public boolean removeAll(StateManager sm, Collection elements, int size)
    {
        if (removeStmt == null)
        {
            throw new UnsupportedOperationException("Cannot remove from an inverse map through its key set");
        }

        return super.removeAll(sm, elements, size);
    }

    /**
     * Method to clear the collection. Overridden because we want to prevent it.
     * @param sm State Manager of collection.
     **/
    public void clear(StateManager sm)
    {
        if (clearStmt == null)
        {
            throw new UnsupportedOperationException("Cannot clear an inverse map through its key set");
        }

        super.clear(sm);
    }

    // ------------------------------- JDOQL Query Methods ---------------------------

    public ScalarExpression joinElementsTo(QueryExpression stmt,
            QueryExpression qs,
            JavaTypeMapping ownerMapping,
            LogicSetExpression te,
            DatastoreIdentifier setTableAlias,
            Class filteredElementType,
            ScalarExpression elmExpr,
            DatastoreIdentifier elementTableAlias,
            boolean existsQuery)
    {
        throw new JPOXUserException("Cannot query sets obtained by Map.keySet()");
    }

    public QueryExpression newQueryStatement(StateManager sm, String candidateClass, DatastoreIdentifier candidateAlias)
    {
        throw new JPOXUserException("Cannot query sets obtained by Map.keySet()");
    }
}
TOP

Related Classes of org.jpox.store.rdbms.scostore.MapKeySetStore

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.