com.ibatis.sqlmap.engine.mapping.statement.MappedStatement.java Source code

Java tutorial

Introduction

Here is the source code for com.ibatis.sqlmap.engine.mapping.statement.MappedStatement.java

Source

/*
 *  Copyright 2004 Clinton Begin
 *
 *  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.
 */
package com.ibatis.sqlmap.engine.mapping.statement;

import java.io.StringReader;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.apache.commons.lang.StringUtils;
import org.w3c.dom.Document;

import com.ibatis.common.io.ReaderInputStream;
import com.ibatis.common.jdbc.exception.NestedSQLException;
import com.ibatis.sqlmap.client.SqlMapClient;
import com.ibatis.sqlmap.client.event.RowHandler;
import com.ibatis.sqlmap.engine.cache.CacheKey;
import com.ibatis.sqlmap.engine.execution.SqlExecutor;
import com.ibatis.sqlmap.engine.impl.SqlMapClientImpl;
import com.ibatis.sqlmap.engine.mapping.parameter.ParameterMap;
import com.ibatis.sqlmap.engine.mapping.result.ResultMap;
import com.ibatis.sqlmap.engine.mapping.sql.Sql;
import com.ibatis.sqlmap.engine.scope.ErrorContext;
import com.ibatis.sqlmap.engine.scope.StatementScope;
import com.ibatis.sqlmap.engine.transaction.Transaction;
import com.ibatis.sqlmap.engine.transaction.TransactionException;
import com.ibatis.sqlmap.engine.type.DomTypeMarker;
import com.ibatis.sqlmap.engine.type.XmlTypeMarker;

public class MappedStatement {
    private String id;
    private Integer resultSetType;
    private Integer fetchSize;
    private ResultMap resultMap;
    private ParameterMap parameterMap;
    private Class parameterClass;
    private Sql sql;
    private int baseCacheKey;
    private SqlMapClientImpl sqlMapClient;
    private Integer timeout;
    private ResultMap[] additionalResultMaps = new ResultMap[0];
    private List executeListeners = new ArrayList();
    private String resource;

    public StatementType getStatementType() {
        return StatementType.UNKNOWN;
    }

    public int executeUpdate(StatementScope statementScope, Transaction trans, Object parameterObject)
            throws SQLException {
        ErrorContext errorContext = statementScope.getErrorContext();
        errorContext.setActivity("preparing the mapped statement for execution");
        errorContext.setObjectId(this.getId());
        errorContext.setResource(this.getResource());

        statementScope.getSession().setCommitRequired(true);

        try {
            parameterObject = validateParameter(parameterObject);

            Sql sql = getSql();

            errorContext.setMoreInfo("Check the parameter map.");
            ParameterMap parameterMap = sql.getParameterMap(statementScope, parameterObject);

            errorContext.setMoreInfo("Check the result map.");
            ResultMap resultMap = sql.getResultMap(statementScope, parameterObject);

            statementScope.setResultMap(resultMap);
            statementScope.setParameterMap(parameterMap);

            int rows = 0;

            errorContext.setMoreInfo("Check the parameter map.");
            Object[] parameters = parameterMap.getParameterObjectValues(statementScope, parameterObject);

            errorContext.setMoreInfo("Check the SQL statement.");
            String sqlString = sql.getSql(statementScope, parameterObject);

            errorContext.setActivity("executing mapped statement");
            errorContext.setMoreInfo("Check the statement or the result map.");
            rows = sqlExecuteUpdate(statementScope, trans.getConnection(), sqlString, parameters);

            errorContext.setMoreInfo("Check the output parameters.");
            if (parameterObject != null) {
                postProcessParameterObject(statementScope, parameterObject, parameters);
            }

            errorContext.reset();
            sql.cleanup(statementScope);
            notifyListeners();
            return rows;
        } catch (SQLException e) {
            errorContext.setCause(e);
            throw new NestedSQLException(errorContext.toString(), e.getSQLState(), e.getErrorCode(), e);
        } catch (Exception e) {
            errorContext.setCause(e);
            throw new NestedSQLException(errorContext.toString(), e);
        }
    }

