commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bay...@apache.org
Subject svn commit: r1158109 - in /commons/proper/dbutils/trunk/src: java/org/apache/commons/dbutils/ test/org/apache/commons/dbutils/
Date Tue, 16 Aug 2011 05:50:20 GMT
Author: bayard
Date: Tue Aug 16 05:50:19 2011
New Revision: 1158109

URL: http://svn.apache.org/viewvc?rev=1158109&view=rev
Log:
Creating an Abstract class for QueryRunner and AsyncQueryRunner. Also moving AsyncQueryRunner to a Callable rather than RunnableFuture API. Supplied by William Speirs in DBUTILS-78

Added:
    commons/proper/dbutils/trunk/src/java/org/apache/commons/dbutils/AbstractQueryRunner.java   (with props)
Modified:
    commons/proper/dbutils/trunk/src/java/org/apache/commons/dbutils/AsyncQueryRunner.java
    commons/proper/dbutils/trunk/src/java/org/apache/commons/dbutils/QueryRunner.java
    commons/proper/dbutils/trunk/src/test/org/apache/commons/dbutils/AsyncQueryRunnerTest.java

Added: commons/proper/dbutils/trunk/src/java/org/apache/commons/dbutils/AbstractQueryRunner.java
URL: http://svn.apache.org/viewvc/commons/proper/dbutils/trunk/src/java/org/apache/commons/dbutils/AbstractQueryRunner.java?rev=1158109&view=auto
==============================================================================
--- commons/proper/dbutils/trunk/src/java/org/apache/commons/dbutils/AbstractQueryRunner.java (added)
+++ commons/proper/dbutils/trunk/src/java/org/apache/commons/dbutils/AbstractQueryRunner.java Tue Aug 16 05:50:19 2011
@@ -0,0 +1,376 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.commons.dbutils;
+
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.sql.Connection;
+import java.sql.ParameterMetaData;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.sql.Types;
+import java.util.Arrays;
+
+import javax.sql.DataSource;
+
+/**
+ * The base class for QueryRunner & AsyncQueryRunner. 
+ * This class is thread safe.
+ */
+public abstract class AbstractQueryRunner {
+    /**
+     * Is {@link ParameterMetaData#getParameterType(int)} broken (have we tried it yet)?
+     */
+    protected volatile boolean pmdKnownBroken = false;
+    
+    /**
+     * The DataSource to retrieve connections from.
+     */
+    protected final DataSource ds;
+
+    /**
+     * Default constructor, sets pmdKnownBroken to false and ds to null.
+     */
+    public AbstractQueryRunner() {
+        ds = null;
+    }
+
+    /**
+     * Constructor to allow workaround for Oracle drivers
+     * @param pmdKnownBroken Oracle drivers don't support {@link ParameterMetaData#getParameterType(int) };
+     * if <code>pmdKnownBroken</code> is set to true, we won't even try it; if false, we'll try it,
+     * and if it breaks, we'll remember not to use it again.
+     */
+    public AbstractQueryRunner(boolean pmdKnownBroken) {
+        this.pmdKnownBroken = pmdKnownBroken; 
+        ds = null;
+    }
+    
+    /**
+     * Constructor to provide a <code>DataSource</code>.
+     * Methods that do not take a <code>Connection</code> parameter will
+     * retrieve connections from this <code>DataSource</code>.
+     * 
+     * @param ds The <code>DataSource</code> to retrieve connections from.
+     */
+    public AbstractQueryRunner(DataSource ds) {
+        this.ds = ds;
+    }
+    
+    /**
+     * Constructor to allow workaround for Oracle drivers.  Methods that do not take a 
+     * <code>Connection</code> parameter will retrieve connections from this
+     * <code>DataSource</code>.
+     * 
+     * @param ds The <code>DataSource</code> to retrieve connections from.
+     * @param pmdKnownBroken Oracle drivers don't support {@link ParameterMetaData#getParameterType(int) };
+     * if <code>pmdKnownBroken</code> is set to true, we won't even try it; if false, we'll try it,
+     * and if it breaks, we'll remember not to use it again.
+     */
+    public AbstractQueryRunner(DataSource ds, boolean pmdKnownBroken) {
+        this.pmdKnownBroken = pmdKnownBroken;
+        this.ds = ds;
+    }
+
+    /**
+     * Returns the <code>DataSource</code> this runner is using.  
+     * <code>QueryRunner</code> methods always call this method to get the
+     * <code>DataSource</code> so subclasses can provide specialized
+     * behavior.
+     *
+     * @return DataSource the runner is using
+     */
+    public DataSource getDataSource() {
+        return this.ds;
+    }
+
+
+    /**
+     * Factory method that creates and initializes a 
+     * <code>PreparedStatement</code> object for the given SQL.  
+     * <code>QueryRunner</code> methods always call this method to prepare 
+     * statements for them.  Subclasses can override this method to provide 
+     * special PreparedStatement configuration if needed.  This implementation
+     * simply calls <code>conn.prepareStatement(sql)</code>.
+     *  
+     * @param conn The <code>Connection</code> used to create the 
+     * <code>PreparedStatement</code>
+     * @param sql The SQL statement to prepare.
+     * @return An initialized <code>PreparedStatement</code>.
+     * @throws SQLException if a database access error occurs
+     */
+    protected PreparedStatement prepareStatement(Connection conn, String sql)
+        throws SQLException {
+            
+        return conn.prepareStatement(sql);
+    }
+    
+    /**
+     * Factory method that creates and initializes a 
+     * <code>Connection</code> object.  <code>QueryRunner</code> methods 
+     * always call this method to retrieve connections from its DataSource.  
+     * Subclasses can override this method to provide 
+     * special <code>Connection</code> configuration if needed.  This 
+     * implementation simply calls <code>ds.getConnection()</code>.
+     * 
+     * @return An initialized <code>Connection</code>.
+     * @throws SQLException if a database access error occurs
+     * @since DbUtils 1.1
+     */
+    protected Connection prepareConnection() throws SQLException {
+        if(this.getDataSource() == null) {
+            throw new SQLException("QueryRunner requires a DataSource to be " +
+                "invoked in this way, or a Connection should be passed in");
+        }
+        return this.getDataSource().getConnection();
+    }
+
+    /**
+     * Fill the <code>PreparedStatement</code> replacement parameters with 
+     * the given objects.
+     * @param stmt PreparedStatement to fill
+     * @param params Query replacement parameters; <code>null</code> is a valid
+     * value to pass in.
+     * @throws SQLException if a database access error occurs
+     */
+    public void fillStatement(PreparedStatement stmt, Object... params) throws SQLException {
+
+        // check the parameter count, if we can
+        ParameterMetaData pmd = null;
+        if (!pmdKnownBroken) {
+            pmd = stmt.getParameterMetaData();
+            int stmtCount = pmd.getParameterCount();
+            int paramsCount = params == null ? 0 : params.length;
+            
+            if (stmtCount != paramsCount) {
+                throw new SQLException("Wrong number of parameters: expected "
+                        + stmtCount + ", was given " + paramsCount);
+            }
+        }
+
+        // nothing to do here
+        if (params == null) {
+            return;
+        }
+
+        for (int i = 0; i < params.length; i++) {
+            if (params[i] != null) {
+                stmt.setObject(i + 1, params[i]);
+            } else {
+                // VARCHAR works with many drivers regardless
+                // of the actual column type.  Oddly, NULL and 
+                // OTHER don't work with Oracle's drivers.
+                int sqlType = Types.VARCHAR;
+                if (!pmdKnownBroken) {
+                    try {
+                        sqlType = pmd.getParameterType(i + 1);
+                    } catch (SQLException e) {
+                        pmdKnownBroken = true;
+                    }
+                }
+                stmt.setNull(i + 1, sqlType);
+            }
+        }
+    }
+
+    /**
+     * Fill the <code>PreparedStatement</code> replacement parameters with the
+     * given object's bean property values.
+     * 
+     * @param stmt
+     *            PreparedStatement to fill
+     * @param bean
+     *            a JavaBean object
+     * @param properties
+     *            an ordered array of properties; this gives the order to insert
+     *            values in the statement
+     * @throws SQLException
+     *             if a database access error occurs
+     */
+    public void fillStatementWithBean(PreparedStatement stmt, Object bean,
+            PropertyDescriptor[] properties) throws SQLException {
+        Object[] params = new Object[properties.length];
+        for (int i = 0; i < properties.length; i++) {
+            PropertyDescriptor property = properties[i];
+            Object value = null;
+            Method method = property.getReadMethod();
+            if (method == null) {
+                throw new RuntimeException("No read method for bean property "
+                        + bean.getClass() + " " + property.getName());
+            }
+            try {
+                value = method.invoke(bean, new Object[0]);
+            } catch (InvocationTargetException e) {
+                throw new RuntimeException("Couldn't invoke method: " + method, e);
+            } catch (IllegalArgumentException e) {
+                throw new RuntimeException("Couldn't invoke method with 0 arguments: " + method, e);
+            } catch (IllegalAccessException e) {
+                throw new RuntimeException("Couldn't invoke method: " + method, e);
+            } 
+            params[i] = value;
+        }
+        fillStatement(stmt, params);
+    }
+
+    /**
+     * Fill the <code>PreparedStatement</code> replacement parameters with the
+     * given object's bean property values.
+     * 
+     * @param stmt PreparedStatement to fill
+     * @param bean A JavaBean object
+     * @param propertyNames An ordered array of property names (these should match the
+     *                      getters/setters); this gives the order to insert values in the
+     *                      statement
+     * @throws SQLException If a database access error occurs
+     */
+    public void fillStatementWithBean(PreparedStatement stmt, Object bean, String... propertyNames) throws SQLException {
+        PropertyDescriptor[] descriptors;
+        try {
+            descriptors = Introspector.getBeanInfo(bean.getClass())
+                    .getPropertyDescriptors();
+        } catch (IntrospectionException e) {
+            throw new RuntimeException("Couldn't introspect bean " + bean.getClass().toString(), e);
+        }
+        PropertyDescriptor[] sorted = new PropertyDescriptor[propertyNames.length];
+        for (int i = 0; i < propertyNames.length; i++) {
+            String propertyName = propertyNames[i];
+            if (propertyName == null) {
+                throw new NullPointerException("propertyName can't be null: " + i);
+            }
+            boolean found = false;
+            for (int j = 0; j < descriptors.length; j++) {
+                PropertyDescriptor descriptor = descriptors[j];
+                if (propertyName.equals(descriptor.getName())) {
+                    sorted[i] = descriptor;
+                    found = true;
+                    break;
+                }
+            }
+            if (!found) {
+                throw new RuntimeException("Couldn't find bean property: "
+                        + bean.getClass() + " " + propertyName);
+            }
+        }
+        fillStatementWithBean(stmt, bean, sorted);
+    }
+
+    /**
+     * Throws a new exception with a more informative error message.
+     * 
+     * @param cause The original exception that will be chained to the new 
+     * exception when it's rethrown. 
+     * 
+     * @param sql The query that was executing when the exception happened.
+     * 
+     * @param params The query replacement parameters; <code>null</code> is a 
+     * valid value to pass in.
+     * 
+     * @throws SQLException if a database access error occurs
+     */
+    protected void rethrow(SQLException cause, String sql, Object... params)
+        throws SQLException {
+
+        String causeMessage = cause.getMessage();
+        if (causeMessage == null) {
+            causeMessage = "";
+        }
+        StringBuffer msg = new StringBuffer(causeMessage);
+
+        msg.append(" Query: ");
+        msg.append(sql);
+        msg.append(" Parameters: ");
+
+        if (params == null) {
+            msg.append("[]");
+        } else {
+            msg.append(Arrays.deepToString(params));
+        }
+
+        SQLException e = new SQLException(msg.toString(), cause.getSQLState(),
+                cause.getErrorCode());
+        e.setNextException(cause);
+
+        throw e;
+    }
+
+    /**
+     * Wrap the <code>ResultSet</code> in a decorator before processing it.
+     * This implementation returns the <code>ResultSet</code> it is given
+     * without any decoration.
+     *
+     * <p>
+     * Often, the implementation of this method can be done in an anonymous 
+     * inner class like this:
+     * </p>
+     * <pre> 
+     * QueryRunner run = new QueryRunner() {
+     *     protected ResultSet wrap(ResultSet rs) {
+     *         return StringTrimmedResultSet.wrap(rs);
+     *     }
+     * };
+     * </pre>
+     * 
+     * @param rs The <code>ResultSet</code> to decorate; never 
+     * <code>null</code>.
+     * @return The <code>ResultSet</code> wrapped in some decorator. 
+     */
+    protected ResultSet wrap(ResultSet rs) {
+        return rs;
+    }
+    
+    /**
+     * Close a <code>Connection</code>.  This implementation avoids closing if 
+     * null and does <strong>not</strong> suppress any exceptions.  Subclasses
+     * can override to provide special handling like logging.
+     * @param conn Connection to close
+     * @throws SQLException if a database access error occurs
+     * @since DbUtils 1.1
+     */
+    protected void close(Connection conn) throws SQLException {
+        DbUtils.close(conn);
+    }
+    
+    /**
+     * Close a <code>Statement</code>.  This implementation avoids closing if 
+     * null and does <strong>not</strong> suppress any exceptions.  Subclasses
+     * can override to provide special handling like logging.
+     * @param stmt Statement to close
+     * @throws SQLException if a database access error occurs
+     * @since DbUtils 1.1
+     */
+    protected void close(Statement stmt) throws SQLException {
+        DbUtils.close(stmt);
+    }
+
+    /**
+     * Close a <code>ResultSet</code>.  This implementation avoids closing if 
+     * null and does <strong>not</strong> suppress any exceptions.  Subclasses
+     * can override to provide special handling like logging.
+     * @param rs ResultSet to close
+     * @throws SQLException if a database access error occurs
+     * @since DbUtils 1.1
+     */
+    protected void close(ResultSet rs) throws SQLException {
+        DbUtils.close(rs);
+    }
+
+}

