Package org.apache.ojb.broker.accesslayer

Source Code of org.apache.ojb.broker.accesslayer.StatementManager

package org.apache.ojb.broker.accesslayer;

/* Copyright 2002-2004 The Apache Software Foundation
*
* 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.
*/

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;

import org.apache.ojb.broker.Identity;
import org.apache.ojb.broker.PersistenceBroker;
import org.apache.ojb.broker.PersistenceBrokerException;
import org.apache.ojb.broker.PersistenceBrokerSQLException;
import org.apache.ojb.broker.core.ValueContainer;
import org.apache.ojb.broker.metadata.ArgumentDescriptor;
import org.apache.ojb.broker.metadata.ClassDescriptor;
import org.apache.ojb.broker.metadata.FieldDescriptor;
import org.apache.ojb.broker.metadata.ProcedureDescriptor;
import org.apache.ojb.broker.platforms.Platform;
import org.apache.ojb.broker.platforms.PlatformException;
import org.apache.ojb.broker.platforms.PlatformFactory;
import org.apache.ojb.broker.query.BetweenCriteria;
import org.apache.ojb.broker.query.Criteria;
import org.apache.ojb.broker.query.ExistsCriteria;
import org.apache.ojb.broker.query.FieldCriteria;
import org.apache.ojb.broker.query.InCriteria;
import org.apache.ojb.broker.query.NullCriteria;
import org.apache.ojb.broker.query.Query;
import org.apache.ojb.broker.query.SelectionCriteria;
import org.apache.ojb.broker.query.SqlCriteria;
import org.apache.ojb.broker.util.logging.Logger;
import org.apache.ojb.broker.util.logging.LoggerFactory;

/**
* manages JDBC Connection and Statement resources.
*
* @author Thomas Mahler
* @author <a href="mailto:rburt3@mchsi.com">Randall Burt</a>
* @version $Id: StatementManager.java,v 1.47.2.2 2005/03/02 20:32:35 mkalen Exp $
*/
public class StatementManager implements StatementManagerIF
{
    private Logger m_log = LoggerFactory.getLogger(StatementManager.class);

    /** the associated broker */
    private final PersistenceBroker m_broker;
    private Platform m_platform;
    /**
     * Used when OJB run in JBoss
     * TODO: Find a better solution to handle OJB within JBoss
     * --> the JCA implementation should solve this problem
     *
     * arminw:
     * Seems with JBoss 3.2.2 or higher the problem is gone, so we
     * can deprecate this attribute sooner or later
     */
    private boolean m_eagerRelease;
    private ConnectionManagerIF m_conMan;

    public StatementManager(final PersistenceBroker pBroker)
    {
        this.m_broker = pBroker;
        this.m_conMan = m_broker.serviceConnectionManager();
        m_eagerRelease = m_conMan.getConnectionDescriptor().getEagerRelease();
        m_platform = PlatformFactory.getPlatformFor(m_conMan.getConnectionDescriptor());
    }

    public void closeResources(Statement stmt, ResultSet rs)
    {
        if (m_log.isDebugEnabled())
            m_log.debug("closeResources was called");
        try
        {
            m_platform.beforeStatementClose(stmt, rs);
            //close statement on wrapped statement class, or real statement
            if (stmt != null)
            {
                //log.info("## close: "+stmt);
                stmt.close();

                /*
                *********************************************
                special stuff for OJB within JBoss
                ********************************************
                */
                if (m_eagerRelease)
                {
                    m_conMan.releaseConnection();
                }

            }
            m_platform.afterStatementClose(stmt, rs);
        }
        catch (PlatformException e)
        {
            m_log.error("Platform dependent operation failed", e);
        }
        catch (SQLException ignored)
        {
            if (m_log.isDebugEnabled())
                m_log.debug("Statement closing failed", ignored);
        }
    }