    public Object executeQueryForObject(StatementScope statementScope, Transaction trans, Object parameterObject,
            Object resultObject) throws SQLException {
        try {
            Object object = null;

            DefaultRowHandler rowHandler = new DefaultRowHandler();
            executeQueryWithCallback(statementScope, trans.getConnection(), parameterObject, resultObject,
                    rowHandler, SqlExecutor.NO_SKIPPED_RESULTS, SqlExecutor.NO_MAXIMUM_RESULTS);
            List list = rowHandler.getList();

            if (list.size() > 1) {
                throw new SQLException("Error: executeQueryForObject returned too many results.");
            } else if (list.size() > 0) {
                object = list.get(0);
            }

            return object;
        } catch (TransactionException e) {
            throw new NestedSQLException("Error getting Connection from Transaction.  Cause: " + e, e);
        }
    }

    /**
     * @param statementScope
     * @param trans
     * @param parameterObject
     * @param startRow
     * @param endRow
     * @return
     * @throws SQLException
     * @author shaq
     */
    public List executeQueryForPaginated(StatementScope statementScope, Transaction trans, Object parameterObject,
            int startRow, int numPerPage) throws SQLException {
        try {
            DefaultRowHandler rowHandler = new DefaultRowHandler();
            executePaginatedQueryWithCallback(statementScope, trans.getConnection(), parameterObject, null,
                    rowHandler, startRow, numPerPage);
            return rowHandler.getList();
        } catch (TransactionException e) {
            throw new NestedSQLException("Error getting Connection from Transaction.  Cause: " + e, e);
        }
    }

    public Object executeQueryForPaginatedCount(StatementScope statementScope, Transaction trans,
            Object parameterObject) throws SQLException {
        try {
            Object object = null;

            DefaultRowHandler rowHandler = new DefaultRowHandler();
            executePaginatedCountWithCallback(statementScope, trans.getConnection(), parameterObject, null,
                    rowHandler);
            List list = rowHandler.getList();
            if (list.size() > 1) {
                throw new SQLException("Error: executeQueryForObject returned too many results.");
            } else if (list.size() > 0) {
                object = list.get(0);
            }
            return object;
        } catch (TransactionException e) {
            throw new NestedSQLException("Error getting Connection from Transaction.  Cause: " + e, e);
        }
    }

    private void executePaginatedCountWithCallback(StatementScope statementScope, Connection conn,
            Object parameterObject, Object resultObject, RowHandler rowHandler) throws SQLException {

        ErrorContext errorContext = statementScope.getErrorContext();
        errorContext.setActivity("preparing the mapped statement for execution");
        errorContext.setObjectId(this.getId());
        errorContext.setResource(this.getResource());

        try {
            parameterObject = validateParameter(parameterObject);

            Sql sql = getSql();

            errorContext.setMoreInfo("Check the parameter map.");
            ParameterMap parameterMap = sql.getParameterMap(statementScope, parameterObject);

            errorContext.setMoreInfo("Check the result map.");
            ResultMap resultMap = sql.getResultMap(statementScope, parameterObject);

            statementScope.setResultMap(resultMap);
            statementScope.setParameterMap(parameterMap);

            errorContext.setMoreInfo("Check the parameter map.");
            Object[] parameters = parameterMap.getParameterObjectValues(statementScope, parameterObject);

            errorContext.setMoreInfo("Check the SQL statement.");
            String sqlString = sql.getSql(statementScope, parameterObject);
            sqlString = paginatedCountSQL(sqlString);

            errorContext.setActivity("executing mapped statement");
            errorContext.setMoreInfo("Check the SQL statement or the result map.");
            RowHandlerCallback callback = new RowHandlerCallback(resultMap, resultObject, rowHandler);
            sqlExecuteQuery(statementScope, conn, sqlString, parameters, SqlExecutor.NO_SKIPPED_RESULTS,
                    SqlExecutor.NO_MAXIMUM_RESULTS, callback);
            errorContext.setMoreInfo("Check the output parameters.");
            if (parameterObject != null) {
                postProcessParameterObject(statementScope, parameterObject, parameters);
            }

            errorContext.reset();
            sql.cleanup(statementScope);
            notifyListeners();
        } catch (SQLException e) {
            errorContext.setCause(e);
            throw new NestedSQLException(errorContext.toString(), e.getSQLState(), e.getErrorCode(), e);
        } catch (Exception e) {
            errorContext.setCause(e);
            throw new NestedSQLException(errorContext.toString(), e);
        }
    }