Propchange: commons/proper/dbutils/trunk/src/java/org/apache/commons/dbutils/AbstractQueryRunner.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: commons/proper/dbutils/trunk/src/java/org/apache/commons/dbutils/AsyncQueryRunner.java
URL: http://svn.apache.org/viewvc/commons/proper/dbutils/trunk/src/java/org/apache/commons/dbutils/AsyncQueryRunner.java?rev=1158109&r1=1158108&r2=1158109&view=diff
==============================================================================
--- commons/proper/dbutils/trunk/src/java/org/apache/commons/dbutils/AsyncQueryRunner.java (original)
+++ commons/proper/dbutils/trunk/src/java/org/apache/commons/dbutils/AsyncQueryRunner.java Tue Aug 16 05:50:19 2011
@@ -16,22 +16,12 @@
  */
 package org.apache.commons.dbutils;
 
-import java.beans.IntrospectionException;
-import java.beans.Introspector;
-import java.beans.PropertyDescriptor;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
 import java.sql.Connection;
 import java.sql.ParameterMetaData;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
-import java.sql.Statement;
-import java.sql.Types;
-import java.util.Arrays;
 import java.util.concurrent.Callable;
-import java.util.concurrent.FutureTask;
-import java.util.concurrent.RunnableFuture;
 
 import javax.sql.DataSource;
 
@@ -42,44 +32,34 @@ import javax.sql.DataSource;
  * @see ResultSetHandler
  * @since 1.4
  */