    /**
     * binds the Identities Primary key values to the statement
     */
    public void bindDelete(PreparedStatement stmt, Identity oid, ClassDescriptor cld) throws SQLException
    {
        Object[] pkValues = oid.getPrimaryKeyValues();
        FieldDescriptor[] pkFields = cld.getPkFields();
        int i = 0;
        try
        {
            for (; i < pkValues.length; i++)
            {
                setObjectForStatement(stmt, i + 1, pkValues[i], pkFields[i].getJdbcType().getType());
            }
        }
        catch (SQLException e)
        {
            m_log.error("bindDelete failed for: " + oid.toString() + ", while set value '" +
                    pkValues[i] + "' for column " + pkFields[i].getColumnName());
            throw e;
        }
    }

    /**
     * binds the objects primary key and locking values to the statement, BRJ
     */
    public void bindDelete(PreparedStatement stmt, ClassDescriptor cld, Object obj) throws SQLException
    {
        if (cld.getDeleteProcedure() != null)
        {
            this.bindProcedure(stmt, cld, obj, cld.getDeleteProcedure());
        }
        else
        {
            int index = 1;
            ValueContainer[] values, currentLockingValues;

            currentLockingValues = cld.getCurrentLockingValues(obj);
            // parameters for WHERE-clause pk
            values = getKeyValues(m_broker, cld, obj);
            for (int i = 0; i < values.length; i++)
            {
                setObjectForStatement(stmt, index, values[i].getValue(), values[i].getJdbcType().getType());
                index++;
            }

            // parameters for WHERE-clause locking
            values = currentLockingValues;
            for (int i = 0; i < values.length; i++)
            {
                setObjectForStatement(stmt, index, values[i].getValue(), values[i].getJdbcType().getType());
                index++;
            }
        }
    }

    /**
     * bind attribute and value
     * @param stmt
     * @param index
     * @param attributeOrQuery
     * @param value
     * @param cld
     * @return
     * @throws SQLException
     */
    private int bindStatementValue(PreparedStatement stmt, int index, Object attributeOrQuery, Object value, ClassDescriptor cld)
            throws SQLException
    {
        FieldDescriptor fld = null;
        // if value is a subQuery bind it
        if (value instanceof Query)
        {
            Query subQuery = (Query) value;
            return bindStatement(stmt, subQuery, cld.getRepository().getDescriptorFor(subQuery.getSearchClass()), index);
        }

        // if attribute is a subQuery bind it
        if (attributeOrQuery instanceof Query)
        {
            Query subQuery = (Query) attributeOrQuery;
            bindStatement(stmt, subQuery, cld.getRepository().getDescriptorFor(subQuery.getSearchClass()), index);
        }
        else
        {
            fld = cld.getFieldDescriptorForPath((String) attributeOrQuery);
        }

        if (fld != null)
        {
            // BRJ: use field conversions and platform
            if (value != null)
            {
                m_platform.setObjectForStatement(stmt, index, fld.getFieldConversion().javaToSql(value), fld.getJdbcType().getType());
            }
            else
            {
                m_platform.setNullForStatement(stmt, index, fld.getJdbcType().getType());
            }
        }
        else
        {
            if (value != null)
            {
                stmt.setObject(index, value);
            }
            else
            {
                stmt.setNull(index, Types.NULL);
            }
        }

        return ++index; // increment before return
    }

    /**
     * bind SelectionCriteria
     * @param stmt the PreparedStatement
     * @param index the position of the parameter to bind
     * @param crit the Criteria containing the parameter
     * @param cld the ClassDescriptor
     * @return next index for PreparedStatement
     */
    private int bindStatement(PreparedStatement stmt, int index, SelectionCriteria crit, ClassDescriptor cld) throws SQLException
    {
        return bindStatementValue(stmt, index, crit.getAttribute(), crit.getValue(), cld);
    }

    /**
     * bind NullCriteria
     * @param stmt the PreparedStatement
     * @param index the position of the parameter to bind
     * @param crit the Criteria containing the parameter
     * @return next index for PreparedStatement
     */
    private int bindStatement(PreparedStatement stmt, int index, NullCriteria crit)
    {
        return index;
    }