    private String paginatedCountSQL(String sqlString) {
        StringBuffer sqlTemplate = new StringBuffer("SELECT COUNT(*) FROM (" + SQL_SECTION + ") entity");
        return StringUtils.replace(sqlTemplate.toString(), SQL_SECTION, sqlString);
    }

    public List executeQueryForList(StatementScope statementScope, Transaction trans, Object parameterObject,
            int skipResults, int maxResults) throws SQLException {
        try {
            DefaultRowHandler rowHandler = new DefaultRowHandler();
            executeQueryWithCallback(statementScope, trans.getConnection(), parameterObject, null, rowHandler,
                    skipResults, maxResults);
            return rowHandler.getList();
        } catch (TransactionException e) {
            throw new NestedSQLException("Error getting Connection from Transaction.  Cause: " + e, e);
        }
    }

    public void executeQueryWithRowHandler(StatementScope statementScope, Transaction trans, Object parameterObject,
            RowHandler rowHandler) throws SQLException {
        try {
            executeQueryWithCallback(statementScope, trans.getConnection(), parameterObject, null, rowHandler,
                    SqlExecutor.NO_SKIPPED_RESULTS, SqlExecutor.NO_MAXIMUM_RESULTS);
        } catch (TransactionException e) {
            throw new NestedSQLException("Error getting Connection from Transaction.  Cause: " + e, e);
        }
    }

    /**
     * @param statementScope
     * @param trans
     * @param parameterObject
     * @param rowHandler
     * @throws SQLException
     * @author shaq
     */
    public void executePaginatedQueryWithRowHandler(StatementScope statementScope, Transaction trans,
            Object parameterObject, RowHandler rowHandler, int startRow, int endRow) throws SQLException {
        try {
            executePaginatedQueryWithCallback(statementScope, trans.getConnection(), parameterObject, null,
                    rowHandler, startRow, endRow);
        } catch (TransactionException e) {
            throw new NestedSQLException("Error getting Connection from Transaction.  Cause: " + e, e);
        }
    }

    /**
     * @param statementScope
     * @param conn
     * @param parameterObject
     * @param resultObject
     * @param rowHandler
     * @param skipResults
     * @param maxResults
     * @throws SQLException
     * @author shaq
     */
    protected void executePaginatedQueryWithCallback(StatementScope statementScope, Connection conn,
            Object parameterObject, Object resultObject, RowHandler rowHandler, int startRow, int endRow)
            throws SQLException {
        ErrorContext errorContext = statementScope.getErrorContext();
        errorContext.setActivity("preparing the mapped statement for execution");
        errorContext.setObjectId(this.getId());
        errorContext.setResource(this.getResource());

        try {
            parameterObject = validateParameter(parameterObject);

            Sql sql = getSql();

            errorContext.setMoreInfo("Check the parameter map.");
            ParameterMap parameterMap = sql.getParameterMap(statementScope, parameterObject);

            errorContext.setMoreInfo("Check the result map.");
            ResultMap resultMap = sql.getResultMap(statementScope, parameterObject);

            statementScope.setResultMap(resultMap);
            statementScope.setParameterMap(parameterMap);

            errorContext.setMoreInfo("Check the parameter map.");
            Object[] parameters = parameterMap.getParameterObjectValues(statementScope, parameterObject);

            errorContext.setMoreInfo("Check the SQL statement.");
            String sqlString = sql.getSql(statementScope, parameterObject);
            sqlString = paginatedSQL(sqlString, startRow, endRow);

            errorContext.setActivity("executing mapped statement");
            errorContext.setMoreInfo("Check the SQL statement or the result map.");
            RowHandlerCallback callback = new RowHandlerCallback(resultMap, resultObject, rowHandler);
            sqlExecuteQuery(statementScope, conn, sqlString, parameters, SqlExecutor.NO_SKIPPED_RESULTS,
                    SqlExecutor.NO_MAXIMUM_RESULTS, callback);
            errorContext.setMoreInfo("Check the output parameters.");
            if (parameterObject != null) {
                postProcessParameterObject(statementScope, parameterObject, parameters);
            }

            errorContext.reset();
            sql.cleanup(statementScope);
            notifyListeners();
        } catch (SQLException e) {
            errorContext.setCause(e);
            throw new NestedSQLException(errorContext.toString(), e.getSQLState(), e.getErrorCode(), e);
        } catch (Exception e) {
            errorContext.setCause(e);
            throw new NestedSQLException(errorContext.toString(), e);
        }
    }

