Package org.jpox.store.rdbms.scostore

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

/**********************************************************************
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
2004 Andy Jefferson - moved statements to AbstractSetStore
    ...
**********************************************************************/
package org.jpox.store.rdbms.scostore;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;

import org.jpox.ClassLoaderResolver;
import org.jpox.ManagedConnection;
import org.jpox.ObjectManager;
import org.jpox.StateManager;
import org.jpox.exceptions.JPOXDataStoreException;
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.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.mapped.mapping.Mappings;
import org.jpox.store.rdbms.SQLController;
import org.jpox.store.rdbms.SQLWarnings;
import org.jpox.store.rdbms.mapping.RDBMSMapping;
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.scostore.MapStore;

/**
* Representation of the backing store for a MapValue Set.
* This is used where the user calls Map.values() and then wants to perform
* some operation on the resulting Collection.
* TODO Cater for embedded values.
*
* @version $Revision: 1.69 $
**/
public class MapValueSetStore extends AbstractSetStore
{
    private final MapStore mapStore;
    private final JavaTypeMapping keyMapping;
    private final String findKeyStmt;

    private DatastoreIdentifier valueIdentifier;

    /**
     * Constructor where a join table is used to store the map relation.
     * @param mapTable Table used by the map
     * @param mapStore Store used by the map
     * @param clr The ClassLoaderResolver
     */
    public MapValueSetStore(MapTable mapTable, MapStore mapStore, ClassLoaderResolver clr)
    {
        super(mapTable.getStoreManager(), clr);

        this.containerTable = mapTable;
        this.mapStore = mapStore;

        setName = "values";
        ownerMapping = mapTable.getOwnerMapping();
        keyMapping = mapTable.getKeyMapping();
        elementMapping = mapTable.getValueMapping();

        elementType = elementMapping.getType();
        elementsAreEmbedded = isEmbeddedMapping(elementMapping);
        elementsAreSerialised = isEmbeddedMapping(elementMapping);

        initialize(clr);

        findKeyStmt  = getFindKeyStmt();
    }