-public class AsyncQueryRunner {
+public class AsyncQueryRunner extends AbstractQueryRunner {
 
     /**
-     * Is {@link ParameterMetaData#getParameterType(int)} broken (have we tried it yet)?
-     */
-    private volatile boolean pmdKnownBroken = false;
-    
-    /**
-     * The DataSource to retrieve connections from.
-     */
-    protected final DataSource ds;
-
-    /**
-     * Constructor for QueryRunner.
+     * Constructor for AsyncQueryRunner.
      */
     public AsyncQueryRunner() {
-        this(null, false); 
+        super(null, false); 
     }
 
     /**
-     * Constructor for QueryRunner, allows workaround for Oracle drivers
+     * Constructor for AsyncQueryRunner, allows workaround for Oracle drivers
      * @param pmdKnownBroken Oracle drivers don't support {@link ParameterMetaData#getParameterType(int) };
      * if <code>pmdKnownBroken</code> is set to true, we won't even try it; if false, we'll try it,
      * and if it breaks, we'll remember not to use it again.
      */
     public AsyncQueryRunner(boolean pmdKnownBroken) {
-        this(null, pmdKnownBroken); 
+        super(null, pmdKnownBroken); 
     }
     
     /**
-     * Constructor for QueryRunner, allows workaround for Oracle drivers.  Methods that do not take a 
+     * Constructor for AsyncQueryRunner which takes a <code>DataSource</code>.  Methods that do not take a 
      * <code>Connection</code> parameter will retrieve connections from this
      * <code>DataSource</code>.
      * 
      * @param ds The <code>DataSource</code> to retrieve connections from.
      */
     public AsyncQueryRunner(DataSource ds) {
-        this(ds, false);
+        super(ds, false);
     }
     
     /**
@@ -93,10 +73,12 @@ public class AsyncQueryRunner {
      * and if it breaks, we'll remember not to use it again.
      */
     public AsyncQueryRunner(DataSource ds, boolean pmdKnownBroken) {
-        this.pmdKnownBroken = pmdKnownBroken;
-        this.ds = ds;
+        super(ds, pmdKnownBroken);
     }
     
+    /**
+     * Class that encapsulates the continuation for batch calls.
+     */
     protected class BatchCallableStatement implements Callable<int[]> {
     	private String sql;
     	private Object[][] params;
@@ -112,6 +94,9 @@ public class AsyncQueryRunner {
     		this.ps = ps;
     	}
 		
+    	/**
+    	 * The actual call to executeBatch.
+    	 */
     	public int[] call() throws Exception {
     		int[] ret = null;
     		
@@ -132,16 +117,16 @@ public class AsyncQueryRunner {
     /**
      * Execute a batch of SQL INSERT, UPDATE, or DELETE queries.
      * 
-     * @param conn The Connection to use to run the query.  The caller is
+     * @param conn The <code>Connection</code> to use to run the query.  The caller is
      * responsible for closing this Connection.
      * @param sql The SQL to execute.
      * @param params An array of query replacement parameters.  Each row in
      * this array is one set of batch replacement values. 
-     * @return A RunnableFuture which when completed returns the number of rows updated per statement.
+     * @return A <code>Callable</code> which returns the number of rows updated per statement.
      * @throws SQLException if a database access error occurs
      * @since DbUtils 1.1
      */
-    public RunnableFuture<int[]> batch(Connection conn, String sql, Object[][] params) throws SQLException {
+    public Callable<int[]> batch(Connection conn, String sql, Object[][] params) throws SQLException {
         return this.batch(conn, false, sql, params);
     }
 
@@ -154,17 +139,27 @@ public class AsyncQueryRunner {
      * @param sql The SQL to execute.
      * @param params An array of query replacement parameters.  Each row in
      * this array is one set of batch replacement values. 
-     * @return A RunnableFuture which when completed returns the number of rows updated per statement.
+     * @return A <code>Callable</code> which returns the number of rows updated per statement.
      * @throws SQLException if a database access error occurs
      * @since DbUtils 1.1
      */
-    public RunnableFuture<int[]> batch(String sql, Object[][] params) throws SQLException {
+    public Callable<int[]> batch(String sql, Object[][] params) throws SQLException {
         Connection conn = this.prepareConnection();
 
         return this.batch(conn, true, sql, params);
     }
     
-    private RunnableFuture<int[]> batch(Connection conn, boolean closeConn, String sql, Object[][] params) throws SQLException {
+    /**
+     * Creates a continuation for a batch call, and returns it in a <code>RunnableFuture</code>.
+     * @param conn The connection to use for the batch call.
+     * @param closeConn True if the connection should be closed, false otherwise.
+     * @param sql The SQL statement to execute.
+     * @param params An array of query replacement parameters.  Each row in
+     * this array is one set of batch replacement values. 
+     * @return A <code>Callable</code> which returns the number of rows updated per statement.
+     * @throws SQLException If there are database or parameter errors.
+     */
+    private Callable<int[]> batch(Connection conn, boolean closeConn, String sql, Object[][] params) throws SQLException {
     	if(conn == null) {
     		if(closeConn)
     			close(conn);
@@ -184,7 +179,7 @@ public class AsyncQueryRunner {
     	}
 
         PreparedStatement stmt = null;
-        FutureTask<int[]> ret = null;
+        Callable<int[]> ret = null;
         try {
         	stmt = this.prepareStatement(conn, sql);
         	
@@ -193,7 +188,7 @@ public class AsyncQueryRunner {
                 stmt.addBatch();
             }
             
-            ret = new FutureTask<int[]>(new BatchCallableStatement(sql, params, conn, closeConn, stmt));
+            ret = new BatchCallableStatement(sql, params, conn, closeConn, stmt);
 
         } catch (SQLException e) {
             close(stmt);
@@ -205,186 +200,9 @@ public class AsyncQueryRunner {
     }
 
     /**
-     * Fill the <code>PreparedStatement</code> replacement parameters with 
-     * the given objects.
-     * @param stmt PreparedStatement to fill
-     * @param params Query replacement parameters; <code>null</code> is a valid
-     * value to pass in.
-     * @throws SQLException if a database access error occurs
-     */
-    public void fillStatement(PreparedStatement stmt, Object... params) throws SQLException {
-
-        // check the parameter count, if we can
-        ParameterMetaData pmd = null;
-        if (!pmdKnownBroken) {
-            pmd = stmt.getParameterMetaData();
-            int stmtCount = pmd.getParameterCount();
-            int paramsCount = params == null ? 0 : params.length;
-            
-            if (stmtCount != paramsCount) {
-                throw new SQLException("Wrong number of parameters: expected "
-                        + stmtCount + ", was given " + paramsCount);
-            }
-        }
-
-        // nothing to do here
-        if (params == null) {
-            return;
-        }
-
-        for (int i = 0; i < params.length; i++) {
-            if (params[i] != null) {
-                stmt.setObject(i + 1, params[i]);
-            } else {
-                // VARCHAR works with many drivers regardless
-                // of the actual column type.  Oddly, NULL and 
-                // OTHER don't work with Oracle's drivers.
-                int sqlType = Types.VARCHAR;
-                if (!pmdKnownBroken) {
-                    try {
-                        sqlType = pmd.getParameterType(i + 1);
-                    } catch (SQLException e) {
-                        pmdKnownBroken = true;
-                    }
-                }
-                stmt.setNull(i + 1, sqlType);
-            }
-        }
-    }
-
-    /**
-     * Fill the <code>PreparedStatement</code> replacement parameters with the
-     * given object's bean property values.
-     * 
-     * @param stmt
-     *            PreparedStatement to fill
-     * @param bean
-     *            a JavaBean object
-     * @param properties
-     *            an ordered array of properties; this gives the order to insert
-     *            values in the statement
-     * @throws SQLException
-     *             if a database access error occurs
-     */
-    public void fillStatementWithBean(PreparedStatement stmt, Object bean,
-            PropertyDescriptor[] properties) throws SQLException {
-        Object[] params = new Object[properties.length];
-        for (int i = 0; i < properties.length; i++) {
-            PropertyDescriptor property = properties[i];
-            Object value = null;
-            Method method = property.getReadMethod();
-            if (method == null) {
-                throw new RuntimeException("No read method for bean property "
-                        + bean.getClass() + " " + property.getName());
-            }
-            try {
-                value = method.invoke(bean, new Object[0]);
-            } catch (InvocationTargetException e) {
-                throw new RuntimeException("Couldn't invoke method: " + method, e);
-            } catch (IllegalArgumentException e) {
-                throw new RuntimeException("Couldn't invoke method with 0 arguments: " + method, e);
-            } catch (IllegalAccessException e) {
-                throw new RuntimeException("Couldn't invoke method: " + method, e);
-            } 
-            params[i] = value;
-        }
-        fillStatement(stmt, params);
-    }
-
-    /**
-     * Fill the <code>PreparedStatement</code> replacement parameters with the
-     * given object's bean property values.
-     * 
-     * @param stmt PreparedStatement to fill
-     * @param bean A JavaBean object
-     * @param propertyNames An ordered array of property names (these should match the
-     *                      getters/setters); this gives the order to insert values in the
-     *                      statement
-     * @throws SQLException If a database access error occurs
-     */
-    public void fillStatementWithBean(PreparedStatement stmt, Object bean, String... propertyNames) throws SQLException {
-        PropertyDescriptor[] descriptors;
-        try {
-            descriptors = Introspector.getBeanInfo(bean.getClass())
-                    .getPropertyDescriptors();
-        } catch (IntrospectionException e) {
-            throw new RuntimeException("Couldn't introspect bean " + bean.getClass().toString(), e);
-        }
-        PropertyDescriptor[] sorted = new PropertyDescriptor[propertyNames.length];
-        for (int i = 0; i < propertyNames.length; i++) {
-            String propertyName = propertyNames[i];
-            if (propertyName == null) {
-                throw new NullPointerException("propertyName can't be null: " + i);
-            }
-            boolean found = false;
-            for (int j = 0; j < descriptors.length; j++) {
-                PropertyDescriptor descriptor = descriptors[j];
-                if (propertyName.equals(descriptor.getName())) {
-                    sorted[i] = descriptor;
-                    found = true;
-                    break;
-                }
-            }
-            if (!found) {
-                throw new RuntimeException("Couldn't find bean property: "
-                        + bean.getClass() + " " + propertyName);
-            }
-        }
-        fillStatementWithBean(stmt, bean, sorted);
-    }
-
-    /**
-     * Returns the <code>DataSource</code> this runner is using.  
-     * <code>QueryRunner</code> methods always call this method to get the
-     * <code>DataSource</code> so subclasses can provide specialized
-     * behavior.
-     *
-     * @return DataSource the runner is using
-     */
-    public DataSource getDataSource() {
-        return this.ds;
-    }
-
-    /**
-     * Factory method that creates and initializes a 
-     * <code>PreparedStatement</code> object for the given SQL.  
-     * <code>QueryRunner</code> methods always call this method to prepare 
-     * statements for them.  Subclasses can override this method to provide 
-     * special PreparedStatement configuration if needed.  This implementation
-     * simply calls <code>conn.prepareStatement(sql)</code>.
-     *  
-     * @param conn The <code>Connection</code> used to create the 
-     * <code>PreparedStatement</code>
-     * @param sql The SQL statement to prepare.
-     * @return An initialized <code>PreparedStatement</code>.
-     * @throws SQLException if a database access error occurs
-     */
-    protected PreparedStatement prepareStatement(Connection conn, String sql)
-        throws SQLException {
-            
-        return conn.prepareStatement(sql);
-    }
-    
-    /**
-     * Factory method that creates and initializes a 
-     * <code>Connection</code> object.  <code>QueryRunner</code> methods 
-     * always call this method to retrieve connections from its DataSource.  
-     * Subclasses can override this method to provide 
-     * special <code>Connection</code> configuration if needed.  This 
-     * implementation simply calls <code>ds.getConnection()</code>.
-     * 
-     * @return An initialized <code>Connection</code>.
-     * @throws SQLException if a database access error occurs
-     * @since DbUtils 1.1
+     * Class that encapsulates the continuation for query calls.
+     * @param <T> The type of the result from the call to handle.
      */
-    protected Connection prepareConnection() throws SQLException {
-        if(this.getDataSource() == null) {
-            throw new SQLException("QueryRunner requires a DataSource to be " +
-                "invoked in this way, or a Connection should be passed in");
-        }
-        return this.getDataSource().getConnection();
-    }
-    
     protected class QueryCallableStatement<T> implements Callable<T> {
     	private String sql;
     	private Object[] params;
@@ -426,9 +244,19 @@ public class AsyncQueryRunner {
     	
     }
 
-    private <T> RunnableFuture<T> query(Connection conn, boolean closeConn, String sql, ResultSetHandler<T> rsh, Object... params) throws SQLException {
+    /**
+     * Creates a continuation for a query call, and returns it in a <code>RunnableFuture</code>.
+     * @param conn The connection to use for the query call.
+     * @param closeConn True if the connection should be closed, false otherwise.
+     * @param sql The SQL statement to execute.
+     * @param params An array of query replacement parameters.  Each row in
+     * this array is one set of query replacement values. 
+     * @return A <code>Callable</code> which returns the result of the query call.
+     * @throws SQLException If there are database or parameter errors.
+     */
+    private <T> Callable<T> query(Connection conn, boolean closeConn, String sql, ResultSetHandler<T> rsh, Object... params) throws SQLException {
         PreparedStatement stmt = null;
-        FutureTask<T> ret = null;
+        Callable<T> ret = null;
 
     	if(conn == null) {
     		if(closeConn)
@@ -452,7 +280,7 @@ public class AsyncQueryRunner {
             stmt = this.prepareStatement(conn, sql);
             this.fillStatement(stmt, params);
             
-            ret = new FutureTask<T>(new QueryCallableStatement<T>(conn, closeConn, stmt, rsh, sql, params));
+            ret = new QueryCallableStatement<T>(conn, closeConn, stmt, rsh, sql, params);
 
         } catch (SQLException e) {
             close(stmt);
@@ -472,10 +300,10 @@ public class AsyncQueryRunner {
      * @param sql The query to execute.
      * @param rsh The handler that converts the results into an object.
      * @param params The replacement parameters.
-     * @return A RunnableFuture which when completed returns the object returned by the handler.
+     * @return A <code>Callable</code> which returns the result of the query call.
      * @throws SQLException if a database access error occurs
      */
-    public <T> RunnableFuture<T> query(Connection conn, String sql, ResultSetHandler<T> rsh, Object... params) throws SQLException {
+    public <T> Callable<T> query(Connection conn, String sql, ResultSetHandler<T> rsh, Object... params) throws SQLException {
     	return query(conn, false, sql, rsh, params);
     }
 
@@ -486,10 +314,10 @@ public class AsyncQueryRunner {
      * @param conn The connection to execute the query in.
      * @param sql The query to execute.
      * @param rsh The handler that converts the results into an object.
-     * @return A RunnableFuture which when completed returns the object returned by the handler.
+     * @return A <code>Callable</code> which returns the result of the query call.
      * @throws SQLException if a database access error occurs
      */
-    public <T> RunnableFuture<T> query(Connection conn, String sql, ResultSetHandler<T> rsh) throws SQLException {
+    public <T> Callable<T> query(Connection conn, String sql, ResultSetHandler<T> rsh) throws SQLException {
         return this.query(conn, false, sql, rsh, (Object[]) null);
     }
 
@@ -503,12 +331,11 @@ public class AsyncQueryRunner {
      * the <code>ResultSet</code>.
      * @param params Initialize the PreparedStatement's IN parameters with 
      * this array.
-     * @return A RunnableFuture which when completed returns the object generated by the handler.
+     * @return A <code>Callable</code> which returns the result of the query call.
      * @throws SQLException if a database access error occurs
      */
-    public <T> RunnableFuture<T> query(String sql, ResultSetHandler<T> rsh, Object... params) throws SQLException {
+    public <T> Callable<T> query(String sql, ResultSetHandler<T> rsh, Object... params) throws SQLException {
         Connection conn = this.prepareConnection();
-
         return this.query(conn, true, sql, rsh, params);
     }
 
@@ -521,53 +348,17 @@ public class AsyncQueryRunner {
      * @param rsh The handler used to create the result object from 
      * the <code>ResultSet</code>.
      * 
-     * @return A RunnableFuture which when completed returns the object generated by the handler.
+     * @return A <code>Callable</code> which returns the result of the query call.
      * @throws SQLException if a database access error occurs
      */
-    public <T> RunnableFuture<T> query(String sql, ResultSetHandler<T> rsh) throws SQLException {
+    public <T> Callable<T> query(String sql, ResultSetHandler<T> rsh) throws SQLException {
         Connection conn = this.prepareConnection();
         return this.query(conn, true, sql, rsh, (Object[]) null);
     }
 
     /**
-     * Throws a new exception with a more informative error message.
-     * 
-     * @param cause The original exception that will be chained to the new 
-     * exception when it's rethrown. 
-     * 
-     * @param sql The query that was executing when the exception happened.
-     * 
-     * @param params The query replacement parameters; <code>null</code> is a 
-     * valid value to pass in.
-     * 
-     * @throws SQLException if a database access error occurs
+     * Class that encapsulates the continuation for update calls.
      */
-    protected void rethrow(SQLException cause, String sql, Object... params)
-        throws SQLException {
-
-        String causeMessage = cause.getMessage();
-        if (causeMessage == null) {
-            causeMessage = "";
-        }
-        StringBuffer msg = new StringBuffer(causeMessage);
-
-        msg.append(" Query: ");
-        msg.append(sql);
-        msg.append(" Parameters: ");
-
-        if (params == null) {
-            msg.append("[]");
-        } else {
-            msg.append(Arrays.deepToString(params));
-        }
-
-        SQLException e = new SQLException(msg.toString(), cause.getSQLState(),
-                cause.getErrorCode());
-        e.setNextException(cause);
-
-        throw e;
-    }
-
     protected class UpdateCallableStatement implements Callable<Integer> {
     	private String sql;
     	private Object[] params;
@@ -601,9 +392,19 @@ public class AsyncQueryRunner {
     	
     }
     
-    private RunnableFuture<Integer> update(Connection conn, boolean closeConn, String sql, Object... params) throws SQLException {
+    /**
+     * Creates a continuation for an update call, and returns it in a <code>RunnableFuture</code>.
+     * @param conn The connection to use for the update call.
+     * @param closeConn True if the connection should be closed, false otherwise.
+     * @param sql The SQL statement to execute.
+     * @param params An array of update replacement parameters.  Each row in
+     * this array is one set of update replacement values. 
+     * @return A <code>Callable</code> which returns the number of rows updated.
+     * @throws SQLException If there are database or parameter errors.
+     */
+    private Callable<Integer> update(Connection conn, boolean closeConn, String sql, Object... params) throws SQLException {
         PreparedStatement stmt = null;
-        FutureTask<Integer> ret = null;
+        Callable<Integer> ret = null;
 
     	if(conn == null) {
     		if(closeConn)
@@ -621,7 +422,7 @@ public class AsyncQueryRunner {
             stmt = this.prepareStatement(conn, sql);
             this.fillStatement(stmt, params);
             
-            ret = new FutureTask<Integer>(new UpdateCallableStatement(conn, closeConn, stmt, sql, params));
+            ret = new UpdateCallableStatement(conn, closeConn, stmt, sql, params);
 
         } catch (SQLException e) {
         	close(stmt);
@@ -639,10 +440,10 @@ public class AsyncQueryRunner {
      * 
      * @param conn The connection to use to run the query.
      * @param sql The SQL to execute.
-     * @return A RunnableFuture which when completed returns the number of rows updated.
+     * @return A <code>Callable</code> which returns the number of rows updated.
      * @throws SQLException if a database access error occurs
      */
-    public RunnableFuture<Integer> update(Connection conn, String sql) throws SQLException {
+    public Callable<Integer> update(Connection conn, String sql) throws SQLException {
         return this.update(conn, false, sql, (Object[]) null);
     }
 
@@ -653,10 +454,10 @@ public class AsyncQueryRunner {
      * @param conn The connection to use to run the query.
      * @param sql The SQL to execute.
      * @param param The replacement parameter.
-     * @return A RunnableFuture which when completed returns the number of rows updated.
+     * @return A <code>Callable</code> which returns the number of rows updated.
      * @throws SQLException if a database access error occurs
      */
-    public RunnableFuture<Integer> update(Connection conn, String sql, Object param) throws SQLException {
+    public Callable<Integer> update(Connection conn, String sql, Object param) throws SQLException {
         return this.update(conn, false, sql, new Object[] { param });
     }
 
@@ -666,10 +467,10 @@ public class AsyncQueryRunner {
      * @param conn The connection to use to run the query.
      * @param sql The SQL to execute.
      * @param params The query replacement parameters.
-     * @return A RunnableFuture which when completed returns the number of rows updated.
+     * @return A <code>Callable</code> which returns the number of rows updated.
      * @throws SQLException if a database access error occurs
      */
-    public RunnableFuture<Integer> update(Connection conn, String sql, Object... params) throws SQLException {
+    public Callable<Integer> update(Connection conn, String sql, Object... params) throws SQLException {
     	return this.update(conn, false, sql, params);
     }
 
@@ -682,9 +483,9 @@ public class AsyncQueryRunner {
      * 
      * @param sql The SQL statement to execute.
      * @throws SQLException if a database access error occurs
-     * @return A RunnableFuture which when completed returns the number of rows updated.
+     * @return A <code>Callable</code> which returns the number of rows updated.
      */
-    public RunnableFuture<Integer> update(String sql) throws SQLException {
+    public Callable<Integer> update(String sql) throws SQLException {
         Connection conn = this.prepareConnection();
         return this.update(conn, true, sql, (Object[]) null);
     }
@@ -699,9 +500,9 @@ public class AsyncQueryRunner {
      * @param sql The SQL statement to execute.
      * @param param The replacement parameter.
      * @throws SQLException if a database access error occurs
-     * @return A RunnableFuture which when completed returns the number of rows updated.
+     * @return A <code>Callable</code> which returns the number of rows updated.
      */
-    public RunnableFuture<Integer> update(String sql, Object param) throws SQLException {
+    public Callable<Integer> update(String sql, Object param) throws SQLException {
         Connection conn = this.prepareConnection();
         return this.update(conn, true, sql, new Object[] { param });
     }
@@ -716,72 +517,11 @@ public class AsyncQueryRunner {
      * @param params Initializes the PreparedStatement's IN (i.e. '?') 
      * parameters.
      * @throws SQLException if a database access error occurs
-     * @return A RunnableFuture which when completed returns the number of rows updated.
+     * @return A <code>Callable</code> which returns the number of rows updated.
      */
-    public RunnableFuture<Integer> update(String sql, Object... params) throws SQLException {
+    public Callable<Integer> update(String sql, Object... params) throws SQLException {
         Connection conn = this.prepareConnection();
         return this.update(conn, true, sql, params);
     }
     
-    /**
-     * Wrap the <code>ResultSet</code> in a decorator before processing it.
-     * This implementation returns the <code>ResultSet</code> it is given
-     * without any decoration.
-     *
-     * <p>
-     * Often, the implementation of this method can be done in an anonymous 
-     * inner class like this:
-     * </p>
-     * <pre> 
-     * QueryRunner run = new QueryRunner() {
-     *     protected ResultSet wrap(ResultSet rs) {
-     *         return StringTrimmedResultSet.wrap(rs);
-     *     }
-     * };
-     * </pre>
-     * 
-     * @param rs The <code>ResultSet</code> to decorate; never 
-     * <code>null</code>.
-     * @return The <code>ResultSet</code> wrapped in some decorator. 
-     */
-    protected ResultSet wrap(ResultSet rs) {
-        return rs;
-    }
-    
-    /**
-     * Close a <code>Connection</code>.  This implementation avoids closing if 
-     * null and does <strong>not</strong> suppress any exceptions.  Subclasses
-     * can override to provide special handling like logging.
-     * @param conn Connection to close
-     * @throws SQLException if a database access error occurs
-     * @since DbUtils 1.1
-     */
-    protected void close(Connection conn) throws SQLException {
-        DbUtils.close(conn);
-    }
-    
-    /**
-     * Close a <code>Statement</code>.  This implementation avoids closing if 
-     * null and does <strong>not</strong> suppress any exceptions.  Subclasses
-     * can override to provide special handling like logging.
-     * @param stmt Statement to close
-     * @throws SQLException if a database access error occurs
-     * @since DbUtils 1.1
-     */
-    protected void close(Statement stmt) throws SQLException {
-        DbUtils.close(stmt);
-    }
-
-    /**
-     * Close a <code>ResultSet</code>.  This implementation avoids closing if 
-     * null and does <strong>not</strong> suppress any exceptions.  Subclasses
-     * can override to provide special handling like logging.
-     * @param rs ResultSet to close
-     * @throws SQLException if a database access error occurs
-     * @since DbUtils 1.1
-     */
-    protected void close(ResultSet rs) throws SQLException {
-        DbUtils.close(rs);
-    }
-
 }

Modified: commons/proper/dbutils/trunk/src/java/org/apache/commons/dbutils/QueryRunner.java
URL: http://svn.apache.org/viewvc/commons/proper/dbutils/trunk/src/java/org/apache/commons/dbutils/QueryRunner.java?rev=1158109&r1=1158108&r2=1158109&view=diff
==============================================================================
--- commons/proper/dbutils/trunk/src/java/org/apache/commons/dbutils/QueryRunner.java (original)
+++ commons/proper/dbutils/trunk/src/java/org/apache/commons/dbutils/QueryRunner.java Tue Aug 16 05:50:19 2011
@@ -16,19 +16,11 @@
  */
 package org.apache.commons.dbutils;
 
-import java.beans.IntrospectionException;
-import java.beans.Introspector;
-import java.beans.PropertyDescriptor;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
 import java.sql.Connection;
 import java.sql.ParameterMetaData;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
-import java.sql.Statement;
-import java.sql.Types;
-import java.util.Arrays;
 
 import javax.sql.DataSource;
 
@@ -38,24 +30,13 @@ import javax.sql.DataSource;
  * 
  * @see ResultSetHandler
  */
-public class QueryRunner {
-
-    /**
-     * Is {@link ParameterMetaData#getParameterType(int)} broken (have we tried it yet)?
-     */
-    private volatile boolean pmdKnownBroken = false;
-    
-    /**
-     * The DataSource to retrieve connections from.
-     */
-    protected final DataSource ds;
+public class QueryRunner extends AbstractQueryRunner {
 
     /**
      * Constructor for QueryRunner.
      */
     public QueryRunner() {
         super();
-        ds = null;
     }
 
     /**
@@ -65,21 +46,18 @@ public class QueryRunner {
      * and if it breaks, we'll remember not to use it again.
      */
     public QueryRunner(boolean pmdKnownBroken) {
-        super();
-        this.pmdKnownBroken = pmdKnownBroken; 
-        ds = null;
+        super(pmdKnownBroken);
     }
     
     /**
-     * Constructor for QueryRunner, allows workaround for Oracle drivers.  Methods that do not take a 
+     * Constructor for QueryRunner which takes a <code>DataSource</code>.  Methods that do not take a 
      * <code>Connection</code> parameter will retrieve connections from this
      * <code>DataSource</code>.
      * 
      * @param ds The <code>DataSource</code> to retrieve connections from.
      */
     public QueryRunner(DataSource ds) {
-        super();
-        this.ds = ds;
+        super(ds);
     }
     
     /**
@@ -93,9 +71,7 @@ public class QueryRunner {
      * and if it breaks, we'll remember not to use it again.
      */
     public QueryRunner(DataSource ds, boolean pmdKnownBroken) {
-        super();
-        this.pmdKnownBroken = pmdKnownBroken;
-        this.ds = ds;
+        super(ds, pmdKnownBroken);
     }
     
     /**
@@ -110,27 +86,8 @@ public class QueryRunner {
      * @throws SQLException if a database access error occurs
      * @since DbUtils 1.1
      */
-    public int[] batch(Connection conn, String sql, Object[][] params)
-        throws SQLException {
-
-        PreparedStatement stmt = null;
-        int[] rows = null;
-        try {
-            stmt = this.prepareStatement(conn, sql);
-
-            for (int i = 0; i < params.length; i++) {
-                this.fillStatement(stmt, params[i]);
-                stmt.addBatch();
-            }
-            rows = stmt.executeBatch();
-
-        } catch (SQLException e) {
-            this.rethrow(e, sql, (Object[])params);
-        } finally {
-            close(stmt);
-        }
-
-        return rows;
+    public int[] batch(Connection conn, String sql, Object[][] params) throws SQLException {
+        return this.batch(conn, false, sql, params);
     }
 
     /**
@@ -149,195 +106,61 @@ public class QueryRunner {
     public int[] batch(String sql, Object[][] params) throws SQLException {
         Connection conn = this.prepareConnection();
 
-        try {
-            return this.batch(conn, sql, params);
-        } finally {
-            close(conn);
-        }
+        return this.batch(conn, true, sql, params);
     }
 
     /**
-     * Fill the <code>PreparedStatement</code> replacement parameters with 
-     * the given objects.
-     * @param stmt PreparedStatement to fill
-     * @param params Query replacement parameters; <code>null</code> is a valid
-     * value to pass in.
-     * @throws SQLException if a database access error occurs
+     * Calls update after checking the parameters to ensure nothing is null.
+     * @param conn The connection to use for the batch call.
+     * @param closeConn True if the connection should be closed, false otherwise.
+     * @param sql The SQL statement to execute.
+     * @param params An array of query replacement parameters.  Each row in
+     * this array is one set of batch replacement values. 
+     * @return The number of rows updated in the batch.
+     * @throws SQLException If there are database or parameter errors.
      */
-    public void fillStatement(PreparedStatement stmt, Object... params)
-        throws SQLException {
-
-        if (params == null) {
-            return;
+    private int[] batch(Connection conn, boolean closeConn, String sql, Object[][] params) throws SQLException {
+        if(conn == null) {
+            if(closeConn)
+                close(conn);
+            throw new SQLException("Null connection");
         }
         
-        ParameterMetaData pmd = null;
-        if (!pmdKnownBroken) {
-            pmd = stmt.getParameterMetaData();
-            if (pmd.getParameterCount() < params.length) {
-                throw new SQLException("Too many parameters: expected "
-                        + pmd.getParameterCount() + ", was given " + params.length);
-            }
+        if(sql == null) {
+            if(closeConn)
+                close(conn);
+            throw new SQLException("Null SQL statement");
         }
-        for (int i = 0; i < params.length; i++) {
-            if (params[i] != null) {
-                stmt.setObject(i + 1, params[i]);
-            } else {
-                // VARCHAR works with many drivers regardless
-                // of the actual column type.  Oddly, NULL and 
-                // OTHER don't work with Oracle's drivers.
-                int sqlType = Types.VARCHAR;
-                if (!pmdKnownBroken) {
-                    try {
-                        sqlType = pmd.getParameterType(i + 1);
-                    } catch (SQLException e) {
-                        pmdKnownBroken = true;
-                    }
-                }
-                stmt.setNull(i + 1, sqlType);
-            }
+        
+        if(params == null) {
+            if(closeConn)
+                close(conn);
+            throw new SQLException("Null parameters. If parameters aren't need, pass an empty array.");
         }
-    }
 
-    /**
-     * Fill the <code>PreparedStatement</code> replacement parameters with the
-     * given object's bean property values.
-     * 
-     * @param stmt
-     *            PreparedStatement to fill
-     * @param bean
-     *            a JavaBean object
-     * @param properties
-     *            an ordered array of properties; this gives the order to insert
-     *            values in the statement
-     * @throws SQLException
-     *             if a database access error occurs
-     */
-    public void fillStatementWithBean(PreparedStatement stmt, Object bean,
-            PropertyDescriptor[] properties) throws SQLException {
-        Object[] params = new Object[properties.length];
-        for (int i = 0; i < properties.length; i++) {
-            PropertyDescriptor property = properties[i];
-            Object value = null;
-            Method method = property.getReadMethod();
-            if (method == null) {
-                throw new RuntimeException("No read method for bean property "
-                        + bean.getClass() + " " + property.getName());
-            }
-            try {
-                value = method.invoke(bean, new Object[0]);
-            } catch (InvocationTargetException e) {
-                throw new RuntimeException("Couldn't invoke method: " + method, e);
-            } catch (IllegalArgumentException e) {
-                throw new RuntimeException("Couldn't invoke method with 0 arguments: " + method, e);
-            } catch (IllegalAccessException e) {
-                throw new RuntimeException("Couldn't invoke method: " + method, e);
-            } 
-            params[i] = value;
-        }
-        fillStatement(stmt, params);
-    }
-
-    /**
-     * Fill the <code>PreparedStatement</code> replacement parameters with the
-     * given object's bean property values.
-     * 
-     * @param stmt
-     *            PreparedStatement to fill
-     * @param bean
-     *            a JavaBean object
-     * @param propertyNames
-     *            an ordered array of property names (these should match the
-     *            getters/setters); this gives the order to insert values in the
-     *            statement
-     * @throws SQLException
-     *             if a database access error occurs
-     */
-    public void fillStatementWithBean(PreparedStatement stmt, Object bean,
-            String... propertyNames) throws SQLException {
-        PropertyDescriptor[] descriptors;
+        PreparedStatement stmt = null;
+        int[] rows = null;
         try {
-            descriptors = Introspector.getBeanInfo(bean.getClass())
-                    .getPropertyDescriptors();
-        } catch (IntrospectionException e) {
-            throw new RuntimeException("Couldn't introspect bean " + bean.getClass().toString(), e);
-        }
-        PropertyDescriptor[] sorted = new PropertyDescriptor[propertyNames.length];
-        for (int i = 0; i < propertyNames.length; i++) {
-            String propertyName = propertyNames[i];
-            if (propertyName == null) {
-                throw new NullPointerException("propertyName can't be null: " + i);
-            }
-            boolean found = false;
-            for (int j = 0; j < descriptors.length; j++) {
-                PropertyDescriptor descriptor = descriptors[j];
-                if (propertyName.equals(descriptor.getName())) {
-                    sorted[i] = descriptor;
-                    found = true;
-                    break;
-                }
-            }
-            if (!found) {
-                throw new RuntimeException("Couldn't find bean property: "
-                        + bean.getClass() + " " + propertyName);
+            stmt = this.prepareStatement(conn, sql);
+
+            for (int i = 0; i < params.length; i++) {
+                this.fillStatement(stmt, params[i]);
+                stmt.addBatch();
             }
-        }
-        fillStatementWithBean(stmt, bean, sorted);
-    }
+            rows = stmt.executeBatch();
 
-    /**
-     * Returns the <code>DataSource</code> this runner is using.  
-     * <code>QueryRunner</code> methods always call this method to get the
-     * <code>DataSource</code> so subclasses can provide specialized
-     * behavior.
-     *
-     * @return DataSource the runner is using
-     */
-    public DataSource getDataSource() {
-        return this.ds;
-    }
+        } catch (SQLException e) {
+            this.rethrow(e, sql, (Object[])params);
+        } finally {
+            close(stmt);
+            if(closeConn)
+                close(conn);
+        }
 
-    /**
-     * Factory method that creates and initializes a 
-     * <code>PreparedStatement</code> object for the given SQL.  
-     * <code>QueryRunner</code> methods always call this method to prepare 
-     * statements for them.  Subclasses can override this method to provide 
-     * special PreparedStatement configuration if needed.  This implementation
-     * simply calls <code>conn.prepareStatement(sql)</code>.
-     *  
-     * @param conn The <code>Connection</code> used to create the 
-     * <code>PreparedStatement</code>
-     * @param sql The SQL statement to prepare.
-     * @return An initialized <code>PreparedStatement</code>.
-     * @throws SQLException if a database access error occurs
-     */
-    protected PreparedStatement prepareStatement(Connection conn, String sql)
-        throws SQLException {
-            
-        return conn.prepareStatement(sql);
+        return rows;
     }
     
     /**
-     * Factory method that creates and initializes a 
-     * <code>Connection</code> object.  <code>QueryRunner</code> methods 
-     * always call this method to retrieve connections from its DataSource.  
-     * Subclasses can override this method to provide 
-     * special <code>Connection</code> configuration if needed.  This 
-     * implementation simply calls <code>ds.getConnection()</code>.
-     * 
-     * @return An initialized <code>Connection</code>.
-     * @throws SQLException if a database access error occurs
-     * @since DbUtils 1.1
-     */
-    protected Connection prepareConnection() throws SQLException {
-        if(this.getDataSource() == null) {
-            throw new SQLException("QueryRunner requires a DataSource to be " +
-                "invoked in this way, or a Connection should be passed in");
-        }
-        return this.getDataSource().getConnection();
-    }
-
-    /**
      * Execute an SQL SELECT query with a single replacement parameter. The
      * caller is responsible for closing the connection.
      * @param <T> The type of object that the handler returns
@@ -350,10 +173,8 @@ public class QueryRunner {
      * @deprecated Use {@link #query(Connection, String, ResultSetHandler, Object...)}
      */
     @Deprecated
-    public <T> T query(Connection conn, String sql, Object param,
-            ResultSetHandler<T> rsh) throws SQLException {
-
-        return this.query(conn, sql, rsh, new Object[] { param });
+    public <T> T query(Connection conn, String sql, Object param, ResultSetHandler<T> rsh) throws SQLException {
+        return this.query(conn, false, sql, rsh, new Object[] { param });
     }
 
     /**
@@ -369,10 +190,10 @@ public class QueryRunner {
      * @deprecated Use {@link #query(Connection,String,ResultSetHandler,Object...)} instead
      */
     @Deprecated
-    public <T> T query(Connection conn, String sql, Object[] params,
-            ResultSetHandler<T> rsh) throws SQLException {
-                return query(conn, sql, rsh, params);
-            }
+    public <T> T query(Connection conn, String sql, Object[] params, ResultSetHandler<T> rsh) throws SQLException {
+                return this.query(conn, false, sql, rsh, params);
+    }
+    
     /**
      * Execute an SQL SELECT query with replacement parameters.  The
      * caller is responsible for closing the connection.
@@ -384,33 +205,10 @@ public class QueryRunner {
      * @return The object returned by the handler.
      * @throws SQLException if a database access error occurs
      */
-    public <T> T query(Connection conn, String sql, ResultSetHandler<T> rsh,
-            Object... params) throws SQLException {
-
-        PreparedStatement stmt = null;
-        ResultSet rs = null;
-        T result = null;
-
-        try {
-            stmt = this.prepareStatement(conn, sql);
-            this.fillStatement(stmt, params);
-            rs = this.wrap(stmt.executeQuery());
-            result = rsh.handle(rs);
-
-        } catch (SQLException e) {
-            this.rethrow(e, sql, params);
-
-        } finally {
-            try {
-                close(rs);
-            } finally {
-                close(stmt);
-            }
-        }
-
-        return result;
+    public <T> T query(Connection conn, String sql, ResultSetHandler<T> rsh, Object... params) throws SQLException {
+        return this.query(conn, false, sql, rsh, params);
     }
-
+    
     /**
      * Execute an SQL SELECT query without any replacement parameters.  The
      * caller is responsible for closing the connection.
@@ -421,10 +219,8 @@ public class QueryRunner {
      * @return The object returned by the handler.
      * @throws SQLException if a database access error occurs
      */
-    public <T> T query(Connection conn, String sql, ResultSetHandler<T> rsh)
-        throws SQLException {
-
-        return this.query(conn, sql, rsh, (Object[]) null);
+    public <T> T query(Connection conn, String sql, ResultSetHandler<T> rsh) throws SQLException {
+        return this.query(conn, false, sql, rsh, (Object[]) null);
     }
 
     /**
@@ -442,10 +238,10 @@ public class QueryRunner {
      * @deprecated Use {@link #query(String, ResultSetHandler, Object...)}
      */
     @Deprecated
-    public <T> T query(String sql, Object param, ResultSetHandler<T> rsh)
-        throws SQLException {
+    public <T> T query(String sql, Object param, ResultSetHandler<T> rsh) throws SQLException {
+        Connection conn = this.prepareConnection();
 
-        return this.query(sql, rsh, new Object[] { param });
+        return this.query(conn, true, sql, rsh, new Object[] { param });
     }
 
     /**
@@ -465,10 +261,11 @@ public class QueryRunner {
      * @deprecated Use {@link #query(String, ResultSetHandler, Object...)}
      */
     @Deprecated
-    public <T> T query(String sql, Object[] params, ResultSetHandler<T> rsh)
-        throws SQLException {
-            return query(sql, rsh, params);
-        }
+    public <T> T query(String sql, Object[] params, ResultSetHandler<T> rsh) throws SQLException {
+        Connection conn = this.prepareConnection();
+
+        return query(conn, true, sql, rsh, params);
+    }
 
     /**
      * Executes the given SELECT SQL query and returns a result object.
@@ -483,16 +280,10 @@ public class QueryRunner {
      * @return An object generated by the handler.
      * @throws SQLException if a database access error occurs
      */
-    public <T> T query(String sql, ResultSetHandler<T> rsh, Object... params)
-        throws SQLException {
-
+    public <T> T query(String sql, ResultSetHandler<T> rsh, Object... params) throws SQLException {
         Connection conn = this.prepareConnection();
 
-        try {
-            return this.query(conn, sql, rsh, params);
-        } finally {
-            close(conn);
-        }
+        return this.query(conn, true, sql, rsh, params);
     }
 
     /**
@@ -508,46 +299,64 @@ public class QueryRunner {
      * @throws SQLException if a database access error occurs
      */
     public <T> T query(String sql, ResultSetHandler<T> rsh) throws SQLException {
-        return this.query(sql, rsh, (Object[]) null);
+        Connection conn = this.prepareConnection();
+
+        return this.query(conn, true, sql, rsh, (Object[]) null);
     }
 
     /**
-     * Throws a new exception with a more informative error message.
-     * 
-     * @param cause The original exception that will be chained to the new 
-     * exception when it's rethrown. 
-     * 
-     * @param sql The query that was executing when the exception happened.
-     * 
-     * @param params The query replacement parameters; <code>null</code> is a 
-     * valid value to pass in.
-     * 
-     * @throws SQLException if a database access error occurs
+     * Calls query after checking the parameters to ensure nothing is null.
+     * @param conn The connection to use for the query call.
+     * @param closeConn True if the connection should be closed, false otherwise.
+     * @param sql The SQL statement to execute.
+     * @param params An array of query replacement parameters.  Each row in
+     * this array is one set of batch replacement values. 
+     * @return The results of the query.
+     * @throws SQLException If there are database or parameter errors.
      */
-    protected void rethrow(SQLException cause, String sql, Object... params)
-        throws SQLException {
-
-        String causeMessage = cause.getMessage();
-        if (causeMessage == null) {
-            causeMessage = "";
+    private <T> T query(Connection conn, boolean closeConn, String sql, ResultSetHandler<T> rsh, Object... params) throws SQLException {
+        if(conn == null) {
+            if(closeConn)
+                close(conn);
+            throw new SQLException("Null connection");
+        }
+        
+        if(sql == null) {
+            if(closeConn)
+                close(conn);
+            throw new SQLException("Null SQL statement");
+        }
+        
+        if(rsh == null) {
+            if(closeConn)
+                close(conn);
+            throw new SQLException("Null ResultSetHandler");
         }
-        StringBuffer msg = new StringBuffer(causeMessage);
+        
+        PreparedStatement stmt = null;
+        ResultSet rs = null;
+        T result = null;
 
-        msg.append(" Query: ");
-        msg.append(sql);
-        msg.append(" Parameters: ");
+        try {
+            stmt = this.prepareStatement(conn, sql);
+            this.fillStatement(stmt, params);
+            rs = this.wrap(stmt.executeQuery());
+            result = rsh.handle(rs);
 
-        if (params == null) {
-            msg.append("[]");
-        } else {
-            msg.append(Arrays.deepToString(params));
-        }
+        } catch (SQLException e) {
+            this.rethrow(e, sql, params);
 
-        SQLException e = new SQLException(msg.toString(), cause.getSQLState(),
-                cause.getErrorCode());
-        e.setNextException(cause);
+        } finally {
+            try {
+                close(rs);
+            } finally {
+                close(stmt);
+                if(closeConn)
+                    close(conn);
+            }
+        }
 
-        throw e;
+        return result;
     }
 
     /**
@@ -560,7 +369,7 @@ public class QueryRunner {
      * @throws SQLException if a database access error occurs
      */
     public int update(Connection conn, String sql) throws SQLException {
-        return this.update(conn, sql, (Object[]) null);
+        return this.update(conn, false, sql, (Object[]) null);
     }
 
     /**
@@ -573,10 +382,8 @@ public class QueryRunner {
      * @return The number of rows updated.
      * @throws SQLException if a database access error occurs
      */
-    public int update(Connection conn, String sql, Object param)
-        throws SQLException {
-
-        return this.update(conn, sql, new Object[] { param });
+    public int update(Connection conn, String sql, Object param) throws SQLException {
+        return this.update(conn, false, sql, new Object[] { param });
     }
 
     /**
@@ -588,25 +395,8 @@ public class QueryRunner {
      * @return The number of rows updated.
      * @throws SQLException if a database access error occurs
      */
-    public int update(Connection conn, String sql, Object... params)
-        throws SQLException {
-
-        PreparedStatement stmt = null;
-        int rows = 0;
-
-        try {
-            stmt = this.prepareStatement(conn, sql);
-            this.fillStatement(stmt, params);
-            rows = stmt.executeUpdate();
-
-        } catch (SQLException e) {
-            this.rethrow(e, sql, params);
-
-        } finally {
-            close(stmt);
-        }
-
-        return rows;
+    public int update(Connection conn, String sql, Object... params) throws SQLException {
+        return update(conn, false, sql, params);
     }
 
     /**
@@ -621,7 +411,9 @@ public class QueryRunner {
      * @return The number of rows updated.
      */
     public int update(String sql) throws SQLException {
-        return this.update(sql, (Object[]) null);
+        Connection conn = this.prepareConnection();
+
+        return this.update(conn, true, sql, (Object[]) null);
     }
 
     /**
@@ -637,7 +429,9 @@ public class QueryRunner {
      * @return The number of rows updated.
      */
     public int update(String sql, Object param) throws SQLException {
-        return this.update(sql, new Object[] { param });
+        Connection conn = this.prepareConnection();
+
+        return this.update(conn, true, sql, new Object[] { param });
     }
 
     /**
@@ -655,72 +449,50 @@ public class QueryRunner {
     public int update(String sql, Object... params) throws SQLException {
         Connection conn = this.prepareConnection();
 
-        try {
-            return this.update(conn, sql, params);
-        } finally {
-            close(conn);
-        }
+        return this.update(conn, true, sql, params);
     }
     
     /**
-     * Wrap the <code>ResultSet</code> in a decorator before processing it.
-     * This implementation returns the <code>ResultSet</code> it is given
-     * without any decoration.
-     *
-     * <p>
-     * Often, the implementation of this method can be done in an anonymous 
-     * inner class like this:
-     * </p>
-     * <pre> 
-     * QueryRunner run = new QueryRunner() {
-     *     protected ResultSet wrap(ResultSet rs) {
-     *         return StringTrimmedResultSet.wrap(rs);
-     *     }
-     * };
-     * </pre>
-     * 
-     * @param rs The <code>ResultSet</code> to decorate; never 
-     * <code>null</code>.
-     * @return The <code>ResultSet</code> wrapped in some decorator. 
-     */
-    protected ResultSet wrap(ResultSet rs) {
-        return rs;
-    }
-    
-    /**
-     * Close a <code>Connection</code>.  This implementation avoids closing if 
-     * null and does <strong>not</strong> suppress any exceptions.  Subclasses
-     * can override to provide special handling like logging.
-     * @param conn Connection to close
-     * @throws SQLException if a database access error occurs
-     * @since DbUtils 1.1
-     */
-    protected void close(Connection conn) throws SQLException {
-        DbUtils.close(conn);
-    }
-    
-    /**
-     * Close a <code>Statement</code>.  This implementation avoids closing if 
-     * null and does <strong>not</strong> suppress any exceptions.  Subclasses
-     * can override to provide special handling like logging.
-     * @param stmt Statement to close
-     * @throws SQLException if a database access error occurs
-     * @since DbUtils 1.1
+     * Calls update after checking the parameters to ensure nothing is null.
+     * @param conn The connection to use for the update call.
+     * @param closeConn True if the connection should be closed, false otherwise.
+     * @param sql The SQL statement to execute.
+     * @param params An array of update replacement parameters.  Each row in
+     * this array is one set of update replacement values. 
+     * @return The number of rows updated.
+     * @throws SQLException If there are database or parameter errors.
      */
-    protected void close(Statement stmt) throws SQLException {
-        DbUtils.close(stmt);
-    }
+    public int update(Connection conn, boolean closeConn, String sql, Object... params) throws SQLException {
+        if(conn == null) {
+            if(closeConn)
+                close(conn);
+            throw new SQLException("Null connection");
+        }
+        
+        if(sql == null) {
+            if(closeConn)
+                close(conn);
+            throw new SQLException("Null SQL statement");
+        }
 
-    /**
-     * Close a <code>ResultSet</code>.  This implementation avoids closing if 
-     * null and does <strong>not</strong> suppress any exceptions.  Subclasses
-     * can override to provide special handling like logging.
-     * @param rs ResultSet to close
-     * @throws SQLException if a database access error occurs
-     * @since DbUtils 1.1
-     */
-    protected void close(ResultSet rs) throws SQLException {
-        DbUtils.close(rs);
-    }
+        PreparedStatement stmt = null;
+        int rows = 0;
 
+        try {
+            stmt = this.prepareStatement(conn, sql);
+            this.fillStatement(stmt, params);
+            rows = stmt.executeUpdate();
+
+        } catch (SQLException e) {
+            this.rethrow(e, sql, params);
+
+        } finally {
+            close(stmt);
+            if(closeConn)
+                close(conn);
+        }
+
+        return rows;
+    }
+    
 }

Modified: commons/proper/dbutils/trunk/src/test/org/apache/commons/dbutils/AsyncQueryRunnerTest.java
URL: http://svn.apache.org/viewvc/commons/proper/dbutils/trunk/src/test/org/apache/commons/dbutils/AsyncQueryRunnerTest.java?rev=1158109&r1=1158108&r2=1158109&view=diff
==============================================================================
--- commons/proper/dbutils/trunk/src/test/org/apache/commons/dbutils/AsyncQueryRunnerTest.java (original)
+++ commons/proper/dbutils/trunk/src/test/org/apache/commons/dbutils/AsyncQueryRunnerTest.java Tue Aug 16 05:50:19 2011
@@ -24,14 +24,12 @@ import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import java.lang.reflect.Method;
 import java.sql.Connection;
 import java.sql.ParameterMetaData;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.RunnableFuture;
+import java.util.concurrent.Callable;
 
 import javax.sql.DataSource;
 
@@ -51,17 +49,6 @@ public class AsyncQueryRunnerTest {
     @Mock ParameterMetaData meta;
     @Mock ResultSet results;
     
-    static final Method getParameterCount, getParameterType, getParameterMetaData;
-    static {
-        try {
-            getParameterCount = ParameterMetaData.class.getMethod("getParameterCount", new Class[0]);
-            getParameterType = ParameterMetaData.class.getMethod("getParameterType", new Class[]{int.class});
-            getParameterMetaData = PreparedStatement.class.getMethod("getParameterMetaData", new Class[0]);
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
-    }
-    
     @Before
     public void setUp() throws Exception {
 		MockitoAnnotations.initMocks(this);	// init the mocks
@@ -80,33 +67,28 @@ public class AsyncQueryRunnerTest {
     //
     // Batch test cases
     //
-    
     private void callGoodBatch(Connection conn, Object[][] params) throws Exception {
     	when(meta.getParameterCount()).thenReturn(2);
-    	RunnableFuture<int[]> future = runner.batch(conn, "select * from blah where ? = ?", params);
+    	Callable<int[]> callable = runner.batch(conn, "select * from blah where ? = ?", params);
     	verify(stmt, times(2)).addBatch();
     	verify(stmt, never()).close();	// make sure the statement is still open
 
-    	future.run();
+    	callable.call();
     	verify(stmt, times(1)).executeBatch();
     	verify(stmt, times(1)).close();	// make sure we closed the statement
     	verify(conn, times(0)).close();	// make sure we closed the connection
-
-    	future.get(); // make sure an exception wasn't thrown
     }
     
     private void callGoodBatch(Object[][] params) throws Exception {
     	when(meta.getParameterCount()).thenReturn(2);
-    	RunnableFuture<int[]> future = runner.batch("select * from blah where ? = ?", params);
+    	Callable<int[]> callable = runner.batch("select * from blah where ? = ?", params);
     	verify(stmt, times(2)).addBatch();
     	verify(stmt, never()).close();	// make sure the statement is still open
 
-    	future.run();
+    	callable.call();
     	verify(stmt, times(1)).executeBatch();
     	verify(stmt, times(1)).close();	// make sure we closed the statement
     	verify(conn, times(1)).close();	// make sure we closed the connection
-
-    	future.get(); // make sure an exception wasn't thrown
     }
 
     @Test
@@ -143,23 +125,19 @@ public class AsyncQueryRunnerTest {
 
     // helper method for calling batch when an exception is expected
     private void callBatchWithException(String sql, Object[][] params) throws Exception {
-    	RunnableFuture<int[]> future = null;
+    	Callable<int[]> callable = null;
     	boolean caught = false;
     	
     	try {
-    		future = runner.batch(sql, params);
+    		callable = runner.batch(sql, params);
         	verify(stmt, times(2)).addBatch();
         	verify(stmt, never()).close();	// make sure the statement is still open
 
-        	future.run();
+        	callable.call();
         	verify(stmt, times(1)).executeBatch();
         	verify(stmt, times(1)).close();	// make sure the statement is closed
         	verify(conn, times(1)).close();	// make sure the connection is closed
-        	
-        	future.get();
-    	} catch(SQLException e) {
-    		caught = true;
-    	} catch(ExecutionException e) {
+    	} catch(Exception e) {
     		caught = true;
     	}
     	
@@ -231,57 +209,48 @@ public class AsyncQueryRunnerTest {
     //
     private void callGoodQuery(Connection conn) throws Exception {
     	when(meta.getParameterCount()).thenReturn(2);
-    	RunnableFuture<Object[]> future = runner.query(conn, "select * from blah where ? = ?", handler, "unit", "test");
+    	Callable<Object[]> callable = runner.query(conn, "select * from blah where ? = ?", handler, "unit", "test");
     	verify(stmt, never()).close();	// make sure the statement is still open
 
-    	future.run();
+    	callable.call();
     	verify(stmt, times(1)).executeQuery();
     	verify(results, times(1)).close();
     	verify(stmt, times(1)).close();	// make sure we closed the statement
     	verify(conn, times(0)).close();	// make sure we closed the connection
 
-    	future.get(); // make sure an exception wasn't thrown
-    	
     	// call the other variation of query
     	when(meta.getParameterCount()).thenReturn(0);
-    	future = runner.query(conn, "select * from blah", handler);
+    	callable = runner.query(conn, "select * from blah", handler);
     	verify(stmt, times(1)).close();	// make sure the statement has only been closed once
 
-    	future.run();
+    	callable.call();
     	verify(stmt, times(2)).executeQuery();
     	verify(results, times(2)).close();
     	verify(stmt, times(2)).close();	// make sure we closed the statement
     	verify(conn, times(0)).close();	// make sure we closed the connection
-
-    	future.get(); // make sure an exception wasn't thrown
-    	
     }
     
     private void callGoodQuery() throws Exception {
     	when(meta.getParameterCount()).thenReturn(2);
-    	RunnableFuture<Object[]> future = runner.query("select * from blah where ? = ?", handler, "unit", "test");
+    	Callable<Object[]> callable = runner.query("select * from blah where ? = ?", handler, "unit", "test");
     	verify(stmt, never()).close();	// make sure the statement is still open
 
-    	future.run();
+    	callable.call();
     	verify(stmt, times(1)).executeQuery();
     	verify(results, times(1)).close();
     	verify(stmt, times(1)).close();	// make sure we closed the statement
     	verify(conn, times(1)).close();	// make sure we closed the connection
 
-    	future.get(); // make sure an exception wasn't thrown
-
     	// call the other variation of query
     	when(meta.getParameterCount()).thenReturn(0);
-    	future = runner.query("select * from blah", handler);
+    	callable = runner.query("select * from blah", handler);
     	verify(stmt, times(1)).close();	// make sure the statement is still open
 
-    	future.run();
+    	callable.call();
     	verify(stmt, times(2)).executeQuery();
     	verify(results, times(2)).close();
     	verify(stmt, times(2)).close();	// make sure we closed the statement
     	verify(conn, times(2)).close();	// make sure we closed the connection
-
-    	future.get(); // make sure an exception wasn't thrown
     }
     
     @Test
@@ -304,24 +273,20 @@ public class AsyncQueryRunnerTest {
 
     // helper method for calling batch when an exception is expected
     private void callQueryWithException(Object... params) throws Exception {
-    	RunnableFuture<Object[]> future = null;
+    	Callable<Object[]> callable = null;
     	boolean caught = false;
     	
     	try {
         	when(meta.getParameterCount()).thenReturn(2);
-    		future = runner.query("select * from blah where ? = ?", handler, params);
+    		callable = runner.query("select * from blah where ? = ?", handler, params);
         	verify(stmt, never()).close();	// make sure the statement is still open
 
-        	future.run();
+        	callable.call();
         	verify(stmt, times(1)).executeQuery();
         	verify(results, times(1)).close();
         	verify(stmt, times(1)).close();	// make sure we closed the statement
         	verify(conn, times(1)).close();	// make sure we closed the connection
-        	
-        	future.get();
-    	} catch(SQLException e) {
-    		caught = true;
-    	} catch(ExecutionException e) {
+    	} catch(Exception e) {
     		caught = true;
     	}
     	
@@ -379,76 +344,64 @@ public class AsyncQueryRunnerTest {
     //
     private void callGoodUpdate(Connection conn) throws Exception {
     	when(meta.getParameterCount()).thenReturn(2);
-    	RunnableFuture<Integer> future = runner.update(conn, "update blah set ? = ?", "unit", "test");
+    	Callable<Integer> callable = runner.update(conn, "update blah set ? = ?", "unit", "test");
     	verify(stmt, never()).close();	// make sure the statement is still open
 
-    	future.run();
+    	callable.call();
     	verify(stmt, times(1)).executeUpdate();
     	verify(stmt, times(1)).close();	// make sure we closed the statement
     	verify(conn, times(0)).close();	// make sure we closed the connection
 
-    	future.get(); // make sure an exception wasn't thrown
-    	
     	// call the other variation
     	when(meta.getParameterCount()).thenReturn(0);
-    	future = runner.update(conn, "update blah set unit = test");
+    	callable = runner.update(conn, "update blah set unit = test");
     	verify(stmt, times(1)).close();	// make sure the statement is still open
 
-    	future.run();
+    	callable.call();
     	verify(stmt, times(2)).executeUpdate();
     	verify(stmt, times(2)).close();	// make sure we closed the statement
     	verify(conn, times(0)).close();	// make sure we closed the connection
 
-    	future.get(); // make sure an exception wasn't thrown
-
     	// call the other variation
     	when(meta.getParameterCount()).thenReturn(1);
-    	future = runner.update(conn, "update blah set unit = ?", "test");
+    	callable = runner.update(conn, "update blah set unit = ?", "test");
     	verify(stmt, times(2)).close();	// make sure the statement is still open
 
-    	future.run();
+    	callable.call();
     	verify(stmt, times(3)).executeUpdate();
     	verify(stmt, times(3)).close();	// make sure we closed the statement
     	verify(conn, times(0)).close();	// make sure we closed the connection
-
-    	future.get(); // make sure an exception wasn't thrown
     }
     
     private void callGoodUpdate() throws Exception {
     	when(meta.getParameterCount()).thenReturn(2);
-    	RunnableFuture<Integer> future = runner.update("update blah set ? = ?", "unit", "test");
+    	Callable<Integer> callable = runner.update("update blah set ? = ?", "unit", "test");
     	verify(stmt, never()).close();	// make sure the statement is still open
 
-    	future.run();
+    	callable.call();
     	verify(stmt, times(1)).executeUpdate();
     	verify(stmt, times(1)).close();	// make sure we closed the statement
     	verify(conn, times(1)).close();	// make sure we closed the connection
 
-    	future.get(); // make sure an exception wasn't thrown
-
     	// call the other variation
     	when(meta.getParameterCount()).thenReturn(0);
-    	future = runner.update("update blah set unit = test");
+    	callable = runner.update("update blah set unit = test");
     	verify(stmt, times(1)).close();	// make sure the statement is still open
 
-    	future.run();
+    	callable.call();
     	verify(stmt, times(2)).executeUpdate();
     	verify(stmt, times(2)).close();	// make sure we closed the statement
     	verify(conn, times(2)).close();	// make sure we closed the connection
 
-    	future.get(); // make sure an exception wasn't thrown
-
     	// call the other variation
     	when(meta.getParameterCount()).thenReturn(1);
-    	future = runner.update("update blah set unit = ?", "test");
+    	callable = runner.update("update blah set unit = ?", "test");
     	verify(stmt, times(2)).close();	// make sure the statement is still open
 
-    	future.run();
+    	callable.call();
     	verify(stmt, times(3)).executeUpdate();
     	verify(stmt, times(3)).close();	// make sure we closed the statement
     	verify(conn, times(3)).close();	// make sure we closed the connection
-
-    	future.get(); // make sure an exception wasn't thrown
     }
     
     @Test
@@ -470,23 +423,19 @@ public class AsyncQueryRunnerTest {
 
     // helper method for calling batch when an exception is expected
     private void callUpdateWithException(Object... params) throws Exception {
-    	RunnableFuture<Integer> future = null;
+    	Callable<Integer> callable = null;
     	boolean caught = false;
     	
     	try {
     		when(meta.getParameterCount()).thenReturn(2);
-    		future = runner.update("select * from blah where ? = ?", params);
+    		callable = runner.update("select * from blah where ? = ?", params);
         	verify(stmt, never()).close();	// make sure the statement is still open
 
-        	future.run();
+        	callable.call();
         	verify(stmt, times(1)).executeUpdate();
         	verify(stmt, times(1)).close();	// make sure we closed the statement
         	verify(conn, times(1)).close();	// make sure we closed the connection
-
-        	future.get();
-    	} catch(SQLException e) {
-    		caught = true;
-    	} catch(ExecutionException e) {
+    	} catch(Exception e) {
     		caught = true;
     	}
     	



Mime
View raw message