    private final static String SQL_SECTION = "#SQL_SECTION#";

    /**
     * @param sqlString
     * @param startRow
     * @param endRow
     * @return
     * @author shaq
     */
    private String paginatedSQL(String sqlString, int startRow, int numPerPage) {
        //        StringBuffer sqlTemplate1 = new StringBuffer("SELECT outer.* FROM (SELECT ROWNUM rn, inner.* FROM ( " + SQL_SECTION + "  )  inner) outer WHERE outer.rn >= " + startRow + "AND outer.rn <= " + endRow);
        StringBuffer sqlTemplate = new StringBuffer(SQL_SECTION + "limit " + startRow + "," + numPerPage);
        String str = StringUtils.replace(sqlTemplate.toString(), SQL_SECTION, sqlString);
        return str;
    }

    protected void executeQueryWithCallback(StatementScope statementScope, Connection conn, Object parameterObject,
            Object resultObject, RowHandler rowHandler, int skipResults, int maxResults) throws SQLException {
        ErrorContext errorContext = statementScope.getErrorContext();
        errorContext.setActivity("preparing the mapped statement for execution");
        errorContext.setObjectId(this.getId());
        errorContext.setResource(this.getResource());

        try {
            parameterObject = validateParameter(parameterObject);

            Sql sql = getSql();

            errorContext.setMoreInfo("Check the parameter map.");
            ParameterMap parameterMap = sql.getParameterMap(statementScope, parameterObject);

            errorContext.setMoreInfo("Check the result map.");
            ResultMap resultMap = sql.getResultMap(statementScope, parameterObject);

            statementScope.setResultMap(resultMap);
            statementScope.setParameterMap(parameterMap);

            errorContext.setMoreInfo("Check the parameter map.");
            Object[] parameters = parameterMap.getParameterObjectValues(statementScope, parameterObject);

            errorContext.setMoreInfo("Check the SQL statement.");
            String sqlString = sql.getSql(statementScope, parameterObject);

            errorContext.setActivity("executing mapped statement");
            errorContext.setMoreInfo("Check the SQL statement or the result map.");
            RowHandlerCallback callback = new RowHandlerCallback(resultMap, resultObject, rowHandler);
            sqlExecuteQuery(statementScope, conn, sqlString, parameters, skipResults, maxResults, callback);

            errorContext.setMoreInfo("Check the output parameters.");
            if (parameterObject != null) {
                postProcessParameterObject(statementScope, parameterObject, parameters);
            }

            errorContext.reset();
            sql.cleanup(statementScope);
            notifyListeners();
        } catch (SQLException e) {
            errorContext.setCause(e);
            throw new NestedSQLException(errorContext.toString(), e.getSQLState(), e.getErrorCode(), e);
        } catch (Exception e) {
            errorContext.setCause(e);
            throw new NestedSQLException(errorContext.toString(), e);
        }
    }

    protected void postProcessParameterObject(StatementScope statementScope, Object parameterObject,
            Object[] parameters) {
    }

    protected int sqlExecuteUpdate(StatementScope statementScope, Connection conn, String sqlString,
            Object[] parameters) throws SQLException {
        if (statementScope.getSession().isInBatch()) {
            getSqlExecutor().addBatch(statementScope, conn, sqlString, parameters);
            return 0;
        } else {
            return getSqlExecutor().executeUpdate(statementScope, conn, sqlString, parameters);
        }
    }

    protected void sqlExecuteQuery(StatementScope statementScope, Connection conn, String sqlString,
            Object[] parameters, int skipResults, int maxResults, RowHandlerCallback callback) throws SQLException {
        getSqlExecutor().executeQuery(statementScope, conn, sqlString, parameters, skipResults, maxResults,
                callback);
    }