    /**
     * bind FieldCriteria
     * @param stmt , the PreparedStatement
     * @param index , the position of the parameter to bind
     * @param crit , the Criteria containing the parameter
     * @return next index for PreparedStatement
     */
    private int bindStatement(PreparedStatement stmt, int index, FieldCriteria crit)
    {
        return index;
    }

    /**
     * bind SqlCriteria
     * @param stmt the PreparedStatement
     * @param index the position of the parameter to bind
     * @param crit the Criteria containing the parameter
     * @return next index for PreparedStatement
     */
    private int bindStatement(PreparedStatement stmt, int index, SqlCriteria crit)
    {
        return index;
    }

    /**
     * bind BetweenCriteria
     * @param stmt the PreparedStatement
     * @param index the position of the parameter to bind
     * @param crit the Criteria containing the parameter
     * @param cld the ClassDescriptor
     * @return next index for PreparedStatement
     */
    private int bindStatement(PreparedStatement stmt, int index, BetweenCriteria crit, ClassDescriptor cld) throws SQLException
    {
        index = bindStatementValue(stmt, index, crit.getAttribute(), crit.getValue(), cld);

        return bindStatementValue(stmt, index, crit.getAttribute(), crit.getValue2(), cld);
    }

    /**
     * bind InCriteria
     * @param stmt the PreparedStatement
     * @param index the position of the parameter to bind
     * @param crit the Criteria containing the parameter
     * @param cld the ClassDescriptor
     * @return next index for PreparedStatement
     */
    private int bindStatement(PreparedStatement stmt, int index, InCriteria crit, ClassDescriptor cld) throws SQLException
    {
        if (crit.getValue() instanceof Collection)
        {
            Collection values = (Collection) crit.getValue();
            Iterator iter = values.iterator();

            while (iter.hasNext())
            {
                index = bindStatementValue(stmt, index, crit.getAttribute(), iter.next(), cld);
            }
        }
        else
        {
            index = bindStatementValue(stmt, index, crit.getAttribute(), crit.getValue(), cld);
        }
        return index;
    }

    /**
     * bind ExistsCriteria
     * @param stmt the PreparedStatement
     * @param index the position of the parameter to bind
     * @param crit the Criteria containing the parameter
     * @param cld the ClassDescriptor
     * @return next index for PreparedStatement
     */
    private int bindStatement(PreparedStatement stmt, int index, ExistsCriteria crit, ClassDescriptor cld) throws SQLException
    {
        Query subQuery = (Query) crit.getValue();

        // if query has criteria, bind them
        if (subQuery.getCriteria() != null && !subQuery.getCriteria().isEmpty())
        {
            return bindStatement(stmt, subQuery.getCriteria(), cld.getRepository().getDescriptorFor(subQuery.getSearchClass()), index);

            // otherwise, just ignore it
        }
        else
        {
            return index;
        }
    }

    /**
     * bind a Query based Select Statement
     */
    public int bindStatement(PreparedStatement stmt, Query query, ClassDescriptor cld, int param) throws SQLException
    {
        int result;

        result = bindStatement(stmt, query.getCriteria(), cld, param);
        result = bindStatement(stmt, query.getHavingCriteria(), cld, result);

        return result;
    }

    /**
     * bind a Query based Select Statement
     */
    protected int bindStatement(PreparedStatement stmt, Criteria crit, ClassDescriptor cld, int param) throws SQLException
    {
        if (crit != null)
        {
            Enumeration e = crit.getElements();

            while (e.hasMoreElements())
            {
                Object o = e.nextElement();
                if (o instanceof Criteria)
                {
                    Criteria pc = (Criteria) o;
                    param = bindStatement(stmt, pc, cld, param);
                }
                else
                {
                    SelectionCriteria c = (SelectionCriteria) o;
                    // BRJ : bind once for the criterion's main class
                    param = bindSelectionCriteria(stmt, param, c, cld);

                    // BRJ : and once for each extent
                    for (int i = 0; i < c.getNumberOfExtentsToBind(); i++)
                    {
                        param = bindSelectionCriteria(stmt, param, c, cld);
                    }
                }
            }
        }
        return param;
    }