    /**
     * Constructor where either the key is stored in the value table or the value is stored in the key table.
     * @param valueTable Table for the values
     * @param ownerMapping Mapping to the owner
     * @param valueMapping The mapping for this table to the value table/column
     * @param mapStore Store used by the map.
     * @param clr The ClassLoaderResolver
     * @param fmd FieldMetaData for the owning "map" field
     */
    public MapValueSetStore(DatastoreClass valueTable, JavaTypeMapping ownerMapping, JavaTypeMapping valueMapping, MapStore mapStore,
            ClassLoaderResolver clr, AbstractMemberMetaData fmd)
    {
        super(valueTable.getStoreManager(), clr);

        this.containerTable = valueTable;
        setName = "values";
        this.ownerMemberMetaData = fmd;

        this.ownerMapping = ownerMapping;
        this.keyMapping = null;
        this.elementMapping = valueMapping;

        this.mapStore = mapStore;

        initialize(clr);

        clearStmt = null;
        findKeyStmt  = null;
    }

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

        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");
    }

    /**
     * Generate statement to find the first key for a value in the Map.
     * <PRE>
     * SELECT KEYCOL FROM SETTABLE
     * WHERE OWNERCOL=?
     * AND ELEMENTCOL = ?
     * </PRE>
     * @return Statement to find keys in the Map.
     */
    private String getFindKeyStmt()
    {
        StringBuffer stmt = new StringBuffer();
        stmt.append("SELECT ");
        for (int i=0; i<keyMapping.getNumberOfDatastoreFields(); i++)
        {
            if (i > 0)
            {
                stmt.append(",");
            }
            stmt.append(keyMapping.getDataStoreMapping(i).getDatastoreField().getIdentifier().toString());
        }
        stmt.append(" FROM ");
        stmt.append(containerTable.toString());
        stmt.append(" WHERE ");
        for (int i=0; i<ownerMapping.getNumberOfDatastoreFields(); i++)
        {
            if (i > 0)
            {
                stmt.append(" AND ");
            }
            stmt.append(ownerMapping.getDataStoreMapping(i).getDatastoreField().getIdentifier().toString());
            stmt.append(" = ");
            stmt.append(((RDBMSMapping)ownerMapping.getDataStoreMapping(i)).getUpdateInputParameter());
        }
        for (int i=0; i<elementMapping.getNumberOfDatastoreFields(); i++)
        {
            stmt.append(" AND ");
            stmt.append(elementMapping.getDataStoreMapping(i).getDatastoreField().getIdentifier().toString());
            stmt.append(" = ");
            stmt.append(((RDBMSMapping)elementMapping.getDataStoreMapping(i)).getUpdateInputParameter());
        }  
        return stmt.toString();
    }

    /**
     * Accessor for the statement for the iterator.
     * @param ownerSM the owner StateManager
     * @return The iterator Query Statement.
     **/   
    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 Value 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
        {
            stmt = new UnionIteratorStatement(clr, elementCls, true, this.storeMgr,
                elementCls, elementMapping, containerTable, false, null,
                true, false).getQueryStatement(null);
        }

        // Apply condition on owner field to filter by owner
        ScalarExpression ownerExpr = ownerMapping.newScalarExpression(stmt, stmt.getMainTableExpression());
        ScalarExpression ownerVal = ownerMapping.newLiteral(stmt, ownerSM.getObject());
        stmt.andCondition(ownerExpr.eq(ownerVal), true);

        return stmt;
    }

    /**
     * Method to add a value to the Map. Not supported.
     * @param sm State Manager for the owner
     * @param element The value to add
     * @return Whether it was added correctly.
     */
    public boolean add(StateManager sm, Object element, int size)
    {
        throw new UnsupportedOperationException("Cannot add to a map through its value set");
    }

    /**
     * Method to add entries to the Map. Not supported.
     * @param sm State Manager for the owner
     * @param elements The values to add
     * @return Whether it was added correctly.
     */
    public boolean addAll(StateManager sm, Collection elements, int size)
    {
        throw new UnsupportedOperationException("Cannot add to a map through its value set");
    }

    /**
     * Method to remove a value from the Map.
     * @param sm State Manager for the owner
     * @param element The value to remove
     * @return Whether it was removed correctly.
     */
    public boolean remove(StateManager sm, Object element, int size, boolean allowDependentField)
    {
        if (findKeyStmt == null)
        {
            throw new UnsupportedOperationException("Cannot remove from an inverse map through its value set");
        }

        if (!validateElementForReading(sm, element))
        {
            return false;
        }

        Object key = null;
        boolean keyExists = false;
        ObjectManager om = sm.getObjectManager();

        try
        {
            ManagedConnection mconn = storeMgr.getConnection(om);
            SQLController sqlControl = storeMgr.getSQLController();

            try
            {
                PreparedStatement ps = sqlControl.getStatementForQuery(mconn, findKeyStmt);

                try
                {
                    int jdbcPosition = 1;
                    jdbcPosition = populateOwnerInStatement(sm, om, ps, jdbcPosition);
                    jdbcPosition = populateElementInStatement(om, ps, element, jdbcPosition);

                    ResultSet rs = sqlControl.executeStatementQuery(mconn, findKeyStmt, ps);
                    try
                    {
                        if (rs.next())
                        {
                            key = keyMapping.getObject(om, rs, Mappings.getParametersIndex(1,keyMapping));
                            keyExists = true;
                        }

                        SQLWarnings.log(rs);
                    }
                    finally
                    {
                        rs.close();
                    }
                }
                finally
                {
                    sqlControl.closeStatement(mconn, ps);
                }
            }
            finally
            {
                mconn.release();
            }
        }
        catch (SQLException e)
        {
            throw new JPOXDataStoreException("Request failed to check if set contains an element: " + findKeyStmt, e);
        }

        if (keyExists)
        {
            mapStore.remove(sm, key);
            return true;
        }
        else
        {
            return false;
        }
    }

    /**
     * Method to remove elements from the map via the value collection.
     * @param sm StateManager for the owner
     */
    public boolean removeAll(StateManager sm, Collection elements, int size)
    {
        throw new JPOXUserException("Cannot remove elements from a map through its value set");
    }

    /**
     * Method to clear the map.
     * @param sm StateManager for the owner
     */
    public void clear(StateManager sm)
    {
        if (clearStmt == null)
        {
            throw new JPOXUserException("Cannot clear an inverse map through its value set");
        }

        super.clear(sm);
    }
    // --------------------------- JDOQL Query Methods -------------------------------

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

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

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

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.