    protected Object validateParameter(Object param) throws SQLException {
        Object newParam = param;
        Class parameterClass = getParameterClass();
        if (newParam != null && parameterClass != null) {
            if (DomTypeMarker.class.isAssignableFrom(parameterClass)) {
                if (XmlTypeMarker.class.isAssignableFrom(parameterClass)) {
                    if (!(newParam instanceof String) && !(newParam instanceof Document)) {
                        throw new SQLException("Invalid parameter object type.  Expected '" + String.class.getName()
                                + "' or '" + Document.class.getName() + "' but found '"
                                + newParam.getClass().getName() + "'.");
                    }
                    if (!(newParam instanceof Document)) {
                        newParam = stringToDocument((String) newParam);
                    }
                } else {
                    if (!Document.class.isAssignableFrom(newParam.getClass())) {
                        throw new SQLException(
                                "Invalid parameter object type.  Expected '" + Document.class.getName()
                                        + "' but found '" + newParam.getClass().getName() + "'.");
                    }
                }
            } else {
                if (!parameterClass.isAssignableFrom(newParam.getClass())) {
                    throw new SQLException("Invalid parameter object type.  Expected '" + parameterClass.getName()
                            + "' but found '" + newParam.getClass().getName() + "'.");
                }
            }
        }
        return newParam;
    }

    private Document stringToDocument(String s) {
        try {
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
            return documentBuilder.parse(new ReaderInputStream(new StringReader(s)));
        } catch (Exception e) {
            throw new RuntimeException("Error occurred.  Cause: " + e, e);
        }
    }

    public String getId() {
        return id;
    }

    public Integer getResultSetType() {
        return resultSetType;
    }

    public void setResultSetType(Integer resultSetType) {
        this.resultSetType = resultSetType;
    }

    public Integer getFetchSize() {
        return fetchSize;
    }

    public void setFetchSize(Integer fetchSize) {
        this.fetchSize = fetchSize;
    }

    public void setId(String id) {
        this.id = id;
    }

    public Sql getSql() {
        return sql;
    }

    public void setSql(Sql sql) {
        this.sql = sql;
    }

    public ResultMap getResultMap() {
        return resultMap;
    }

    public void setResultMap(ResultMap resultMap) {
        this.resultMap = resultMap;
    }

    public ParameterMap getParameterMap() {
        return parameterMap;
    }

    public void setParameterMap(ParameterMap parameterMap) {
        this.parameterMap = parameterMap;
    }

    public Class getParameterClass() {
        return parameterClass;
    }

    public void setParameterClass(Class parameterClass) {
        this.parameterClass = parameterClass;
    }

    public String getResource() {
        return resource;
    }

    public void setResource(String resource) {
        this.resource = resource;
    }

    public CacheKey getCacheKey(StatementScope statementScope, Object parameterObject) {
        Sql sql = statementScope.getSql();
        ParameterMap pmap = sql.getParameterMap(statementScope, parameterObject);
        CacheKey cacheKey = pmap.getCacheKey(statementScope, parameterObject);
        cacheKey.update(id);
        cacheKey.update(baseCacheKey);
        cacheKey.update(sql.getSql(statementScope, parameterObject)); //Fixes bug 953001
        return cacheKey;
    }

    public void setBaseCacheKey(int base) {
        this.baseCacheKey = base;
    }

    public void addExecuteListener(ExecuteListener listener) {
        executeListeners.add(listener);
    }

    public void notifyListeners() {
        for (int i = 0, n = executeListeners.size(); i < n; i++) {
            ((ExecuteListener) executeListeners.get(i)).onExecuteStatement(this);
        }
    }

    public SqlExecutor getSqlExecutor() {
        return sqlMapClient.getSqlExecutor();
    }

    public SqlMapClient getSqlMapClient() {
        return sqlMapClient;
    }

    public void setSqlMapClient(SqlMapClient sqlMapClient) {
        this.sqlMapClient = (SqlMapClientImpl) sqlMapClient;
    }

    public void initRequest(StatementScope statementScope) {
        statementScope.setStatement(this);
        statementScope.setParameterMap(parameterMap);
        statementScope.setResultMap(resultMap);
        statementScope.setSql(sql);
    }

    public Integer getTimeout() {
        return timeout;
    }

    public void setTimeout(Integer timeout) {
        this.timeout = timeout;
    }

    public void addResultMap(ResultMap resultMap) {
        List resultMapList = Arrays.asList(additionalResultMaps);
        resultMapList = new ArrayList(resultMapList);
        resultMapList.add(resultMap);
        additionalResultMaps = (ResultMap[]) resultMapList.toArray(new ResultMap[resultMapList.size()]);
    }

    public boolean hasMultipleResultMaps() {
        return additionalResultMaps.length > 0;
    }

    public ResultMap[] getAdditionalResultMaps() {
        return additionalResultMaps;
    }

}