    /**
     * bind SelectionCriteria
     * @param stmt the PreparedStatement
     * @param index the position of the parameter to bind
     * @param crit the Criteria containing the parameter
     * @param cld the ClassDescriptor
     * @return next index for PreparedStatement
     */
    private int bindSelectionCriteria(PreparedStatement stmt, int index, SelectionCriteria crit, ClassDescriptor cld) throws SQLException
    {
        if (crit instanceof NullCriteria)
            index = bindStatement(stmt, index, (NullCriteria) crit);
        else if (crit instanceof BetweenCriteria)
            index = bindStatement(stmt, index, (BetweenCriteria) crit, cld);
        else if (crit instanceof InCriteria)
            index = bindStatement(stmt, index, (InCriteria) crit, cld);
        else if (crit instanceof SqlCriteria)
            index = bindStatement(stmt, index, (SqlCriteria) crit);
        else if (crit instanceof FieldCriteria)
            index = bindStatement(stmt, index, (FieldCriteria) crit);
        else if (crit instanceof ExistsCriteria)
            index = bindStatement(stmt, index, (ExistsCriteria) crit, cld);
        else
            index = bindStatement(stmt, index, crit, cld);

        return index;
    }

    /**
     * binds the values of the object obj to the statements parameters
     */
    public void bindInsert(PreparedStatement stmt, ClassDescriptor cld, Object obj) throws java.sql.SQLException
    {
        ValueContainer[] values;
        cld.updateLockingValues(obj); // BRJ : provide useful defaults for locking fields

        if (cld.getInsertProcedure() != null)
        {
            this.bindProcedure(stmt, cld, obj, cld.getInsertProcedure());
        }
        else
        {
            values = getAllValues(cld, obj);
            for (int i = 0; i < values.length; i++)
            {
                setObjectForStatement(stmt, i + 1, values[i].getValue(), values[i].getJdbcType().getType());
            }
        }
    }

    /**
     * binds the Identities Primary key values to the statement
     */
    public void bindSelect(PreparedStatement stmt, Identity oid, ClassDescriptor cld) throws SQLException
    {
        ValueContainer[] values = null;
        int i = 0;

        if (cld == null)
        {
            cld = m_broker.getClassDescriptor(oid.getObjectsRealClass());
        }
        try
        {
            values = getKeyValues(m_broker, cld, oid);
            for (i = 0; i < values.length; i++)
            {
                setObjectForStatement(stmt, i + 1, values[i].getValue(), values[i].getJdbcType().getType());
            }
        }
        catch (SQLException e)
        {
            m_log.error("bindSelect failed for: " + oid.toString() + ", PK: " + i + ", value: " + values[i]);
            throw e;
        }
    }

    /**
     * binds the values of the object obj to the statements parameters
     */
    public void bindUpdate(PreparedStatement stmt, ClassDescriptor cld, Object obj) throws java.sql.SQLException
    {
        if (cld.getUpdateProcedure() != null)
        {
            this.bindProcedure(stmt, cld, obj, cld.getUpdateProcedure());
        }
        else
        {
            int index = 1;
            ValueContainer[] values, valuesSnapshot;
            // first take a snapshot of current locking values
            valuesSnapshot = cld.getCurrentLockingValues(obj);
            cld.updateLockingValues(obj); // BRJ
            values = getNonKeyValues(m_broker, cld, obj);

            // parameters for SET-clause
            for (int i = 0; i < values.length; i++)
            {
                setObjectForStatement(stmt, index, values[i].getValue(), values[i].getJdbcType().getType());
                index++;
            }
            // parameters for WHERE-clause pk
            values = getKeyValues(m_broker, cld, obj);
            for (int i = 0; i < values.length; i++)
            {
                setObjectForStatement(stmt, index, values[i].getValue(), values[i].getJdbcType().getType());
                index++;
            }
            // parameters for WHERE-clause locking
            // take old locking values
            values = valuesSnapshot;
            for (int i = 0; i < values.length; i++)
            {
                setObjectForStatement(stmt, index, values[i].getValue(), values[i].getJdbcType().getType());
                index++;
            }
        }
    }

