Package org.jpox.store.rdbms.request

Source Code of org.jpox.store.rdbms.request.VersionCheckRequest

/**********************************************************************
Copyright (c) 2006 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.jpox.store.rdbms.request;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.jpox.ClassLoaderResolver;
import org.jpox.ManagedConnection;
import org.jpox.ObjectManager;
import org.jpox.StateManager;
import org.jpox.metadata.AbstractClassMetaData;
import org.jpox.metadata.AbstractMemberMetaData;
import org.jpox.metadata.IdentityType;
import org.jpox.metadata.VersionMetaData;
import org.jpox.metadata.VersionStrategy;
import org.jpox.store.mapped.DatastoreClass;
import org.jpox.store.mapped.DatastoreField;
import org.jpox.store.mapped.FetchStatement;
import org.jpox.store.mapped.StatementExpressionIndex;
import org.jpox.store.mapped.mapping.JavaTypeMapping;
import org.jpox.store.mapped.mapping.MappingConsumer;
import org.jpox.store.rdbms.RDBMSFetchStatement;
import org.jpox.store.rdbms.SQLController;
import org.jpox.store.rdbms.fieldmanager.ParameterSetter;
import org.jpox.store.rdbms.mapping.RDBMSMapping;
import org.jpox.store.rdbms.table.AbstractClassTable;

/**
* Base class for all requests that need to check the optimistic version of an object before proceeding.
*
* @version $Revision: 1.9 $
*/
public abstract class VersionCheckRequest extends Request
{
    /** MetaData for the class. */
    protected AbstractClassMetaData cmd = null;

    /** SQL statement for retrieving the version. */
    protected String versionStmt = null;

    /** index for the expression in the version sql statement */
    protected MappingStatementIndex versionMappingStatementIndex = null;

    /** PK fields to be provided (if using app identity) for the version query. */
    protected int[] versionPkFieldsToBeProvided = null;

    /** Whether we should make checks on optimistic version before updating. */
    protected boolean versionChecks = false;

    /** MetaData for the version handling. */
    protected VersionMetaData versionMetaData = null;

    /** Mapping for the version field/column. */
    protected JavaTypeMapping versionMapping = null;

    /**
     * Constructor, taking the table. Uses the structure of the datastore
     * table to build a basic query.
     * @param table The Class Table representing the datastore table to delete.
     * @param cls Class of objects being deleted
     * @param clr ClassLoader resolver
     */
    public VersionCheckRequest(DatastoreClass table, Class cls, ClassLoaderResolver clr)
    {
        super(table);

        cmd = table.getStoreManager().getOMFContext().getMetaDataManager().getMetaDataForClass(cls, clr);
        versionMetaData = table.getVersionMetaData();
        if (versionMetaData != null)
        {
            if (versionMetaData.getFieldName() != null)
            {
                // Version field
                AbstractMemberMetaData fmd = cmd.getMetaDataForMember(versionMetaData.getFieldName());
                versionMapping = table.getFieldMapping(fmd);
            }
            else
            {
                // Surrogate version column
                versionMapping = table.getVersionMapping(false);
            }
            VersionMappingConsumer versionConsumer = new VersionMappingConsumer(cmd, (AbstractClassTable)table);
            versionMappingStatementIndex = versionConsumer.getMappingStatementIndex();
            versionStmt = versionConsumer.getStatement();
            versionPkFieldsToBeProvided = versionConsumer.getPrimaryKeyFieldsToBeProvided();

            if (versionMetaData.getVersionStrategy() != VersionStrategy.NONE)
            {
                // Only apply a version check if we have a strategy defined
                versionChecks = true;
            }
        }
    }

