JdbcTemplate.java :  » Database-Client » LiquiBase » liquibase » database » template » Java Open Source

Java Open Source » Database Client » LiquiBase 
LiquiBase » liquibase » database » template » JdbcTemplate.java
package liquibase.database.template;

import liquibase.database.Database;
import liquibase.database.DatabaseConnection;
import liquibase.database.sql.CallableSqlStatement;
import liquibase.database.sql.SqlStatement;
import liquibase.exception.JDBCException;
import liquibase.log.LogFactory;
import liquibase.util.JdbcUtils;

import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Class to simplify execution of SqlStatements.  Based heavily on <a href="http://static.springframework.org/spring/docs/2.0.x/reference/jdbc.html">Spring's JdbcTemplate</a>.
 * <br><br>
 * <b>Note: This class is currently intended for LiquiBase-internal use only and may change without notice in the future</b>
 */
@SuppressWarnings({"unchecked"})
public class JdbcTemplate {

    protected Database database;

    public JdbcTemplate(Database database) {
        this.database = database;
    }

    public boolean executesStatements() {
        return true;
    }
    
    //-------------------------------------------------------------------------
    // Methods dealing with static SQL (java.sql.Statement)
    //-------------------------------------------------------------------------

    public Object execute(StatementCallback action) throws JDBCException {
        DatabaseConnection con = database.getConnection();
        Statement stmt = null;
        try {
            stmt = con.createStatement();
            Statement stmtToUse = stmt;

            return action.doInStatement(stmtToUse);
        }
        catch (SQLException ex) {
            // Release Connection early, to avoid potential connection pool deadlock
            // in the case when the exception translator hasn't been initialized yet.
            JdbcUtils.closeStatement(stmt);
            stmt = null;
            throw new JDBCException("Error executing SQL " + action.getStatement().getSqlStatement(database), ex);
        }
        finally {
            JdbcUtils.closeStatement(stmt);
        }
    }

    public void execute(final SqlStatement sql) throws JDBCException {
        if (sql instanceof CallableSqlStatement) {
            call(((CallableSqlStatement) sql), new ArrayList());
            return;
        }


        class ExecuteStatementCallback implements StatementCallback {
            public Object doInStatement(Statement stmt) throws SQLException, JDBCException {
                stmt.execute(sql.getSqlStatement(database));
                return null;
            }

            public SqlStatement getStatement() {
                return sql;
            }
        }
        execute(new ExecuteStatementCallback());
    }

    public Object query(final SqlStatement sql, final ResultSetExtractor rse) throws JDBCException {
        if (sql instanceof CallableSqlStatement) {
            throw new JDBCException("Direct query using CallableSqlStatement not currently implemented");
        }

        class QueryStatementCallback implements StatementCallback {
            public Object doInStatement(Statement stmt) throws SQLException, JDBCException {
                ResultSet rs = null;
                try {
                    rs = stmt.executeQuery(sql.getSqlStatement(database));
                    ResultSet rsToUse = rs;
                    return rse.extractData(rsToUse);
                }
                finally {
                    JdbcUtils.closeResultSet(rs);
                }
            }


            public SqlStatement getStatement() {
                return sql;
            }
        }
        return execute(new QueryStatementCallback());
    }

    public List query(SqlStatement sql, RowMapper rowMapper) throws JDBCException {
        return (List) query(sql, new RowMapperResultSetExtractor(rowMapper));
    }

    public Object queryForObject(SqlStatement sql, RowMapper rowMapper) throws JDBCException {
        List results = query(sql, rowMapper);
        return JdbcUtils.requiredSingleResult(results);
    }

    public Object queryForObject(SqlStatement sql, Class requiredType) throws JDBCException {
        return queryForObject(sql, getSingleColumnRowMapper(requiredType));
    }

    public long queryForLong(SqlStatement sql) throws JDBCException {
        Number number = (Number) queryForObject(sql, Long.class);
        return (number != null ? number.longValue() : 0);
    }