    /**
     * binds the given array of values (if not null) starting from the given
     * parameter index
     * @return the next parameter index
     */
    public int bindValues(PreparedStatement stmt, ValueContainer[] values, int index) throws SQLException
    {
        if (values != null)
        {
            for (int i = 0; i < values.length; i++)
            {
                setObjectForStatement(stmt, index, values[i].getValue(), values[i].getJdbcType().getType());
                index++;
            }
        }
        return index;
    }

    /**
     * return a prepared DELETE Statement fitting for the given ClassDescriptor
     */
    public PreparedStatement getDeleteStatement(ClassDescriptor cld) throws PersistenceBrokerSQLException, PersistenceBrokerException
    {
        try
        {
            return cld.getStatementsForClass(m_conMan).getDeleteStmt(m_conMan.getConnection());
        }
        catch (SQLException e)
        {
            throw new PersistenceBrokerSQLException("Could not build statement ask for", e);
        }
        catch (LookupException e)
        {
            throw new PersistenceBrokerException("Used ConnectionManager instance could not obtain a connection", e);
        }
    }

    /**
     * return a generic Statement for the given ClassDescriptor.
     * Never use this method for UPDATE/INSERT/DELETE if you want to use the batch mode.
     */
    public Statement getGenericStatement(ClassDescriptor cds, boolean scrollable) throws PersistenceBrokerException
    {
        try
        {
            return cds.getStatementsForClass(m_conMan).getGenericStmt(m_conMan.getConnection(), scrollable);
        }
        catch (LookupException e)
        {
            throw new PersistenceBrokerException("Used ConnectionManager instance could not obtain a connection", e);
        }
    }

    /**
     * return a prepared Insert Statement fitting for the given ClassDescriptor
     */
    public PreparedStatement getInsertStatement(ClassDescriptor cds) throws PersistenceBrokerSQLException, PersistenceBrokerException
    {
        try
        {
            return cds.getStatementsForClass(m_conMan).getInsertStmt(m_conMan.getConnection());
        }
        catch (SQLException e)
        {
            throw new PersistenceBrokerSQLException("Could not build statement ask for", e);
        }
        catch (LookupException e)
        {
            throw new PersistenceBrokerException("Used ConnectionManager instance could not obtain a connection", e);
        }
    }

    /**
     * return a generic Statement for the given ClassDescriptor
     */
    public PreparedStatement getPreparedStatement(ClassDescriptor cds, String sql, boolean scrollable) throws PersistenceBrokerException
    {
        try
        {
            return cds.getStatementsForClass(m_conMan).getPreparedStmt(m_conMan.getConnection(), sql, scrollable);
        }
        catch (LookupException e)
        {
            throw new PersistenceBrokerException("Used ConnectionManager instance could not obtain a connection", e);
        }
    }

    /**
     * return a prepared Select Statement for the given ClassDescriptor
     */
    public PreparedStatement getSelectByPKStatement(ClassDescriptor cds) throws PersistenceBrokerSQLException, PersistenceBrokerException
    {
        try
        {
            return cds.getStatementsForClass(m_conMan).getSelectByPKStmt(m_conMan.getConnection());
        }
        catch (SQLException e)
        {
            throw new PersistenceBrokerSQLException("Could not build statement ask for", e);
        }
        catch (LookupException e)
        {
            throw new PersistenceBrokerException("Used ConnectionManager instance could not obtain a connection", e);
        }
    }

    /**
     * return a prepared Update Statement fitting to the given ClassDescriptor
     */
    public PreparedStatement getUpdateStatement(ClassDescriptor cds) throws PersistenceBrokerSQLException, PersistenceBrokerException
    {
        try
        {
            return cds.getStatementsForClass(m_conMan).getUpdateStmt(m_conMan.getConnection());
        }
        catch (SQLException e)
        {
            throw new PersistenceBrokerSQLException("Could not build statement ask for", e);
        }
        catch (LookupException e)
        {
            throw new PersistenceBrokerException("Used ConnectionManager instance could not obtain a connection", e);
        }
    }