    /**
     * Method to return the current version for the passed object from the datastore.
     * @param sm StateManager for the object
     * @param mconn The connection to use
     * @param sqlControl The SQLController
     * @throws SQLException Thrown if an error occurs during the checks
     */
    protected Object getCurrentVersionForObject(StateManager sm, ManagedConnection mconn, SQLController sqlControl)
    throws SQLException
    {
        Object datastoreVersion = null;

        ObjectManager om = sm.getObjectManager();
        if (versionStmt != null)
        {
            // Version mapping present
            PreparedStatement ps = sqlControl.getStatementForQuery(mconn, versionStmt);

            try
            {
                // provide primary key fields for WHERE clause
                if (table.getIdentityType() == IdentityType.DATASTORE)
                {
                    // a). datastore identity
                    table.getDataStoreObjectIdMapping().setObject(om, ps,
                        versionMappingStatementIndex.getDatastoreId().getParameterIndex(), sm.getInternalObjectId());
                }
                else if (table.getIdentityType() == IdentityType.APPLICATION)
                {
                    // b). application identity
                    sm.provideFields(versionPkFieldsToBeProvided,
                        new ParameterSetter(sm, ps, versionMappingStatementIndex.getPrimaryKeys(), true));
                }

                ResultSet rs = sqlControl.executeStatementQuery(mconn, versionStmt, ps);
                try
                {
                    if (rs.next())
                    {
                        datastoreVersion = versionMapping.getObject(om, rs,
                            versionMappingStatementIndex.getVersion().getExpressionIndex());
                    }
                }
                finally
                {
                    rs.close();
                }
            }
            finally
            {
                sqlControl.closeStatement(mconn, ps);
            }
        }
        else
        {
            // TODO No version mapping so retrieve the datastore object and do a field-by-field comparison check
        }

        return datastoreVersion;
    }
   
    /**
     * Mapping Consumer used for generating the SELECT statement to get the version for an object in a table.
     * This statement will be of the form
     * <PRE>
     * SELECT VERSION FROM TABLE WHERE ID = ?
     * </PRE>
     *
     * @version $Revision: 1.9 $
     */
    class VersionMappingConsumer implements MappingConsumer
    {
        /** Flag for initialisation state of the consumer. */
        boolean initialized = false;

        /** Flag for whether this table has a version mapping. */
        boolean hasVersionMapping = false;

        /** Current parameter index. */
        int paramIndex = 1;

        int exprIndex = 1;

        List pkbp = new ArrayList();

        /** MetaData for the class. */
        private final AbstractClassMetaData cmd;

        /** The statement to get the version of the object. */
        FetchStatement fetchStmt = null;

        /** index for the expression(s) in the statement */
        MappingStatementIndex versionMappingStatementIndex;

        /**
         * Default constructor
         */
        public VersionMappingConsumer(AbstractClassMetaData cmd, AbstractClassTable table)
        {
            this.cmd = cmd;
            fetchStmt = new RDBMSFetchStatement(table.getPrimaryDatastoreContainerObject());
            versionMappingStatementIndex = new MappingStatementIndex();

            // Consume the mappings for the table so we can build the statement
            if (versionMetaData.getFieldName() != null)
            {
                // Version stored in column of a field
                AbstractMemberMetaData[] fmds = new AbstractMemberMetaData[1];
                fmds[0] = cmd.getMetaDataForMember(versionMetaData.getFieldName());
                table.provideMappingsForFields(this, fmds, false);
                table.providePrimaryKeyMappings(this);
                table.provideDatastoreIdMappings(this);
            }
            else
            {
                // Version stored in surrogate column
                table.provideVersionMappings(this);
                table.providePrimaryKeyMappings(this);
                table.provideDatastoreIdMappings(this);
            }
        }

        /**
         * Method to set the size of numbers of mappings to consume (so we can allocate space).
         * @param highestFieldNumber Max field numbers
         */
        public void preConsumeMapping(int highestFieldNumber)
        {
            if (!initialized)
            {
                versionMappingStatementIndex.setPrimaryKeys(new StatementExpressionIndex[highestFieldNumber]);
                initialized = true;
            }
        }