    public int queryForInt(SqlStatement sql) throws JDBCException {
        Number number = (Number) queryForObject(sql, Integer.class);
        return (number != null ? number.intValue() : 0);
    }

    public List queryForList(SqlStatement sql, Class elementType) throws JDBCException {
        return query(sql, getSingleColumnRowMapper(elementType));
    }

    public List<Map> queryForList(SqlStatement sql) throws JDBCException {
        //noinspection unchecked
        return (List<Map>) query(sql, getColumnMapRowMapper());
    }

    public int update(final SqlStatement sql) throws JDBCException {
        if (sql instanceof CallableSqlStatement) {
            throw new JDBCException("Direct update using CallableSqlStatement not currently implemented");
        }

        class UpdateStatementCallback implements StatementCallback {
            public Object doInStatement(Statement stmt) throws SQLException, JDBCException {
                return stmt.executeUpdate(sql.getSqlStatement(database));
            }


            public SqlStatement getStatement() {
                return sql;
            }
        }
        return (Integer) execute(new UpdateStatementCallback());
    }
    //-------------------------------------------------------------------------
    // Methods dealing with callable statements
    //-------------------------------------------------------------------------

    public Object execute(CallableSqlStatement csc, CallableStatementCallback action) throws JDBCException {
        CallableStatement cs = null;
        try {
            cs = csc.createCallableStatement(database);
            CallableStatement csToUse = cs;
            return action.doInCallableStatement(csToUse);
        }
        catch (SQLException ex) {
            throw new JDBCException("Error executing callable statement", ex);
        }
        finally {
            JdbcUtils.closeStatement(cs);
        }

    }

    public Map call(CallableSqlStatement csc, final List declaredParameters) throws JDBCException {
        return (Map) execute(csc, new CallableStatementCallback() {
            public Object doInCallableStatement(CallableStatement cs) throws SQLException {
                //not currently doing anything with returned results
//                boolean retVal = cs.execute();
//                int updateCount = cs.getUpdateCount();
//                Map returnedResults = new HashMap();
//                if (retVal || updateCount != -1) {
//                    returnedResults.putAll(extractReturnedResultSets(cs, declaredParameters, updateCount));
//                }
//                returnedResults.putAll(extractOutputParameters(cs, declaredParameters));
                cs.execute();
                return new HashMap();
            }
        });
    }

    /**
     * Create a new RowMapper for reading columns as key-value pairs.
     *
     * @return the RowMapper to use
     * @see ColumnMapRowMapper
     */
    protected RowMapper getColumnMapRowMapper() {
        return new ColumnMapRowMapper();
    }

    /**
     * Create a new RowMapper for reading result objects from a single column.
     *
     * @param requiredType the type that each result object is expected to match
     * @return the RowMapper to use
     * @see SingleColumnRowMapper
     */
    protected RowMapper getSingleColumnRowMapper(Class requiredType) {
        return new SingleColumnRowMapper(requiredType);
    }

    /**
     * Adds a comment to the database.  Currently does nothing but is over-ridden in the output JDBC template
     * @param message
     * @throws JDBCException
     */
    public void comment(String message) throws JDBCException {
        LogFactory.getLogger().info(message);
    }

    /**
     * Adapter to enable use of a RowCallbackHandler inside a ResultSetExtractor.
     * <p>Uses a regular ResultSet, so we have to be careful when using it:
     * We don't use it for navigating since this could lead to unpredictable consequences.
     */
    private static class RowCallbackHandlerResultSetExtractor implements ResultSetExtractor {

        private final RowCallbackHandler rch;

        public RowCallbackHandlerResultSetExtractor(RowCallbackHandler rch) {
            this.rch = rch;
        }

        public Object extractData(ResultSet rs) throws SQLException {
            while (rs.next()) {
                this.rch.processRow(rs);
            }
            return null;
        }
    }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.