    /**
     * returns an array containing values for all the Objects attribute
     * @throws PersistenceBrokerException if there is an erros accessing obj field values
     */
    protected ValueContainer[] getAllValues(ClassDescriptor cld, Object obj) throws PersistenceBrokerException
    {
        return m_broker.serviceBrokerHelper().getAllRwValues(cld, obj);
    }

    /**
     * returns an Array with an Objects PK VALUES
     * @throws PersistenceBrokerException if there is an erros accessing o field values
     */
    protected ValueContainer[] getKeyValues(PersistenceBroker broker, ClassDescriptor cld, Object obj) throws PersistenceBrokerException
    {
        return broker.serviceBrokerHelper().getKeyValues(cld, obj);
    }

    /**
     * returns an Array with an Identities PK VALUES
     * @throws PersistenceBrokerException if there is an erros accessing o field values
     */
    protected ValueContainer[] getKeyValues(PersistenceBroker broker, ClassDescriptor cld, Identity oid) throws PersistenceBrokerException
    {
        return broker.serviceBrokerHelper().getKeyValues(cld, oid);
    }

    /**
     * returns an Array with an Objects NON-PK VALUES
     * @throws PersistenceBrokerException if there is an erros accessing o field values
     */
    protected ValueContainer[] getNonKeyValues(PersistenceBroker broker, ClassDescriptor cld, Object obj) throws PersistenceBrokerException
    {
        return broker.serviceBrokerHelper().getNonKeyRwValues(cld, obj);
    }

    /**
     * Bind a prepared statment that represents a call to a procedure or
     * user-defined function.
     *
     * @param stmt the statement to bind.
     * @param cld the class descriptor of the object that triggered the
     *        invocation of the procedure or user-defined function.
     * @param obj the object that triggered the invocation of the procedure
     *        or user-defined function.
     * @param proc the procedure descriptor that provides information about
     *        the arguments that shoudl be passed to the procedure or
     *        user-defined function
     */
    private void bindProcedure(PreparedStatement stmt, ClassDescriptor cld, Object obj, ProcedureDescriptor proc)
            throws SQLException
    {
        int valueSub = 0;

        // Figure out if we are using a callable statement.  If we are, then we
        // will need to register one or more output parameters.
        CallableStatement callable = null;
        if (stmt instanceof CallableStatement)
        {
            callable = (CallableStatement) stmt;
        }

        // If we have a return value, then register it.
        if ((proc.hasReturnValue()) && (callable != null))
        {
            int jdbcType = proc.getReturnValueFieldRef().getJdbcType().getType();
            m_platform.setNullForStatement(stmt, valueSub + 1, jdbcType);
            callable.registerOutParameter(valueSub + 1, jdbcType);
            valueSub++;
        }

        // Process all of the arguments.
        Iterator iterator = proc.getArguments().iterator();
        while (iterator.hasNext())
        {
            ArgumentDescriptor arg = (ArgumentDescriptor) iterator.next();
            Object val = arg.getValue(obj);
            int jdbcType = arg.getJdbcType();
            setObjectForStatement(stmt, valueSub + 1, val, jdbcType);
            if ((arg.getIsReturnedByProcedure()) && (callable != null))
            {
                callable.registerOutParameter(valueSub + 1, jdbcType);
            }
            valueSub++;
        }
    }

    /**
     * Sets object for statement at specific index, adhering to platform- and null-rules.
     * @param stmt the statement
     * @param index the current parameter index
     * @param value the value to set
     * @param sqlType the JDBC SQL-type of the value
     * @throws SQLException on platform error
     */
    private void setObjectForStatement(PreparedStatement stmt, int index, Object value, int sqlType)
            throws SQLException
    {
        if (value == null)
        {
            m_platform.setNullForStatement(stmt, index, sqlType);
        }
        else
        {
            m_platform.setObjectForStatement(stmt, index, value, sqlType);
        }
    }

}
TOP

Related Classes of org.apache.ojb.broker.accesslayer.StatementManager

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.