        /**
         * Method to consume mappings of particular fields.
         * @param m The mapping to consume
         * @param fmd MetaData of the field
         */
        public void consumeMapping(JavaTypeMapping m, AbstractMemberMetaData fmd)
        {
            if (!fmd.getAbstractClassMetaData().isSameOrAncestorOf(cmd))
            {
                return;
            }           
            if (m.includeInUpdateStatement())
            {
                int parametersIndex[] = new int[m.getNumberOfDatastoreFields()];

                StatementExpressionIndex sei = new StatementExpressionIndex();
                sei.setMapping(m);
                sei.setParameterIndex(parametersIndex);

                if (fmd.isPrimaryKey())
                {
                    // Application id - for WHERE
                    versionMappingStatementIndex.getPrimaryKeys()[fmd.getAbsoluteFieldNumber()] = sei;
                    for (int j=0; j<parametersIndex.length; j++)
                    {                  
                        String condition = m.getDataStoreMapping(j).getDatastoreField().getIdentifier() +
                        "=" + ((RDBMSMapping)m.getDataStoreMapping(j)).getUpdateInputParameter();
                        fetchStmt.andCondition(condition);

                        pkbp.add(new Integer(fmd.getAbsoluteFieldNumber()));
                        parametersIndex[j] = paramIndex++;
                    }                      
                }
                else
                {
                    if (fmd.getName().equals(versionMetaData.getFieldName()))
                    {
                        // Version field - for SELECT
                        hasVersionMapping = true;
                        fetchStmt.select(m.getDataStoreMapping(0).getDatastoreField());
                        versionMappingStatementIndex.getVersion().setMapping(m);
                        versionMappingStatementIndex.getVersion().setExpressionIndex(new int[]{ exprIndex++ });
                    }
                }
            }
        }

        /**
         * Method to consume mappings of particular types (datastore id, version etc)
         * @param m The mapping to consume
         * @param mappingType Type of mapping
         */
        public void consumeMapping(JavaTypeMapping m, int mappingType)
        {
            if (mappingType == MappingConsumer.MAPPING_TYPE_VERSION)
            {
                // Surrogate version column - for SELECT
                hasVersionMapping = true;
                fetchStmt.select(m.getDataStoreMapping(0).getDatastoreField());
                versionMappingStatementIndex.getVersion().setMapping(m);
                versionMappingStatementIndex.getVersion().setExpressionIndex(new int[]{ exprIndex++ });
            }            
            else if (mappingType == MappingConsumer.MAPPING_TYPE_DATASTORE_ID)
            {
                // Datastore id - for WHERE
                String condition = ((DatastoreField)key.getColumns().get(0)).getIdentifier() + "=? ";
                fetchStmt.andCondition(condition);
                int[] param = { paramIndex++ };
                versionMappingStatementIndex.getDatastoreId().setParameterIndex(param);
            }
        }

        /**
         * Consumer a datastore field without mapping.
         * @param fld The datastore field
         */
        public void consumeUnmappedDatastoreField(DatastoreField fld)
        {
            // Do nothing since we dont handle unmapped columns
        }

        /**
         * Accessor for the SQL statement to get the version
         * @return the SQL statement
         */
        public String getStatement()
        {
            if (!hasVersionMapping)
            {
                return null;
            }
            return fetchStmt.toString();
        }

        /**
         * Accessor for the mapping statement index
         * @return The Mapping statement index for the version statement
         */
        public MappingStatementIndex getMappingStatementIndex()
        {
            return versionMappingStatementIndex;
        }

        /**
         * All primary key fields to be provided to set the values in the sql statement.
         * The StateManager will call the Persistent capable class instance to provide fields
         * @return array of absolute primary key field numbers
         */       
        public int[] getPrimaryKeyFieldsToBeProvided()
        {
            int[] pkfieldsToBeProvided = new int[pkbp.size()];
            for (int i = 0; i < pkbp.size(); i++)
            {
                pkfieldsToBeProvided[i] = ((Integer) pkbp.get(i)).intValue();
            }
            return pkfieldsToBeProvided;
        }
    }
}
TOP

Related Classes of org.jpox.store.rdbms.request.VersionCheckRequest

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.