All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.milyn.routing.db.StatementExec Maven / Gradle / Ivy

There is a newer version: 1.7.1
Show newest version
/*
	Milyn - Copyright (C) 2006 - 2010

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License (version 2.1) as published by the Free Software
	Foundation.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

	See the GNU Lesser General Public License for more details:
	http://www.gnu.org/licenses/lgpl.txt
*/
package org.milyn.routing.db;

import org.milyn.assertion.AssertArgument;
import org.milyn.cdr.SmooksConfigurationException;
import org.milyn.util.DollarBraceDecoder;
import org.milyn.util.MVELTemplate;
import org.milyn.xml.XmlUtil;
import org.milyn.javabean.expression.BeanMapExpressionEvaluator;

import java.sql.*;
import java.util.*;

/**
 * SQL Statement Executor.
 *
 * @author [email protected]
 */
public class StatementExec {

    private String statement;
    private StatementType statementType;
    private boolean isJoin;
    private List statementExpressionEvaluators = new ArrayList();
    private MVELTemplate updateStatementTemplate;

    public StatementExec(String statementString) throws SmooksConfigurationException {
        AssertArgument.isNotNull(statementString, "statementString");

        statement = XmlUtil.removeEntities(statementString).trim();
        if (statement.toLowerCase().startsWith("select")) {
            statementType = StatementType.QUERY;
        } else {
            statementType = StatementType.UPDATE;
            updateStatementTemplate = new MVELTemplate(statement);
        }

        // The input payload can be a List (result set)and the statement can look
        // like "select * from ORDER_DETAIL_SOURCE where ORD_ID = ${ORD_ID} and ORD_CD = ${ORD_CD}",
        // where the ${} tokens denote one or more field/column names in the payload List rows. These
        // tokens will be used to extract values from the input rows (Map) to populate the PreparedStatment.
        List statementExecFields = DollarBraceDecoder.getTokens(statement);
        intitialiseStatementExpressions(statementExecFields);
        statement = DollarBraceDecoder.replaceTokens(statement, "?");
        isJoin = !statementExecFields.isEmpty();
    }

    private void intitialiseStatementExpressions(List statementExecFields) {
        for (String statementExecField : statementExecFields) {
            BeanMapExpressionEvaluator expression = new BeanMapExpressionEvaluator();
            expression.setExpression(statementExecField);
            statementExpressionEvaluators.add(expression);
        }
    }

    public String getStatement() {
        return statement;
    }

    public StatementType getStatementType() {
        return statementType;
    }

    public boolean isJoin() {
        return isJoin;
    }

    public List> executeUnjoinedQuery(Connection dbConnection, Object... params) throws SQLException {
        return executeUnjoinedQuery(dbConnection, Arrays.asList(params));
    }

    public List> executeUnjoinedQuery(Connection dbConnection, List params) throws SQLException {
        PreparedStatement preparedStatement = dbConnection.prepareStatement(statement);

        try {
            ResultSet resultSet;

            // initialise and execute the query...
            for (int i = 0; params != null && i < params.size(); i++) {
                preparedStatement.setObject((i + 1), params.get(i));
            }

            resultSet = preparedStatement.executeQuery();
            try {
                List> resultMap = new ArrayList>();
                mapResultSet(resultSet, resultMap);
                return resultMap;
            } finally {
                resultSet.close();
            }
        } finally {
            preparedStatement.close();
        }
    }

    public int executeUnjoinedUpdate(Connection dbConnection, Object... params) throws SQLException {
        return executeUnjoinedUpdate(dbConnection, Arrays.asList(params));
    }

    public int executeUnjoinedUpdate(Connection dbConnection, List params) throws SQLException {
        PreparedStatement preparedStatement = dbConnection.prepareStatement(statement);

        try {
            // initialise and execute the statement...
            for (int i = 0; params != null && i < params.size(); i++) {
                preparedStatement.setObject((i + 1), params.get(i));
            }
            return preparedStatement.executeUpdate();
        } finally {
            preparedStatement.close();
        }
    }

    public void executeJoinedStatement(Connection dbConnection, List> resultSet) throws SQLException {
        for (Map row : resultSet) {
            executeJoinedStatement(dbConnection, row);
        }
    }

    public void executeJoinedStatement(Connection dbConnection, Map beanMap) throws SQLException {
        if (getStatementType() == StatementType.QUERY) {
            executeJoinedQuery(dbConnection, beanMap);
        } else {
            executeJoinedUpdate(dbConnection, beanMap);
        }
    }

    public void executeJoinedQuery(Connection dbConnection, Map beanMap) throws SQLException {
        executeJoinedQuery(dbConnection, beanMap, null);
    }

    public void executeJoinedQuery(Connection dbConnection, Map beanMap, List> resultMap) throws SQLException {
        PreparedStatement preparedStatement = dbConnection.prepareStatement(statement);
        try {
            ResultSet resultSet;
            // initialise and execute the query...
            setStatementParamaters(preparedStatement, beanMap);
            resultSet = preparedStatement.executeQuery();

            try {
                if (resultMap == null) {
                    if (resultSet.next()) {
                        mapResultSetRowToMap(resultSet, beanMap);
                    }
                } else {
                    mapResultSet(resultSet, resultMap);
                }
            } finally {
                resultSet.close();
            }
        } finally {
            preparedStatement.close();
        }
    }

    public int executeJoinedUpdate(Connection dbConnection, Map beanMap) throws SQLException {
        PreparedStatement preparedStatement = dbConnection.prepareStatement(statement);
        try {
            // initialise and execute the query...
            setStatementParamaters(preparedStatement, beanMap);
            return preparedStatement.executeUpdate();
        } finally {
            preparedStatement.close();
        }
    }

    private void setStatementParamaters(PreparedStatement preparedStatement, Map beanMap) throws SQLException {
        // The query params are coming from other fields in
        // the row (the "join fields")...
        for (int i = 0; i < statementExpressionEvaluators.size(); i++) {
            Object value;
            try {
                value = statementExpressionEvaluators.get(i).getValue(beanMap);
            } catch(Throwable t) {
                SQLException e =  new SQLException("Error evaluting expression '" + statementExpressionEvaluators.get(i).getExpression() + "' on map " + beanMap);
                e.initCause(t);
                throw e;
            }
            preparedStatement.setObject((i + 1), value);
        }
    }

    public String getUpdateStatement(Map beanMap) {
        if (updateStatementTemplate == null) {
            throw new RuntimeException("Illegal call to getUpdateStatement().  This is not an 'update' statement.");
        }
        return updateStatementTemplate.apply(beanMap);
    }

    private void mapResultSet(ResultSet resultSet, List> resultMap) throws SQLException {
        while (resultSet.next()) {
            Map row = new LinkedHashMap();

            mapResultSetRowToMap(resultSet, row);
            resultMap.add(row);
        }
    }

    private void mapResultSetRowToMap(ResultSet resultSet, Map beanMap) throws SQLException {
        ResultSetMetaData resultSetMD = resultSet.getMetaData();
        int columnCount = resultSetMD.getColumnCount();

        for (int i = 0; i < columnCount; i++) {
            String colName = resultSetMD.getColumnName(i + 1);
            Object rowValue = resultSet.getObject(i + 1);
            beanMap.put(colName, rowValue);
        }
    }

}