You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ibatis.apache.org by cb...@apache.org on 2008/08/30 21:03:52 UTC

svn commit: r690554 [1/2] - in /ibatis/trunk/java/ibatis-3: ibatis-3-compat/src/main/java/com/ibatis/common/jdbc/ ibatis-3-core/src/main/java/org/apache/ibatis/adhoc/ ibatis-3-core/src/main/java/org/apache/ibatis/jdbc/ ibatis-3-core/src/main/java/org/a...

Author: cbegin
Date: Sat Aug 30 12:03:51 2008
New Revision: 690554

URL: http://svn.apache.org/viewvc?rev=690554&view=rev
Log:
Refactored data sources and runners

Added:
    ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/jdbc/PoolState.java
    ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/jdbc/PooledConnection.java
    ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/jdbc/PooledDataSource.java
      - copied, changed from r690527, ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/jdbc/SimpleDataSource.java
    ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/jdbc/UnpooledDataSource.java
      - copied, changed from r690527, ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/jdbc/DriverManagerDataSource.java
    ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/Null.java
      - copied, changed from r690527, ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/adhoc/Null.java
    ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/SqlRunner.java
      - copied, changed from r690527, ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/adhoc/AdHocExecutor.java
    ibatis/trunk/java/ibatis-3/ibatis-3-core/src/test/java/org/apache/ibatis/jdbc/PooledDataSourceTest.java
      - copied, changed from r690527, ibatis/trunk/java/ibatis-3/ibatis-3-core/src/test/java/org/apache/ibatis/jdbc/SimpleDataSourceTest.java
Removed:
    ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/adhoc/
    ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/jdbc/DriverManagerDataSource.java
    ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/jdbc/SimpleDataSource.java
    ibatis/trunk/java/ibatis-3/ibatis-3-core/src/test/java/org/apache/ibatis/jdbc/SimpleDataSourceTest.java
Modified:
    ibatis/trunk/java/ibatis-3/ibatis-3-compat/src/main/java/com/ibatis/common/jdbc/ScriptRunner.java
    ibatis/trunk/java/ibatis-3/ibatis-3-compat/src/main/java/com/ibatis/common/jdbc/SimpleDataSource.java
    ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/ScriptRunner.java
    ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/commands/BaseCommand.java
    ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/commands/BootstrapCommand.java
    ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/commands/DownCommand.java
    ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/commands/UpCommand.java
    ibatis/trunk/java/ibatis-3/ibatis-3-core/src/test/java/org/apache/ibatis/BaseDataTest.java
    ibatis/trunk/java/ibatis-3/ibatis-3-core/src/test/java/org/apache/ibatis/adhoc/AdHocExecutorTest.java
    ibatis/trunk/java/ibatis-3/ibatis-3-core/src/test/java/org/apache/ibatis/adhoc/NullTest.java
    ibatis/trunk/java/ibatis-3/ibatis-3-core/src/test/java/org/apache/ibatis/executor/BaseExecutorTest.java
    ibatis/trunk/java/ibatis-3/ibatis-3-core/src/test/java/org/apache/ibatis/metadata/MetadataTest.java
    ibatis/trunk/java/ibatis-3/ibatis-3-core/src/test/java/org/apache/ibatis/migration/MigratorTest.java
    ibatis/trunk/java/ibatis-3/ibatis-3-core/src/test/java/org/apache/ibatis/migration/ScriptRunnerTest.java

Modified: ibatis/trunk/java/ibatis-3/ibatis-3-compat/src/main/java/com/ibatis/common/jdbc/ScriptRunner.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-compat/src/main/java/com/ibatis/common/jdbc/ScriptRunner.java?rev=690554&r1=690553&r2=690554&view=diff
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-compat/src/main/java/com/ibatis/common/jdbc/ScriptRunner.java (original)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-compat/src/main/java/com/ibatis/common/jdbc/ScriptRunner.java Sat Aug 30 12:03:51 2008
@@ -1,15 +1,21 @@
 package com.ibatis.common.jdbc;
 
+import org.apache.ibatis.jdbc.UnpooledDataSource;
+
 import javax.sql.DataSource;
-import java.sql.Connection;
+import java.sql.*;
 
 public class ScriptRunner extends org.apache.ibatis.migration.ScriptRunner {
 
   public ScriptRunner(Connection connection, boolean autoCommit, boolean stopOnError) {
-    super(connection, autoCommit, stopOnError);
+    super(connection);
+    setAutoCommit(autoCommit);
+    setStopOnError(stopOnError);
   }
 
-  public ScriptRunner(String driver, String url, String username, String password, boolean autoCommit, boolean stopOnError) {
-    super(driver, url, username, password, autoCommit, stopOnError);
+  public ScriptRunner(String driver, String url, String username, String password, boolean autoCommit, boolean stopOnError) throws SQLException {
+    super(new UnpooledDataSource(driver, url, username, password).getConnection());
+    setAutoCommit(autoCommit);
+    setStopOnError(stopOnError);
   }
 }

Modified: ibatis/trunk/java/ibatis-3/ibatis-3-compat/src/main/java/com/ibatis/common/jdbc/SimpleDataSource.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-compat/src/main/java/com/ibatis/common/jdbc/SimpleDataSource.java?rev=690554&r1=690553&r2=690554&view=diff
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-compat/src/main/java/com/ibatis/common/jdbc/SimpleDataSource.java (original)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-compat/src/main/java/com/ibatis/common/jdbc/SimpleDataSource.java Sat Aug 30 12:03:51 2008
@@ -4,7 +4,9 @@
 
 import java.util.*;
 
-public class SimpleDataSource extends org.apache.ibatis.jdbc.SimpleDataSource {
+import org.apache.ibatis.jdbc.PooledDataSource;
+
+public class SimpleDataSource extends PooledDataSource {
 
   // Required Properties
   private static final String PROP_JDBC_DRIVER = "JDBC.Driver";

Added: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/jdbc/PoolState.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/jdbc/PoolState.java?rev=690554&view=auto
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/jdbc/PoolState.java (added)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/jdbc/PoolState.java Sat Aug 30 12:03:51 2008
@@ -0,0 +1,95 @@
+package org.apache.ibatis.jdbc;
+
+import java.util.*;
+
+public class PoolState {
+
+  protected PooledDataSource dataSource;
+
+  protected List idleConnections = new ArrayList();
+  protected List activeConnections = new ArrayList();
+  protected long requestCount = 0;
+  protected long accumulatedRequestTime = 0;
+  protected long accumulatedCheckoutTime = 0;
+  protected long claimedOverdueConnectionCount = 0;
+  protected long accumulatedCheckoutTimeOfOverdueConnections = 0;
+  protected long accumulatedWaitTime = 0;
+  protected long hadToWaitCount = 0;
+  protected long badConnectionCount = 0;
+
+  public PoolState(PooledDataSource dataSource) {
+    this.dataSource = dataSource;
+  }
+
+  public synchronized long getRequestCount() {
+    return requestCount;
+  }
+
+  public synchronized long getAverageRequestTime() {
+    return requestCount == 0 ? 0 : accumulatedRequestTime / requestCount;
+  }
+
+  public synchronized long getAverageWaitTime() {
+    return hadToWaitCount == 0 ? 0 : accumulatedWaitTime / hadToWaitCount;
+
+  }
+
+  public synchronized long getHadToWaitCount() {
+    return hadToWaitCount;
+  }
+
+  public synchronized long getBadConnectionCount() {
+    return badConnectionCount;
+  }
+
+  public synchronized long getClaimedOverdueConnectionCount() {
+    return claimedOverdueConnectionCount;
+  }
+
+  public synchronized long getAverageOverdueCheckoutTime() {
+    return claimedOverdueConnectionCount == 0 ? 0 : accumulatedCheckoutTimeOfOverdueConnections / claimedOverdueConnectionCount;
+  }
+
+  public synchronized long getAverageCheckoutTime() {
+    return requestCount == 0 ? 0 : accumulatedCheckoutTime / requestCount;
+  }
+
+
+  public synchronized int getIdleConnectionCount() {
+    return idleConnections.size();
+  }
+
+  public synchronized int getActiveConnectionCount() {
+    return activeConnections.size();
+  }
+
+  public synchronized String toString() {
+    StringBuffer buffer = new StringBuffer();
+    buffer.append("\n===CONFINGURATION==============================================");
+    buffer.append("\n jdbcDriver                     ").append(dataSource.getJdbcDriver());
+    buffer.append("\n jdbcUrl                        ").append(dataSource.getJdbcUrl());
+    buffer.append("\n jdbcUsername                   ").append(dataSource.getJdbcUsername());
+    buffer.append("\n jdbcPassword                   ").append((dataSource.getJdbcPassword() == null ? "NULL" : "************"));
+    buffer.append("\n poolMaxActiveConnections       ").append(dataSource.poolMaximumActiveConnections);
+    buffer.append("\n poolMaxIdleConnections         ").append(dataSource.poolMaximumIdleConnections);
+    buffer.append("\n poolMaxCheckoutTime            ").append(dataSource.poolMaximumCheckoutTime);
+    buffer.append("\n poolTimeToWait                 ").append(dataSource.poolTimeToWait);
+    buffer.append("\n poolPingEnabled                ").append(dataSource.poolPingEnabled);
+    buffer.append("\n poolPingQuery                  ").append(dataSource.poolPingQuery);
+    buffer.append("\n poolPingConnectionsNotUsedFor  ").append(dataSource.poolPingConnectionsNotUsedFor);
+    buffer.append("\n ---STATUS-----------------------------------------------------");
+    buffer.append("\n activeConnections              ").append(getActiveConnectionCount());
+    buffer.append("\n idleConnections                ").append(getIdleConnectionCount());
+    buffer.append("\n requestCount                   ").append(getRequestCount());
+    buffer.append("\n averageRequestTime             ").append(getAverageRequestTime());
+    buffer.append("\n averageCheckoutTime            ").append(getAverageCheckoutTime());
+    buffer.append("\n claimedOverdue                 ").append(getClaimedOverdueConnectionCount());
+    buffer.append("\n averageOverdueCheckoutTime     ").append(getAverageOverdueCheckoutTime());
+    buffer.append("\n hadToWait                      ").append(getHadToWaitCount());
+    buffer.append("\n averageWaitTime                ").append(getAverageWaitTime());
+    buffer.append("\n badConnectionCount             ").append(getBadConnectionCount());
+    buffer.append("\n===============================================================");
+    return buffer.toString();
+  }
+
+}

Added: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/jdbc/PooledConnection.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/jdbc/PooledConnection.java?rev=690554&view=auto
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/jdbc/PooledConnection.java (added)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/jdbc/PooledConnection.java Sat Aug 30 12:03:51 2008
@@ -0,0 +1,237 @@
+package org.apache.ibatis.jdbc;
+
+import org.apache.ibatis.reflection.ExceptionUtil;
+
+import java.lang.reflect.*;
+import java.sql.*;
+import java.util.Map;
+
+class PooledConnection implements InvocationHandler {
+
+  private static final String CLOSE = "close";
+  private static final Class[] IFACES = new Class[]{Connection.class};
+
+  private int hashCode = 0;
+  private PooledDataSource dataSource;
+  private Connection realConnection;
+  private Connection proxyConnection;
+  private long checkoutTimestamp;
+  private long createdTimestamp;
+  private long lastUsedTimestamp;
+  private int connectionTypeCode;
+  private boolean valid;
+
+  /**
+   * Constructor for SimplePooledConnection that uses the Connection and PooledDataSource passed in
+   *
+   * @param connection - the connection that is to be presented as a pooled connection
+   * @param dataSource - the dataSource that the connection is from
+   */
+  public PooledConnection(Connection connection, PooledDataSource dataSource) {
+    this.hashCode = connection.hashCode();
+    this.realConnection = connection;
+    this.dataSource = dataSource;
+    this.createdTimestamp = System.currentTimeMillis();
+    this.lastUsedTimestamp = System.currentTimeMillis();
+    this.valid = true;
+
+    proxyConnection = (Connection) Proxy.newProxyInstance(Connection.class.getClassLoader(), IFACES, this);
+  }
+
+  /**
+   * Invalidates the connection
+   */
+  public void invalidate() {
+    valid = false;
+  }
+
+  /**
+   * Method to see if the connection is usable
+   *
+   * @return True if the connection is usable
+   */
+  public boolean isValid() {
+    return valid && realConnection != null && dataSource.pingConnection(this);
+  }
+
+  /**
+   * Getter for the *real* connection that this wraps
+   *
+   * @return The connection
+   */
+  public Connection getRealConnection() {
+    return realConnection;
+  }
+
+  /**
+   * Getter for the proxy for the connection
+   *
+   * @return The proxy
+   */
+  public Connection getProxyConnection() {
+    return proxyConnection;
+  }
+
+  /**
+   * Gets the hashcode of the real connection (or 0 if it is null)
+   *
+   * @return The hashcode of the real connection (or 0 if it is null)
+   */
+  public int getRealHashCode() {
+    if (realConnection == null) {
+      return 0;
+    } else {
+      return realConnection.hashCode();
+    }
+  }
+
+  /**
+   * Getter for the connection type (based on url + user + password)
+   *
+   * @return The connection type
+   */
+  public int getConnectionTypeCode() {
+    return connectionTypeCode;
+  }
+
+  /**
+   * Setter for the connection type
+   *
+   * @param connectionTypeCode - the connection type
+   */
+  public void setConnectionTypeCode(int connectionTypeCode) {
+    this.connectionTypeCode = connectionTypeCode;
+  }
+
+  /**
+   * Getter for the time that the connection was created
+   *
+   * @return The creation timestamp
+   */
+  public long getCreatedTimestamp() {
+    return createdTimestamp;
+  }
+
+  /**
+   * Setter for the time that the connection was created
+   *
+   * @param createdTimestamp - the timestamp
+   */
+  public void setCreatedTimestamp(long createdTimestamp) {
+    this.createdTimestamp = createdTimestamp;
+  }
+
+  /**
+   * Getter for the time that the connection was last used
+   *
+   * @return - the timestamp
+   */
+  public long getLastUsedTimestamp() {
+    return lastUsedTimestamp;
+  }
+
+  /**
+   * Setter for the time that the connection was last used
+   *
+   * @param lastUsedTimestamp - the timestamp
+   */
+  public void setLastUsedTimestamp(long lastUsedTimestamp) {
+    this.lastUsedTimestamp = lastUsedTimestamp;
+  }
+
+  /**
+   * Getter for the time since this connection was last used
+   *
+   * @return - the time since the last use
+   */
+  public long getTimeElapsedSinceLastUse() {
+    return System.currentTimeMillis() - lastUsedTimestamp;
+  }
+
+  /**
+   * Getter for the age of the connection
+   *
+   * @return the age
+   */
+  public long getAge() {
+    return System.currentTimeMillis() - createdTimestamp;
+  }
+
+  /**
+   * Getter for the timestamp that this connection was checked out
+   *
+   * @return the timestamp
+   */
+  public long getCheckoutTimestamp() {
+    return checkoutTimestamp;
+  }
+
+  /**
+   * Setter for the timestamp that this connection was checked out
+   *
+   * @param timestamp the timestamp
+   */
+  public void setCheckoutTimestamp(long timestamp) {
+    this.checkoutTimestamp = timestamp;
+  }
+
+  /**
+   * Getter for the time that this connection has been checked out
+   *
+   * @return the time
+   */
+  public long getCheckoutTime() {
+    return System.currentTimeMillis() - checkoutTimestamp;
+  }
+
+  public int hashCode() {
+    return hashCode;
+  }
+
+  /**
+   * Allows comparing this connection to another
+   *
+   * @param obj - the other connection to test for equality
+   * @see Object#equals(Object)
+   */
+  public boolean equals(Object obj) {
+    if (obj instanceof PooledConnection) {
+      return realConnection.hashCode() == (((PooledConnection) obj).realConnection.hashCode());
+    } else if (obj instanceof Connection) {
+      return hashCode == obj.hashCode();
+    } else {
+      return false;
+    }
+  }
+
+  /**
+   * Required for InvocationHandler implementation.
+   *
+   * @param proxy  - not used
+   * @param method - the method to be executed
+   * @param args   - the parameters to be passed to the method
+   * @see java.lang.reflect.InvocationHandler#invoke(Object, java.lang.reflect.Method, Object[])
+   */
+  public Object invoke(Object proxy, Method method, Object[] args)
+      throws Throwable {
+    String methodName = method.getName();
+    if (CLOSE.hashCode() == methodName.hashCode() && CLOSE.equals(methodName)) {
+      dataSource.pushConnection(this);
+      return null;
+    } else {
+      try {
+        return method.invoke(getValidConnection(), args);
+      } catch (Throwable t) {
+        throw ExceptionUtil.unwrapThrowable(t);
+      }
+    }
+  }
+
+  private Connection getValidConnection() {
+    if (!valid) {
+      throw new RuntimeException("Error accessing PooledConnection. Connection is invalid.");
+    }
+    return realConnection;
+  }
+
+}

Copied: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/jdbc/PooledDataSource.java (from r690527, ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/jdbc/SimpleDataSource.java)
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/jdbc/PooledDataSource.java?p2=ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/jdbc/PooledDataSource.java&p1=ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/jdbc/SimpleDataSource.java&r1=690527&r2=690554&rev=690554&view=diff
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/jdbc/SimpleDataSource.java (original)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/jdbc/PooledDataSource.java Sat Aug 30 12:03:51 2008
@@ -1,160 +1,105 @@
 package org.apache.ibatis.jdbc;
 
 import org.apache.ibatis.logging.*;
-import org.apache.ibatis.reflection.ExceptionUtil;
 
 import javax.sql.DataSource;
 import java.io.PrintWriter;
-import java.lang.reflect.*;
 import java.sql.*;
 import java.util.*;
 
 /**
  * This is a simple, synchronous, thread-safe database connection pool.
  */
-public class SimpleDataSource implements DataSource {
+public class PooledDataSource implements DataSource {
 
-  private static final Log log = LogFactory.getLog(SimpleDataSource.class);
+  private static final Log log = LogFactory.getLog(PooledDataSource.class);
 
-  private int expectedConnectionTypeCode;
+  private final PoolState state = new PoolState(this);
 
-  // FIELDS LOCKED BY POOL_LOCK
-  private final Object POOL_LOCK = new Object();
-  private List idleConnections = new ArrayList();
-  private List activeConnections = new ArrayList();
-  private long requestCount = 0;
-  private long accumulatedRequestTime = 0;
-  private long accumulatedCheckoutTime = 0;
-  private long claimedOverdueConnectionCount = 0;
-  private long accumulatedCheckoutTimeOfOverdueConnections = 0;
-  private long accumulatedWaitTime = 0;
-  private long hadToWaitCount = 0;
-  private long badConnectionCount = 0;
-
-  // REQUIRED CONFIGURATION FIELDS
-  private String jdbcDriver;
-  private String jdbcUrl;
-  private String jdbcUsername;
-  private String jdbcPassword;
+  private final UnpooledDataSource dataSource;
 
   // OPTIONAL CONFIGURATION FIELDS
-  private boolean jdbcDefaultAutoCommit = false;
-  private Properties jdbcDriverProperties;
-  private int poolMaximumActiveConnections = 10;
-  private int poolMaximumIdleConnections = 5;
-  private int poolMaximumCheckoutTime = 20000;
-  private int poolTimeToWait = 20000;
-  private String poolPingQuery = "NO PING QUERY SET";
-  private boolean poolPingEnabled = false;
-  private int poolPingConnectionsNotUsedFor = 0;
+  protected int poolMaximumActiveConnections = 10;
+  protected int poolMaximumIdleConnections = 5;
+  protected int poolMaximumCheckoutTime = 20000;
+  protected int poolTimeToWait = 20000;
+  protected String poolPingQuery = "NO PING QUERY SET";
+  protected boolean poolPingEnabled = false;
+  protected int poolPingConnectionsNotUsedFor = 0;
+
+  private int expectedConnectionTypeCode;
+
+  public PooledDataSource() {
+    dataSource = new UnpooledDataSource();
+  }
+
+  public PooledDataSource(String driver, String url, String username, String password) {
+    dataSource = new UnpooledDataSource(driver, url, username, password);
+  }
+
+  public PooledDataSource(String driver, String url, Properties driverProperties) {
+    dataSource = new UnpooledDataSource(driver, url, driverProperties);
+  }
+
+  public PooledDataSource(ClassLoader driverClassLoader, String driver, String url, String username, String password) {
+    dataSource = new UnpooledDataSource(driverClassLoader, driver, url, username, password);
+  }
+
+  public PooledDataSource(ClassLoader driverClassLoader, String driver, String url, Properties driverProperties) {
+    dataSource = new UnpooledDataSource(driverClassLoader, driver, url, driverProperties);
+  }
 
-  /**
-   * @see javax.sql.DataSource#getConnection()
-   */
   public Connection getConnection() throws SQLException {
-    return popConnection(jdbcUsername, jdbcPassword).getProxyConnection();
+    return popConnection(dataSource.getUsername(), dataSource.getPassword()).getProxyConnection();
   }
 
-  /**
-   * @see javax.sql.DataSource#getConnection(String, String)
-   */
   public Connection getConnection(String username, String password) throws SQLException {
     return popConnection(username, password).getProxyConnection();
   }
 
-  /**
-   * @see javax.sql.DataSource#setLoginTimeout(int)
-   */
   public void setLoginTimeout(int loginTimeout) throws SQLException {
     DriverManager.setLoginTimeout(loginTimeout);
   }
 
-  /**
-   * @see javax.sql.DataSource#getLoginTimeout()
-   */
   public int getLoginTimeout() throws SQLException {
     return DriverManager.getLoginTimeout();
   }
 
-  /**
-   * @see javax.sql.DataSource#setLogWriter(java.io.PrintWriter)
-   */
   public void setLogWriter(PrintWriter logWriter) throws SQLException {
     DriverManager.setLogWriter(logWriter);
   }
 
-  /**
-   * @see javax.sql.DataSource#getLogWriter()
-   */
   public PrintWriter getLogWriter() throws SQLException {
     return DriverManager.getLogWriter();
   }
 
-  /**
-   * Name of the JDBC driver class to be used.
-   *
-   * @param jdbcDriver The string name of the class
-   */
   public void setJdbcDriver(String jdbcDriver) {
-    this.jdbcDriver = jdbcDriver;
-    try {
-      Class driverType = Class.forName(jdbcDriver);
-      DriverManager.registerDriver((Driver) driverType.newInstance());
-    } catch (Exception e) {
-      throw new RuntimeException("Error setting driver on SimpleDataSource. Cause: " + e, e);
-    }
+    dataSource.setDriver(jdbcDriver);
     forceCloseAll();
   }
 
-  /**
-   * The JDBC URL to use.
-   *
-   * @param jdbcUrl The JDBC URL
-   */
   public void setJdbcUrl(String jdbcUrl) {
-    this.jdbcUrl = jdbcUrl;
+    dataSource.setUrl(jdbcUrl);
     forceCloseAll();
   }
 
-  /**
-   * The JDBC user name to use
-   *
-   * @param jdbcUsername The user name
-   */
   public void setJdbcUsername(String jdbcUsername) {
-    this.jdbcUsername = jdbcUsername;
+    dataSource.setUsername(jdbcUsername);
     forceCloseAll();
   }
 
-  /**
-   * The JDBC password to use
-   *
-   * @param jdbcPassword The password
-   */
   public void setJdbcPassword(String jdbcPassword) {
-    this.jdbcPassword = jdbcPassword;
+    dataSource.setPassword(jdbcPassword);
     forceCloseAll();
   }
 
-  /**
-   * Recommend leaving this false.  Basically disables transactions if set to true.
-   *
-   * @param jdbcDefaultAutoCommit
-   */
-
   public void setJdbcDefaultAutoCommit(boolean jdbcDefaultAutoCommit) {
-    this.jdbcDefaultAutoCommit = jdbcDefaultAutoCommit;
+    dataSource.setAutoCommit(jdbcDefaultAutoCommit);
     forceCloseAll();
   }
 
-  /**
-   * Use alternate connection initializer with properties that may be specific
-   * to your driver.
-   *
-   * @param driverProps The properties for your driver
-   */
   public void setJdbcDriverProperties(Properties driverProps) {
-    this.jdbcDriverProperties = driverProps;
+    dataSource.setDriverProperties(driverProps);
     forceCloseAll();
   }
 
@@ -231,27 +176,27 @@
   }
 
   public String getJdbcDriver() {
-    return jdbcDriver;
+    return dataSource.getDriver();
   }
 
   public String getJdbcUrl() {
-    return jdbcUrl;
+    return dataSource.getUrl();
   }
 
   public String getJdbcUsername() {
-    return jdbcUsername;
+    return dataSource.getUsername();
   }
 
   public String getJdbcPassword() {
-    return jdbcPassword;
+    return dataSource.getPassword();
   }
 
   public boolean isJdbcDefaultAutoCommit() {
-    return jdbcDefaultAutoCommit;
+    return dataSource.isAutoCommit();
   }
 
   public Properties getJdbcDriverProperties() {
-    return jdbcDriverProperties;
+    return dataSource.getDriverProperties();
   }
 
   public int getPoolMaximumActiveConnections() {
@@ -283,153 +228,14 @@
   }
 
   /**
-   * Getter for the number of connection requests made
-   *
-   * @return The number of connection requests made
-   */
-  public long getRequestCount() {
-    synchronized (POOL_LOCK) {
-      return requestCount;
-    }
-  }
-
-  /**
-   * Getter for the average time required to get a connection to the database
-   *
-   * @return The average time
-   */
-  public long getAverageRequestTime() {
-    synchronized (POOL_LOCK) {
-      return requestCount == 0 ? 0 : accumulatedRequestTime / requestCount;
-    }
-  }
-
-  /**
-   * Getter for the average time spent waiting for connections that were in use
-   *
-   * @return The average time
-   */
-  public long getAverageWaitTime() {
-    synchronized (POOL_LOCK) {
-      return hadToWaitCount == 0 ? 0 : accumulatedWaitTime / hadToWaitCount;
-    }
-  }
-
-  /**
-   * Getter for the number of requests that had to wait for connections that were in use
-   *
-   * @return The number of requests that had to wait
-   */
-  public long getHadToWaitCount() {
-    synchronized (POOL_LOCK) {
-      return hadToWaitCount;
-    }
-  }
-
-  /**
-   * Getter for the number of invalid connections that were found in the pool
-   *
-   * @return The number of invalid connections
-   */
-  public long getBadConnectionCount() {
-    synchronized (POOL_LOCK) {
-      return badConnectionCount;
-    }
-  }
-
-  /**
-   * Getter for the number of connections that were claimed before they were returned
-   *
-   * @return The number of connections
-   */
-  public long getClaimedOverdueConnectionCount() {
-    synchronized (POOL_LOCK) {
-      return claimedOverdueConnectionCount;
-    }
-  }
-
-  /**
-   * Getter for the average age of overdue connections
-   *
-   * @return The average age
-   */
-  public long getAverageOverdueCheckoutTime() {
-    synchronized (POOL_LOCK) {
-      return claimedOverdueConnectionCount == 0 ? 0 : accumulatedCheckoutTimeOfOverdueConnections / claimedOverdueConnectionCount;
-    }
-  }
-
-
-  /**
-   * Getter for the average age of a connection checkout
-   *
-   * @return The average age
-   */
-  public long getAverageCheckoutTime() {
-    synchronized (POOL_LOCK) {
-      return requestCount == 0 ? 0 : accumulatedCheckoutTime / requestCount;
-    }
-  }
-
-
-  public int getIdleConnectionCount() {
-    synchronized (POOL_LOCK) {
-      return idleConnections.size();
-    }
-  }
-
-  public int getActiveConnectionCount() {
-    synchronized (POOL_LOCK) {
-      return activeConnections.size();
-    }
-  }
-
-
-  /**
-   * Returns the status of the connection pool
-   *
-   * @return The status
-   */
-  public String getStatus() {
-    StringBuffer buffer = new StringBuffer();
-    buffer.append("\n===CONFINGURATION==============================================");
-    buffer.append("\n jdbcDriver                     ").append(jdbcDriver);
-    buffer.append("\n jdbcUrl                        ").append(jdbcUrl);
-    buffer.append("\n jdbcUsername                   ").append(jdbcUsername);
-    buffer.append("\n jdbcPassword                   ").append((jdbcPassword == null ? "NULL" : "************"));
-    buffer.append("\n poolMaxActiveConnections       ").append(poolMaximumActiveConnections);
-    buffer.append("\n poolMaxIdleConnections         ").append(poolMaximumIdleConnections);
-    buffer.append("\n poolMaxCheckoutTime            ").append(poolMaximumCheckoutTime);
-    buffer.append("\n poolTimeToWait                 ").append(poolTimeToWait);
-    buffer.append("\n poolPingEnabled                ").append(poolPingEnabled);
-    buffer.append("\n poolPingQuery                  ").append(poolPingQuery);
-    buffer.append("\n poolPingConnectionsNotUsedFor  ").append(poolPingConnectionsNotUsedFor);
-    buffer.append("\n ---STATUS-----------------------------------------------------");
-    synchronized (POOL_LOCK) {
-      buffer.append("\n activeConnections              ").append(getActiveConnectionCount());
-      buffer.append("\n idleConnections                ").append(getIdleConnectionCount());
-      buffer.append("\n requestCount                   ").append(getRequestCount());
-      buffer.append("\n averageRequestTime             ").append(getAverageRequestTime());
-      buffer.append("\n averageCheckoutTime            ").append(getAverageCheckoutTime());
-      buffer.append("\n claimedOverdue                 ").append(getClaimedOverdueConnectionCount());
-      buffer.append("\n averageOverdueCheckoutTime     ").append(getAverageOverdueCheckoutTime());
-      buffer.append("\n hadToWait                      ").append(getHadToWaitCount());
-      buffer.append("\n averageWaitTime                ").append(getAverageWaitTime());
-      buffer.append("\n badConnectionCount             ").append(getBadConnectionCount());
-    }
-    buffer.append("\n===============================================================");
-    return buffer.toString();
-  }
-
-  /**
    * Closes all active and idle connections in the pool
    */
   public void forceCloseAll() {
-    synchronized (POOL_LOCK) {
-      expectedConnectionTypeCode = assembleConnectionTypeCode(jdbcUrl, jdbcUsername, jdbcPassword);
-      for (int i = activeConnections.size(); i > 0; i--) {
+    synchronized (state) {
+      expectedConnectionTypeCode = assembleConnectionTypeCode(dataSource.getUrl(), dataSource.getUsername(), dataSource.getPassword());
+      for (int i = state.activeConnections.size(); i > 0; i--) {
         try {
-          SimplePooledConnection conn = (SimplePooledConnection) activeConnections.remove(i - 1);
+          PooledConnection conn = (PooledConnection) state.activeConnections.remove(i - 1);
           conn.invalidate();
 
           Connection realConn = conn.getRealConnection();
@@ -441,9 +247,9 @@
           // ignore
         }
       }
-      for (int i = idleConnections.size(); i > 0; i--) {
+      for (int i = state.idleConnections.size(); i > 0; i--) {
         try {
-          SimplePooledConnection conn = (SimplePooledConnection) idleConnections.remove(i - 1);
+          PooledConnection conn = (PooledConnection) state.idleConnections.remove(i - 1);
           conn.invalidate();
 
           Connection realConn = conn.getRealConnection();
@@ -457,36 +263,40 @@
       }
     }
     if (log.isDebugEnabled()) {
-      log.debug("SimpleDataSource forcefully closed/removed all connections.");
+      log.debug("PooledDataSource forcefully closed/removed all connections.");
     }
   }
 
+  public PoolState getPoolState() {
+    return state;
+  }
+
   private int assembleConnectionTypeCode(String url, String username, String password) {
     return ("" + url + username + password).hashCode();
   }
 
-  private void pushConnection(SimplePooledConnection conn)
+  protected void pushConnection(PooledConnection conn)
       throws SQLException {
 
-    synchronized (POOL_LOCK) {
-      activeConnections.remove(conn);
+    synchronized (state) {
+      state.activeConnections.remove(conn);
       if (conn.isValid()) {
-        if (idleConnections.size() < poolMaximumIdleConnections && conn.getConnectionTypeCode() == expectedConnectionTypeCode) {
-          accumulatedCheckoutTime += conn.getCheckoutTime();
+        if (state.idleConnections.size() < poolMaximumIdleConnections && conn.getConnectionTypeCode() == expectedConnectionTypeCode) {
+          state.accumulatedCheckoutTime += conn.getCheckoutTime();
           if (!conn.getRealConnection().getAutoCommit()) {
             conn.getRealConnection().rollback();
           }
-          SimplePooledConnection newConn = new SimplePooledConnection(conn.getRealConnection(), this);
-          idleConnections.add(newConn);
+          PooledConnection newConn = new PooledConnection(conn.getRealConnection(), this);
+          state.idleConnections.add(newConn);
           newConn.setCreatedTimestamp(conn.getCreatedTimestamp());
           newConn.setLastUsedTimestamp(conn.getLastUsedTimestamp());
           conn.invalidate();
           if (log.isDebugEnabled()) {
             log.debug("Returned connection " + newConn.getRealHashCode() + " to pool.");
           }
-          POOL_LOCK.notifyAll();
+          state.notifyAll();
         } else {
-          accumulatedCheckoutTime += conn.getCheckoutTime();
+          state.accumulatedCheckoutTime += conn.getCheckoutTime();
           if (!conn.getRealConnection().getAutoCommit()) {
             conn.getRealConnection().rollback();
           }
@@ -500,58 +310,49 @@
         if (log.isDebugEnabled()) {
           log.debug("A bad connection (" + conn.getRealHashCode() + ") attempted to return to the pool, discarding connection.");
         }
-        badConnectionCount++;
+        state.badConnectionCount++;
       }
     }
   }
 
-  private SimplePooledConnection popConnection(String username, String password)
+  private PooledConnection popConnection(String username, String password)
       throws SQLException {
     boolean countedWait = false;
-    SimplePooledConnection conn = null;
+    PooledConnection conn = null;
     long t = System.currentTimeMillis();
     int localBadConnectionCount = 0;
 
     while (conn == null) {
-      synchronized (POOL_LOCK) {
-        if (idleConnections.size() > 0) {
+      synchronized (state) {
+        if (state.idleConnections.size() > 0) {
           // Pool has available connection
-          conn = (SimplePooledConnection) idleConnections.remove(0);
+          conn = (PooledConnection) state.idleConnections.remove(0);
           if (log.isDebugEnabled()) {
             log.debug("Checked out connection " + conn.getRealHashCode() + " from pool.");
           }
         } else {
           // Pool does not have available connection
-          if (activeConnections.size() < poolMaximumActiveConnections) {
+          if (state.activeConnections.size() < poolMaximumActiveConnections) {
             // Can create new connection
-            if (jdbcDriverProperties != null) {
-              jdbcDriverProperties.put("user", jdbcUsername);
-              jdbcDriverProperties.put("password", jdbcPassword);
-              conn = new SimplePooledConnection(DriverManager.getConnection(jdbcUrl, jdbcDriverProperties), this);
-            } else {
-              conn = new SimplePooledConnection(DriverManager.getConnection(jdbcUrl, jdbcUsername, jdbcPassword), this);
-            }
+            conn = new PooledConnection(dataSource.getConnection(), this);
             Connection realConn = conn.getRealConnection();
-            if (realConn.getAutoCommit() != jdbcDefaultAutoCommit) {
-              realConn.setAutoCommit(jdbcDefaultAutoCommit);
-            }
             if (log.isDebugEnabled()) {
               log.debug("Created connection " + conn.getRealHashCode() + ".");
             }
           } else {
             // Cannot create new connection
-            SimplePooledConnection oldestActiveConnection = (SimplePooledConnection) activeConnections.get(0);
+            PooledConnection oldestActiveConnection = (PooledConnection) state.activeConnections.get(0);
             long longestCheckoutTime = oldestActiveConnection.getCheckoutTime();
             if (longestCheckoutTime > poolMaximumCheckoutTime) {
               // Can claim overdue connection
-              claimedOverdueConnectionCount++;
-              accumulatedCheckoutTimeOfOverdueConnections += longestCheckoutTime;
-              accumulatedCheckoutTime += longestCheckoutTime;
-              activeConnections.remove(oldestActiveConnection);
+              state.claimedOverdueConnectionCount++;
+              state.accumulatedCheckoutTimeOfOverdueConnections += longestCheckoutTime;
+              state.accumulatedCheckoutTime += longestCheckoutTime;
+              state.activeConnections.remove(oldestActiveConnection);
               if (!oldestActiveConnection.getRealConnection().getAutoCommit()) {
                 oldestActiveConnection.getRealConnection().rollback();
               }
-              conn = new SimplePooledConnection(oldestActiveConnection.getRealConnection(), this);
+              conn = new PooledConnection(oldestActiveConnection.getRealConnection(), this);
               oldestActiveConnection.invalidate();
               if (log.isDebugEnabled()) {
                 log.debug("Claimed overdue connection " + conn.getRealHashCode() + ".");
@@ -560,15 +361,15 @@
               // Must wait
               try {
                 if (!countedWait) {
-                  hadToWaitCount++;
+                  state.hadToWaitCount++;
                   countedWait = true;
                 }
                 if (log.isDebugEnabled()) {
                   log.debug("Waiting as long as " + poolTimeToWait + " milliseconds for connection.");
                 }
                 long wt = System.currentTimeMillis();
-                POOL_LOCK.wait(poolTimeToWait);
-                accumulatedWaitTime += System.currentTimeMillis() - wt;
+                state.wait(poolTimeToWait);
+                state.accumulatedWaitTime += System.currentTimeMillis() - wt;
               } catch (InterruptedException e) {
                 break;
               }
@@ -580,24 +381,24 @@
             if (!conn.getRealConnection().getAutoCommit()) {
               conn.getRealConnection().rollback();
             }
-            conn.setConnectionTypeCode(assembleConnectionTypeCode(jdbcUrl, username, password));
+            conn.setConnectionTypeCode(assembleConnectionTypeCode(dataSource.getUrl(), username, password));
             conn.setCheckoutTimestamp(System.currentTimeMillis());
             conn.setLastUsedTimestamp(System.currentTimeMillis());
-            activeConnections.add(conn);
-            requestCount++;
-            accumulatedRequestTime += System.currentTimeMillis() - t;
+            state.activeConnections.add(conn);
+            state.requestCount++;
+            state.accumulatedRequestTime += System.currentTimeMillis() - t;
           } else {
             if (log.isDebugEnabled()) {
               log.debug("A bad connection (" + conn.getRealHashCode() + ") was returned from the pool, getting another connection.");
             }
-            badConnectionCount++;
+            state.badConnectionCount++;
             localBadConnectionCount++;
             conn = null;
             if (localBadConnectionCount > (poolMaximumIdleConnections + 3)) {
               if (log.isDebugEnabled()) {
-                log.debug("SimpleDataSource: Could not get a good connection to the database.");
+                log.debug("PooledDataSource: Could not get a good connection to the database.");
               }
-              throw new SQLException("SimpleDataSource: Could not get a good connection to the database.");
+              throw new SQLException("PooledDataSource: Could not get a good connection to the database.");
             }
           }
         }
@@ -607,9 +408,9 @@
 
     if (conn == null) {
       if (log.isDebugEnabled()) {
-        log.debug("SimpleDataSource: Unknown severe error condition.  The connection pool returned a null connection.");
+        log.debug("PooledDataSource: Unknown severe error condition.  The connection pool returned a null connection.");
       }
-      throw new SQLException("SimpleDataSource: Unknown severe error condition.  The connection pool returned a null connection.");
+      throw new SQLException("PooledDataSource: Unknown severe error condition.  The connection pool returned a null connection.");
     }
 
     return conn;
@@ -621,7 +422,7 @@
    * @param conn - the connection to check
    * @return True if the connection is still usable
    */
-  private boolean pingConnection(SimplePooledConnection conn) {
+  protected boolean pingConnection(PooledConnection conn) {
     boolean result = true;
 
     try {
@@ -677,8 +478,8 @@
    * @return The 'real' connection
    */
   public static Connection unwrapConnection(Connection conn) {
-    if (conn instanceof SimplePooledConnection) {
-      return ((SimplePooledConnection) conn).getRealConnection();
+    if (conn instanceof PooledConnection) {
+      return ((PooledConnection) conn).getRealConnection();
     } else {
       return conn;
     }
@@ -688,399 +489,4 @@
     forceCloseAll();
   }
 
-  /**
-   * ---------------------------------------------------------------------------------------
-   * SimplePooledConnection
-   * ---------------------------------------------------------------------------------------
-   */
-  private static class SimplePooledConnection implements InvocationHandler {
-
-    private static final String CLOSE = "close";
-    private static final Class[] IFACES = new Class[]{Connection.class};
-
-    private int hashCode = 0;
-    private SimpleDataSource dataSource;
-    private Connection realConnection;
-    private Connection proxyConnection;
-    private long checkoutTimestamp;
-    private long createdTimestamp;
-    private long lastUsedTimestamp;
-    private int connectionTypeCode;
-    private boolean valid;
-
-    /**
-     * Constructor for SimplePooledConnection that uses the Connection and SimpleDataSource passed in
-     *
-     * @param connection - the connection that is to be presented as a pooled connection
-     * @param dataSource - the dataSource that the connection is from
-     */
-    public SimplePooledConnection(Connection connection, SimpleDataSource dataSource) {
-      this.hashCode = connection.hashCode();
-      this.realConnection = connection;
-      this.dataSource = dataSource;
-      this.createdTimestamp = System.currentTimeMillis();
-      this.lastUsedTimestamp = System.currentTimeMillis();
-      this.valid = true;
-
-      proxyConnection = (Connection) Proxy.newProxyInstance(Connection.class.getClassLoader(), IFACES, this);
-    }
-
-    /**
-     * Invalidates the connection
-     */
-    public void invalidate() {
-      valid = false;
-    }
-
-    /**
-     * Method to see if the connection is usable
-     *
-     * @return True if the connection is usable
-     */
-    public boolean isValid() {
-      return valid && realConnection != null && dataSource.pingConnection(this);
-    }
-
-    /**
-     * Getter for the *real* connection that this wraps
-     *
-     * @return The connection
-     */
-    public Connection getRealConnection() {
-      return realConnection;
-    }
-
-    /**
-     * Getter for the proxy for the connection
-     *
-     * @return The proxy
-     */
-    public Connection getProxyConnection() {
-      return proxyConnection;
-    }
-
-    /**
-     * Gets the hashcode of the real connection (or 0 if it is null)
-     *
-     * @return The hashcode of the real connection (or 0 if it is null)
-     */
-    public int getRealHashCode() {
-      if (realConnection == null) {
-        return 0;
-      } else {
-        return realConnection.hashCode();
-      }
-    }
-
-    /**
-     * Getter for the connection type (based on url + user + password)
-     *
-     * @return The connection type
-     */
-    public int getConnectionTypeCode() {
-      return connectionTypeCode;
-    }
-
-    /**
-     * Setter for the connection type
-     *
-     * @param connectionTypeCode - the connection type
-     */
-    public void setConnectionTypeCode(int connectionTypeCode) {
-      this.connectionTypeCode = connectionTypeCode;
-    }
-
-    /**
-     * Getter for the time that the connection was created
-     *
-     * @return The creation timestamp
-     */
-    public long getCreatedTimestamp() {
-      return createdTimestamp;
-    }
-
-    /**
-     * Setter for the time that the connection was created
-     *
-     * @param createdTimestamp - the timestamp
-     */
-    public void setCreatedTimestamp(long createdTimestamp) {
-      this.createdTimestamp = createdTimestamp;
-    }
-
-    /**
-     * Getter for the time that the connection was last used
-     *
-     * @return - the timestamp
-     */
-    public long getLastUsedTimestamp() {
-      return lastUsedTimestamp;
-    }
-
-    /**
-     * Setter for the time that the connection was last used
-     *
-     * @param lastUsedTimestamp - the timestamp
-     */
-    public void setLastUsedTimestamp(long lastUsedTimestamp) {
-      this.lastUsedTimestamp = lastUsedTimestamp;
-    }
-
-    /**
-     * Getter for the time since this connection was last used
-     *
-     * @return - the time since the last use
-     */
-    public long getTimeElapsedSinceLastUse() {
-      return System.currentTimeMillis() - lastUsedTimestamp;
-    }
-
-    /**
-     * Getter for the age of the connection
-     *
-     * @return the age
-     */
-    public long getAge() {
-      return System.currentTimeMillis() - createdTimestamp;
-    }
-
-    /**
-     * Getter for the timestamp that this connection was checked out
-     *
-     * @return the timestamp
-     */
-    public long getCheckoutTimestamp() {
-      return checkoutTimestamp;
-    }
-
-    /**
-     * Setter for the timestamp that this connection was checked out
-     *
-     * @param timestamp the timestamp
-     */
-    public void setCheckoutTimestamp(long timestamp) {
-      this.checkoutTimestamp = timestamp;
-    }
-
-    /**
-     * Getter for the time that this connection has been checked out
-     *
-     * @return the time
-     */
-    public long getCheckoutTime() {
-      return System.currentTimeMillis() - checkoutTimestamp;
-    }
-
-    private Connection getValidConnection() {
-      if (!valid) {
-        throw new RuntimeException("Error accessing SimplePooledConnection. Connection is invalid.");
-      }
-      return realConnection;
-    }
-
-    public int hashCode() {
-      return hashCode;
-    }
-
-    /**
-     * Allows comparing this connection to another
-     *
-     * @param obj - the other connection to test for equality
-     * @see Object#equals(Object)
-     */
-    public boolean equals(Object obj) {
-      if (obj instanceof SimplePooledConnection) {
-        return realConnection.hashCode() == (((SimplePooledConnection) obj).realConnection.hashCode());
-      } else if (obj instanceof Connection) {
-        return hashCode == obj.hashCode();
-      } else {
-        return false;
-      }
-    }
-
-    // **********************************
-    // Implemented Connection Methods -- Now handled by proxy
-    // **********************************
-
-    /**
-     * Required for InvocationHandler implementation.
-     *
-     * @param proxy  - not used
-     * @param method - the method to be executed
-     * @param args   - the parameters to be passed to the method
-     * @see java.lang.reflect.InvocationHandler#invoke(Object, java.lang.reflect.Method, Object[])
-     */
-    public Object invoke(Object proxy, Method method, Object[] args)
-        throws Throwable {
-      String methodName = method.getName();
-      if (CLOSE.hashCode() == methodName.hashCode() && CLOSE.equals(methodName)) {
-        dataSource.pushConnection(this);
-        return null;
-      } else {
-        try {
-          return method.invoke(getValidConnection(), args);
-        } catch (Throwable t) {
-          throw ExceptionUtil.unwrapThrowable(t);
-        }
-      }
-    }
-
-    public Statement createStatement() throws SQLException {
-      return getValidConnection().createStatement();
-    }
-
-    public PreparedStatement prepareStatement(String sql) throws SQLException {
-      return getValidConnection().prepareStatement(sql);
-    }
-
-    public CallableStatement prepareCall(String sql) throws SQLException {
-      return getValidConnection().prepareCall(sql);
-    }
-
-    public String nativeSQL(String sql) throws SQLException {
-      return getValidConnection().nativeSQL(sql);
-    }
-
-    public void setAutoCommit(boolean autoCommit) throws SQLException {
-      getValidConnection().setAutoCommit(autoCommit);
-    }
-
-    public boolean getAutoCommit() throws SQLException {
-      return getValidConnection().getAutoCommit();
-    }
-
-    public void commit() throws SQLException {
-      getValidConnection().commit();
-    }
-
-    public void rollback() throws SQLException {
-      getValidConnection().rollback();
-    }
-
-    public void close() throws SQLException {
-      dataSource.pushConnection(this);
-    }
-
-    public boolean isClosed() throws SQLException {
-      return getValidConnection().isClosed();
-    }
-
-    public DatabaseMetaData getMetaData() throws SQLException {
-      return getValidConnection().getMetaData();
-    }
-
-    public void setReadOnly(boolean readOnly) throws SQLException {
-      getValidConnection().setReadOnly(readOnly);
-    }
-
-    public boolean isReadOnly() throws SQLException {
-      return getValidConnection().isReadOnly();
-    }
-
-    public void setCatalog(String catalog) throws SQLException {
-      getValidConnection().setCatalog(catalog);
-    }
-
-    public String getCatalog() throws SQLException {
-      return getValidConnection().getCatalog();
-    }
-
-    public void setTransactionIsolation(int level) throws SQLException {
-      getValidConnection().setTransactionIsolation(level);
-    }
-
-    public int getTransactionIsolation() throws SQLException {
-      return getValidConnection().getTransactionIsolation();
-    }
-
-    public SQLWarning getWarnings() throws SQLException {
-      return getValidConnection().getWarnings();
-    }
-
-    public void clearWarnings() throws SQLException {
-      getValidConnection().clearWarnings();
-    }
-
-    public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
-      return getValidConnection().createStatement(resultSetType, resultSetConcurrency);
-    }
-
-    public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
-      return getValidConnection().prepareCall(sql, resultSetType, resultSetConcurrency);
-    }
-
-    public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
-      return getValidConnection().prepareCall(sql, resultSetType, resultSetConcurrency);
-    }
-
-    public Map getTypeMap() throws SQLException {
-      return getValidConnection().getTypeMap();
-    }
-
-    public void setTypeMap(Map map) throws SQLException {
-      getValidConnection().setTypeMap(map);
-    }
-
-    // **********************************
-    // JDK 1.4 JDBC 3.0 Methods below
-    // **********************************
-
-    public void setHoldability(int holdability) throws SQLException {
-      getValidConnection().setHoldability(holdability);
-    }
-
-    public int getHoldability() throws SQLException {
-      return getValidConnection().getHoldability();
-    }
-
-    public Savepoint setSavepoint() throws SQLException {
-      return getValidConnection().setSavepoint();
-    }
-
-    public Savepoint setSavepoint(String name) throws SQLException {
-      return getValidConnection().setSavepoint(name);
-    }
-
-    public void rollback(Savepoint savepoint) throws SQLException {
-      getValidConnection().rollback(savepoint);
-    }
-
-    public void releaseSavepoint(Savepoint savepoint) throws SQLException {
-      getValidConnection().releaseSavepoint(savepoint);
-    }
-
-    public Statement createStatement(int resultSetType, int resultSetConcurrency,
-                                     int resultSetHoldability) throws SQLException {
-      return getValidConnection().createStatement(resultSetType, resultSetConcurrency, resultSetHoldability);
-    }
-
-    public PreparedStatement prepareStatement(String sql, int resultSetType,
-                                              int resultSetConcurrency, int resultSetHoldability)
-        throws SQLException {
-      return getValidConnection().prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
-    }
-
-    public CallableStatement prepareCall(String sql, int resultSetType,
-                                         int resultSetConcurrency,
-                                         int resultSetHoldability) throws SQLException {
-      return getValidConnection().prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
-    }
-
-    public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)
-        throws SQLException {
-      return getValidConnection().prepareStatement(sql, autoGeneratedKeys);
-    }
-
-    public PreparedStatement prepareStatement(String sql, int columnIndexes[])
-        throws SQLException {
-      return getValidConnection().prepareStatement(sql, columnIndexes);
-    }
-
-    public PreparedStatement prepareStatement(String sql, String columnNames[])
-        throws SQLException {
-      return getValidConnection().prepareStatement(sql, columnNames);
-    }
-
-
-  }
 }

Copied: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/jdbc/UnpooledDataSource.java (from r690527, ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/jdbc/DriverManagerDataSource.java)
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/jdbc/UnpooledDataSource.java?p2=ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/jdbc/UnpooledDataSource.java&p1=ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/jdbc/DriverManagerDataSource.java&r1=690527&r2=690554&rev=690554&view=diff
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/jdbc/DriverManagerDataSource.java (original)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/jdbc/UnpooledDataSource.java Sat Aug 30 12:03:51 2008
@@ -2,39 +2,72 @@
 
 import javax.sql.DataSource;
 import java.io.PrintWriter;
-import java.sql.Connection;
-import java.sql.Driver;
-import java.sql.DriverManager;
-import java.sql.SQLException;
+import java.sql.*;
 import java.util.Properties;
 
-public class DriverManagerDataSource implements DataSource {
-
-  private String jdbcDriver;
-  private String jdbcUrl;
-  private String jdbcUsername;
-  private String jdbcPassword;
+public class UnpooledDataSource implements DataSource {
 
   private ClassLoader driverClassLoader;
+  private Properties driverProperties;
+  private boolean driverInitialized;
 
-  private boolean jdbcDefaultAutoCommit;
-  private Properties jdbcDriverProperties;
+  private String driver;
+  private String url;
+  private String username;
+  private String password;
 
-  private boolean driverInitialized;
+  private boolean autoCommit;
+
+  public UnpooledDataSource() {
+  }
+
+  public UnpooledDataSource(String driver, String url, String username, String password) {
+    this.driver = driver;
+    this.url = url;
+    this.username = username;
+    this.password = password;
+  }
+
+  public UnpooledDataSource(String driver, String url, Properties driverProperties) {
+    this.driver = driver;
+    this.url = url;
+    this.driverProperties = driverProperties;
+  }
+
+  public UnpooledDataSource(ClassLoader driverClassLoader, String driver, String url, String username, String password) {
+    this.driverClassLoader = driverClassLoader;
+    this.driver = driver;
+    this.url = url;
+    this.username = username;
+    this.password = password;
+  }
+
+  public UnpooledDataSource(ClassLoader driverClassLoader, String driver, String url, Properties driverProperties) {
+    this.driverClassLoader = driverClassLoader;
+    this.driver = driver;
+    this.url = url;
+    this.driverProperties = driverProperties;
+  }
 
   public Connection getConnection() throws SQLException {
     initializeDriver();
-    if (jdbcDriverProperties != null) {
-      return DriverManager.getConnection(jdbcUrl, jdbcDriverProperties);
-    } else if (jdbcUsername == null && jdbcPassword == null) {
-      return DriverManager.getConnection(jdbcUrl);
+    Connection connection;
+    if (driverProperties != null) {
+      connection = DriverManager.getConnection(url, driverProperties);
+    } else if (username == null && password == null) {
+      connection = DriverManager.getConnection(url);
     } else {
-      return DriverManager.getConnection(jdbcUrl, jdbcUsername, jdbcPassword);
+      connection = DriverManager.getConnection(url, username, password);
     }
+    configureAutoCommit(connection);
+    return connection;
   }
 
   public Connection getConnection(String username, String password) throws SQLException {
-    return DriverManager.getConnection(jdbcUrl, username, password);
+    initializeDriver();
+    Connection connection = DriverManager.getConnection(url, username, password);
+    configureAutoCommit(connection);
+    return connection;
   }
 
   public void setLoginTimeout(int loginTimeout) throws SQLException {
@@ -61,69 +94,108 @@
     this.driverClassLoader = driverClassLoader;
   }
 
-  public String getJdbcDriver() {
-    return jdbcDriver;
+  public Properties getDriverProperties() {
+    return driverProperties;
   }
 
-  public void setJdbcDriver(String jdbcDriver) {
-    this.jdbcDriver = jdbcDriver;
+  public void setDriverProperties(Properties driverProperties) {
+    this.driverProperties = driverProperties;
   }
 
-  public String getJdbcUrl() {
-    return jdbcUrl;
+  public String getDriver() {
+    return driver;
   }
 
-  public void setJdbcUrl(String jdbcUrl) {
-    this.jdbcUrl = jdbcUrl;
+  public synchronized void setDriver(String driver) {
+    this.driver = driver;
+    driverInitialized = false;
   }
 
-  public String getJdbcUsername() {
-    return jdbcUsername;
+  public String getUrl() {
+    return url;
   }
 
-  public void setJdbcUsername(String jdbcUsername) {
-    this.jdbcUsername = jdbcUsername;
+  public void setUrl(String url) {
+    this.url = url;
   }
 
-  public String getJdbcPassword() {
-    return jdbcPassword;
+  public String getUsername() {
+    return username;
   }
 
-  public void setJdbcPassword(String jdbcPassword) {
-    this.jdbcPassword = jdbcPassword;
+  public void setUsername(String username) {
+    this.username = username;
   }
 
-  public boolean isJdbcDefaultAutoCommit() {
-    return jdbcDefaultAutoCommit;
+  public String getPassword() {
+    return password;
   }
 
-  public void setJdbcDefaultAutoCommit(boolean jdbcDefaultAutoCommit) {
-    this.jdbcDefaultAutoCommit = jdbcDefaultAutoCommit;
+  public void setPassword(String password) {
+    this.password = password;
   }
 
-  public Properties getJdbcDriverProperties() {
-    return jdbcDriverProperties;
+  public boolean isAutoCommit() {
+    return autoCommit;
   }
 
-  public void setJdbcDriverProperties(Properties jdbcDriverProperties) {
-    this.jdbcDriverProperties = jdbcDriverProperties;
+  public void setAutoCommit(boolean autoCommit) {
+    this.autoCommit = autoCommit;
   }
 
-  private void initializeDriver() {
+  private void configureAutoCommit(Connection conn) throws SQLException {
+    if (autoCommit != conn.getAutoCommit()) {
+      conn.setAutoCommit(autoCommit);
+    }
+  }
+
+  private synchronized void initializeDriver() {
     if (!driverInitialized) {
       driverInitialized = true;
       Class driverType;
       try {
         if (driverClassLoader != null) {
-          driverType = Class.forName(jdbcDriver, true, driverClassLoader);
+          driverType = Class.forName(driver, true, driverClassLoader);
         } else {
-          driverType = Class.forName(jdbcDriver);
+          driverType = Class.forName(driver);
         }
-        DriverManager.registerDriver((Driver) driverType.newInstance());
+        DriverManager.registerDriver(new DriverProxy((Driver) driverType.newInstance()));
       } catch (Exception e) {
-        throw new RuntimeException("Error setting driver on SimpleDataSource. Cause: " + e, e);
+        throw new RuntimeException("Error setting driver on UnpooledDataSource. Cause: " + e, e);
       }
     }
   }
 
+  private static class DriverProxy implements Driver {
+    private Driver driver;
+
+    DriverProxy(Driver d) {
+      this.driver = d;
+    }
+
+    public boolean acceptsURL(String u) throws SQLException {
+      return this.driver.acceptsURL(u);
+    }
+
+    public Connection connect(String u, Properties p) throws SQLException {
+      return this.driver.connect(u, p);
+    }
+
+    public int getMajorVersion() {
+      return this.driver.getMajorVersion();
+    }
+
+    public int getMinorVersion() {
+      return this.driver.getMinorVersion();
+    }
+
+    public DriverPropertyInfo[] getPropertyInfo(String u, Properties p) throws SQLException {
+      return this.driver.getPropertyInfo(u, p);
+    }
+
+    public boolean jdbcCompliant() {
+      return this.driver.jdbcCompliant();
+    }
+  }
+
 }

Copied: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/Null.java (from r690527, ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/adhoc/Null.java)
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/Null.java?p2=ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/Null.java&p1=ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/adhoc/Null.java&r1=690527&r2=690554&rev=690554&view=diff
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/adhoc/Null.java (original)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/Null.java Sat Aug 30 12:03:51 2008
@@ -1,4 +1,4 @@
-package org.apache.ibatis.adhoc;
+package org.apache.ibatis.migration;
 
 import org.apache.ibatis.type.*;
 

Modified: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/ScriptRunner.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/ScriptRunner.java?rev=690554&r1=690553&r2=690554&view=diff
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/ScriptRunner.java (original)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/ScriptRunner.java Sat Aug 30 12:03:51 2008
@@ -1,19 +1,13 @@
 package org.apache.ibatis.migration;
 
-
 import java.io.*;
 import java.sql.*;
-import java.util.Properties;
 
 public class ScriptRunner {
 
   private static final String DEFAULT_DELIMITER = ";";
 
   private Connection connection;
-  private String driver;
-  private String url;
-  private String username;
-  private String password;
 
   private boolean stopOnError;
   private boolean autoCommit;
@@ -23,30 +17,17 @@
 
   private String delimiter = DEFAULT_DELIMITER;
   private boolean fullLineDelimiter = false;
-  private ClassLoader driverClassLoader;
 
-  public ScriptRunner(Connection connection, boolean autoCommit, boolean stopOnError) {
+  public ScriptRunner(Connection connection) {
     this.connection = connection;
-    this.autoCommit = autoCommit;
-    this.stopOnError = stopOnError;
   }
 
-  public ScriptRunner(String driver, String url, String username, String password, boolean autoCommit, boolean stopOnError) {
-    this.driver = driver;
-    this.url = url;
-    this.username = username;
-    this.password = password;
-    this.autoCommit = autoCommit;
+  public void setStopOnError(boolean stopOnError) {
     this.stopOnError = stopOnError;
   }
 
-  public void setDriverClassLoader(ClassLoader loader) {
-    driverClassLoader = loader;
-  }
-
-  public void setDelimiter(String delimiter, boolean fullLineDelimiter) {
-    this.delimiter = delimiter;
-    this.fullLineDelimiter = fullLineDelimiter;
+  public void setAutoCommit(boolean autoCommit) {
+    this.autoCommit = autoCommit;
   }
 
   public void setLogWriter(PrintWriter logWriter) {
@@ -57,54 +38,27 @@
     this.errorLogWriter = errorLogWriter;
   }
 
+  public void setDelimiter(String delimiter) {
+    this.delimiter = delimiter;
+  }
+
+  public void setFullLineDelimiter(boolean fullLineDelimiter) {
+    this.fullLineDelimiter = fullLineDelimiter;
+  }
+
   public void runScript(Reader reader) throws IOException, SQLException {
     try {
-      if (connection != null) {
-        configureAutoCommitAndRun(reader);
-      } else {
-        initConnection();
-        try {
-          configureAutoCommitAndRun(reader);
-        } finally {
-          try {
-            connection.close();
-          } finally {
-            connection = null;
-          }
-        }
-      }
-    } catch (IOException e) {
-      throw e;
-    } catch (SQLException e) {
-      throw e;
-    } catch (Exception e) {
-      throw new RuntimeException("Error running script.  Cause: " + e, e);
+      runScriptWithConnection(connection, reader);
     } finally {
       flush();
     }
   }
 
-  private void initConnection() throws ClassNotFoundException, SQLException, InstantiationException, IllegalAccessException {
-    Class driverType;
-    if (driverClassLoader != null) {
-      driverType = Class.forName(driver, true, driverClassLoader);
-    } else {
-      driverType = Class.forName(driver);
-    }
-    Driver driverInstance = (Driver) driverType.newInstance();
-    DriverManager.registerDriver(new DriverProxy(driverInstance));
-    connection = DriverManager.getConnection(url, username, password);
-  }
-
-  private void configureAutoCommitAndRun(Reader reader) throws SQLException, IOException {
-    boolean originalAutoCommit = connection.getAutoCommit();
+  public void closeConnection() {
     try {
-      if (originalAutoCommit != this.autoCommit) {
-        connection.setAutoCommit(this.autoCommit);
-      }
-      runScriptWithConnection(connection, reader);
-    } finally {
-      connection.setAutoCommit(originalAutoCommit);
+      connection.close();
+    } catch(Exception e) {
+      // ignore
     }
   }
 
@@ -131,9 +85,9 @@
           // do nothing
         } else if (trimmedLine.startsWith("//") || trimmedLine.startsWith("--")) {
           println(trimmedLine);
-        } else if (!fullLineDelimiter && trimmedLine.endsWith(getDelimiter())
-            || fullLineDelimiter && trimmedLine.equals(getDelimiter())) {
-          command.append(line.substring(0, line.lastIndexOf(getDelimiter())));
+        } else if (!fullLineDelimiter && trimmedLine.endsWith(delimiter)
+            || fullLineDelimiter && trimmedLine.equals(delimiter)) {
+          command.append(line.substring(0, line.lastIndexOf(delimiter)));
           command.append(" ");
           Statement statement = conn.createStatement();
 
@@ -188,7 +142,7 @@
           command.append(" ");
         }
       }
-      if (!autoCommit) {
+      if (!autoCommit && !conn.getAutoCommit()) {
         conn.commit();
       }
     } catch (SQLException e) {
@@ -207,10 +161,6 @@
     }
   }
 
-  private String getDelimiter() {
-    return delimiter;
-  }
-
   private void print(Object o) {
     if (logWriter != null) {
       logWriter.print(o);
@@ -238,36 +188,4 @@
     }
   }
 
-  private static class DriverProxy implements Driver {
-    private Driver driver;
-
-    DriverProxy(Driver d) {
-      this.driver = d;
-    }
-
-    public boolean acceptsURL(String u) throws SQLException {
-      return this.driver.acceptsURL(u);
-    }
-
-    public Connection connect(String u, Properties p) throws SQLException {
-      return this.driver.connect(u, p);
-    }
-
-    public int getMajorVersion() {
-      return this.driver.getMajorVersion();
-    }
-
-    public int getMinorVersion() {
-      return this.driver.getMinorVersion();
-    }
-
-    public DriverPropertyInfo[] getPropertyInfo(String u, Properties p) throws SQLException {
-      return this.driver.getPropertyInfo(u, p);
-    }
-
-    public boolean jdbcCompliant() {
-      return this.driver.jdbcCompliant();
-    }
-  }
-
 }

Copied: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/SqlRunner.java (from r690527, ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/adhoc/AdHocExecutor.java)
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/SqlRunner.java?p2=ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/SqlRunner.java&p1=ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/adhoc/AdHocExecutor.java&r1=690527&r2=690554&rev=690554&view=diff
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/adhoc/AdHocExecutor.java (original)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/SqlRunner.java Sat Aug 30 12:03:51 2008
@@ -1,11 +1,13 @@
-package org.apache.ibatis.adhoc;
+package org.apache.ibatis.migration;
 
 import org.apache.ibatis.type.*;
+import org.apache.ibatis.migration.Null;
+import org.apache.ibatis.jdbc.UnpooledDataSource;
 
 import java.sql.*;
 import java.util.*;
 
-public class AdHocExecutor {
+public class SqlRunner {
 
   public static final int NO_GENERATED_KEY = Integer.MIN_VALUE + 1001;
 
@@ -13,43 +15,16 @@
   private TypeHandlerRegistry typeHandlerRegistry;
   private boolean forceGeneratedKeySupport = false;
 
-  public AdHocExecutor(Connection connection) {
+  public SqlRunner(Connection connection) {
     this(connection, false);
   }
 
-  public AdHocExecutor(Connection connection, boolean forceGeneratedKeySupport) {
+  public SqlRunner(Connection connection, boolean forceGeneratedKeySupport) {
     this.connection = connection;
     this.typeHandlerRegistry = new TypeHandlerRegistry();
     this.forceGeneratedKeySupport = forceGeneratedKeySupport;
   }
 
-  public AdHocExecutor(String driver, String url, String username, String password) {
-    this(driver,url,username,password,false,null);  
-  }
-
-  public AdHocExecutor(String driver, String url, String username, String password, boolean forceGeneratedKeySupport) {
-    this(driver,url,username,password,forceGeneratedKeySupport,null);
-  }
-
-  public AdHocExecutor(String driver, String url, String username, String password, boolean forceGeneratedKeySupport, ClassLoader driverClassLoader) {
-    try {
-      Class driverType;
-      if (driverClassLoader != null) {
-        driverType = Class.forName(driver, true, driverClassLoader);
-      } else {
-        driverType = Class.forName(driver);
-      }
-      Driver driverInstance = (Driver) driverType.newInstance();
-      DriverProxy driverProxy = new DriverProxy(driverInstance);
-      DriverManager.registerDriver(driverProxy);
-      connection = DriverManager.getConnection(url, username, password);
-      this.typeHandlerRegistry = new TypeHandlerRegistry();
-      this.forceGeneratedKeySupport = forceGeneratedKeySupport;
-    } catch (Exception e) {
-      throw new RuntimeException("Error configuring AdHocExecutor.  Cause: " + e, e);
-    }
-  }
-
   /**
    * Executes a SELECT statement that returns one row.
    *
@@ -193,13 +168,13 @@
   private void setParameters(PreparedStatement ps, Object... args) throws SQLException {
     for (int i = 0, n = args.length; i < n; i++) {
       if (args[i] == null) {
-        throw new SQLException("AdHocExecutor requires an instance of Null to represent typed null values for JDBC compatibility");
+        throw new SQLException("SqlRunner requires an instance of Null to represent typed null values for JDBC compatibility");
       } else if (args[i] instanceof Null) {
         ((Null) args[i]).getTypeHandler().setParameter(ps, i + 1, null, ((Null) args[i]).getJdbcType());
       } else {
         TypeHandler typeHandler = typeHandlerRegistry.getTypeHandler(args[i].getClass());
         if (typeHandler == null) {
-          throw new SQLException("AdHocExecutor could not find a TypeHandler instance for " + args[i].getClass());
+          throw new SQLException("SqlRunner could not find a TypeHandler instance for " + args[i].getClass());
         } else {
           typeHandler.setParameter(ps, i + 1, args[i], null);
         }
@@ -244,30 +219,5 @@
       }
     }
   }
-
-  private static class DriverProxy implements Driver {
-    private Driver driver;
-    DriverProxy(Driver d) {
-      this.driver = d;
-    }
-    public boolean acceptsURL(String u) throws SQLException {
-      return this.driver.acceptsURL(u);
-    }
-    public Connection connect(String u, Properties p) throws SQLException {
-      return this.driver.connect(u, p);
-    }
-    public int getMajorVersion() {
-      return this.driver.getMajorVersion();
-    }
-    public int getMinorVersion() {
-      return this.driver.getMinorVersion();
-    }
-    public DriverPropertyInfo[] getPropertyInfo(String u, Properties p) throws SQLException {
-      return this.driver.getPropertyInfo(u, p);
-    }
-    public boolean jdbcCompliant() {
-      return this.driver.jdbcCompliant();
-    }
-  }
   
 }

Modified: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/commands/BaseCommand.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/commands/BaseCommand.java?rev=690554&r1=690553&r2=690554&view=diff
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/commands/BaseCommand.java (original)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/commands/BaseCommand.java Sat Aug 30 12:03:51 2008
@@ -1,8 +1,9 @@
 package org.apache.ibatis.migration.commands;
 
-import org.apache.ibatis.adhoc.AdHocExecutor;
+import org.apache.ibatis.migration.SqlRunner;
 import org.apache.ibatis.io.Resources;
 import org.apache.ibatis.migration.*;
+import org.apache.ibatis.jdbc.UnpooledDataSource;
 
 import java.io.*;
 import java.math.BigDecimal;
@@ -51,9 +52,9 @@
   }
 
   protected List<Change> getChangelog() {
-    AdHocExecutor executor = getAdHocExecutor();
+    SqlRunner runner = getSqlRunner();
     try {
-      List<Map<String, Object>> changelog = executor.selectAll("select ID, APPLIED_AT, DESCRIPTION from "+changelogTable()+" order by id");
+      List<Map<String, Object>> changelog = runner.selectAll("select ID, APPLIED_AT, DESCRIPTION from "+changelogTable()+" order by id");
       List<Change> changes = new ArrayList<Change>();
       for (Map<String, Object> change : changelog) {
         String id = change.get("ID") == null ? null : change.get("ID").toString();
@@ -65,7 +66,7 @@
     } catch (SQLException e) {
       throw new MigrationException("Error querying last applied migration.  Cause: " + e, e);
     } finally {
-      executor.closeConnection();
+      runner.closeConnection();
     }
   }
 
@@ -83,14 +84,14 @@
   }
 
   protected boolean changelogExists() {
-    AdHocExecutor executor = getAdHocExecutor();
+    SqlRunner runner = getSqlRunner();
     try {
-      executor.selectAll("select ID, APPLIED_AT, DESCRIPTION from " + changelogTable());
+      runner.selectAll("select ID, APPLIED_AT, DESCRIPTION from " + changelogTable());
       return true;
     } catch (SQLException e) {
       return false;
     } finally {
-      executor.closeConnection();
+      runner.closeConnection();
     }
   }
 
@@ -144,15 +145,22 @@
     }
   }
 
-  protected AdHocExecutor getAdHocExecutor() {
-    lazyInitializeDrivers();
+  protected SqlRunner getSqlRunner() {
+    try {
+      lazyInitializeDrivers();
+
+      Properties props = environmentProperties();
+      String driver = props.getProperty("driver");
+      String url = props.getProperty("url");
+      String username = props.getProperty("username");
+      String password = props.getProperty("password");
 
-    Properties props = environmentProperties();
-    String driver = props.getProperty("driver");
-    String url = props.getProperty("url");
-    String username = props.getProperty("username");
-    String password = props.getProperty("password");
-    return new AdHocExecutor(driver, url, username, password, false, driverClassLoader);
+      UnpooledDataSource dataSource = new UnpooledDataSource(driverClassLoader, driver, url, username, password);
+      dataSource.setAutoCommit(true);
+      return new SqlRunner(dataSource.getConnection(), false);
+    } catch (SQLException e) {
+      throw new RuntimeException("Could not create SqlRunner. Cause: " + e, e);
+    }
   }
 
   protected ScriptRunner getScriptRunner() {
@@ -165,8 +173,11 @@
       String username = props.getProperty("username");
       String password = props.getProperty("password");
       PrintWriter outWriter = new PrintWriter(out);
-      ScriptRunner scriptRunner = new ScriptRunner(driver, url, username, password, false, !force);
-      scriptRunner.setDriverClassLoader(driverClassLoader);
+      UnpooledDataSource dataSource = new UnpooledDataSource(driverClassLoader, driver, url, username, password);
+      dataSource.setAutoCommit(false);
+      ScriptRunner scriptRunner = new ScriptRunner(dataSource.getConnection());
+      scriptRunner.setAutoCommit(true);
+      scriptRunner.setStopOnError(!force);
       scriptRunner.setLogWriter(outWriter);
       scriptRunner.setErrorLogWriter(outWriter);
       return scriptRunner;

Modified: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/commands/BootstrapCommand.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/commands/BootstrapCommand.java?rev=690554&r1=690553&r2=690554&view=diff
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/commands/BootstrapCommand.java (original)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/commands/BootstrapCommand.java Sat Aug 30 12:03:51 2008
@@ -19,7 +19,11 @@
         if (bootstrap.exists()) {
           out.println(horizontalLine("Applying: bootstrap.sql", 80));
           ScriptRunner runner = getScriptRunner();
-          runner.runScript(new MigrationReader(new FileReader(bootstrap), false, environmentProperties()));
+          try {
+            runner.runScript(new MigrationReader(new FileReader(bootstrap), false, environmentProperties()));
+          } finally {
+            runner.closeConnection();
+          }
         } else {
           out.println("Error, could not run bootstrap.sql.  The file does not exist.");
         }

Modified: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/commands/DownCommand.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/commands/DownCommand.java?rev=690554&r1=690553&r2=690554&view=diff
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/commands/DownCommand.java (original)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/commands/DownCommand.java Sat Aug 30 12:03:51 2008
@@ -1,6 +1,6 @@
 package org.apache.ibatis.migration.commands;
 
-import org.apache.ibatis.adhoc.AdHocExecutor;
+import org.apache.ibatis.migration.SqlRunner;
 import org.apache.ibatis.migration.*;
 
 import java.io.*;
@@ -22,7 +22,11 @@
         if (change.getId().equals(lastChange.getId())) {
           out.println(horizontalLine("Undoing: " + change.getFilename(), 80));
           ScriptRunner runner = getScriptRunner();
-          runner.runScript(new MigrationReader(new FileReader(scriptFile(change.getFilename())), true, environmentProperties()));
+          try {
+            runner.runScript(new MigrationReader(new FileReader(scriptFile(change.getFilename())), true, environmentProperties()));
+          } finally {
+            runner.closeConnection();
+          }
           if (changelogExists()) {
             deleteChange(change);
           } else {
@@ -37,13 +41,13 @@
   }
 
   protected void deleteChange(Change change) {
-    AdHocExecutor executor = getAdHocExecutor();
+    SqlRunner runner = getSqlRunner();
     try {
-      executor.delete("delete from " + changelogTable() + " where id = ?", change.getId());
+      runner.delete("delete from " + changelogTable() + " where id = ?", change.getId());
     } catch (SQLException e) {
       throw new MigrationException("Error querying last applied migration.  Cause: " + e, e);
     } finally {
-      executor.closeConnection();
+      runner.closeConnection();
     }
   }
 

Modified: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/commands/UpCommand.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/commands/UpCommand.java?rev=690554&r1=690553&r2=690554&view=diff
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/commands/UpCommand.java (original)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/migration/commands/UpCommand.java Sat Aug 30 12:03:51 2008
@@ -1,6 +1,6 @@
 package org.apache.ibatis.migration.commands;
 
-import org.apache.ibatis.adhoc.AdHocExecutor;
+import org.apache.ibatis.migration.SqlRunner;
 import org.apache.ibatis.migration.*;
 
 import java.io.*;
@@ -32,7 +32,11 @@
         if (lastChange == null || change.getId().compareTo(lastChange.getId()) > 0) {
           out.println(horizontalLine("Applying: " + change.getFilename(), 80));
           ScriptRunner runner = getScriptRunner();
-          runner.runScript(new MigrationReader(new FileReader(scriptFile(change.getFilename())), false, environmentProperties()));
+          try {
+            runner.runScript(new MigrationReader(new FileReader(scriptFile(change.getFilename())), false, environmentProperties()));
+          } finally {
+            runner.closeConnection();
+          }
           insertChangelog(change);
           if (runOneStepOnly) {
             break;
@@ -45,14 +49,14 @@
   }
 
   protected void insertChangelog(Change change) {
-    AdHocExecutor executor = getAdHocExecutor();
+    SqlRunner runner = getSqlRunner();
     change.setAppliedTimestamp(getAppliedTimestampAsString());
     try {
-      executor.insert("insert into " + changelogTable() + " (ID, APPLIED_AT, DESCRIPTION) values (?,?,?)", change.getId(), change.getAppliedTimestamp(), change.getDescription());
+      runner.insert("insert into " + changelogTable() + " (ID, APPLIED_AT, DESCRIPTION) values (?,?,?)", change.getId(), change.getAppliedTimestamp(), change.getDescription());
     } catch (SQLException e) {
       throw new MigrationException("Error querying last applied migration.  Cause: " + e, e);
     } finally {
-      executor.closeConnection();
+      runner.closeConnection();
     }
   }
 

Modified: ibatis/trunk/java/ibatis-3/ibatis-3-core/src/test/java/org/apache/ibatis/BaseDataTest.java
URL: http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/test/java/org/apache/ibatis/BaseDataTest.java?rev=690554&r1=690553&r2=690554&view=diff
==============================================================================
--- ibatis/trunk/java/ibatis-3/ibatis-3-core/src/test/java/org/apache/ibatis/BaseDataTest.java (original)
+++ ibatis/trunk/java/ibatis-3/ibatis-3-core/src/test/java/org/apache/ibatis/BaseDataTest.java Sat Aug 30 12:03:51 2008
@@ -1,7 +1,7 @@
 package org.apache.ibatis;
 
 import org.apache.ibatis.io.Resources;
-import org.apache.ibatis.jdbc.SimpleDataSource;
+import org.apache.ibatis.jdbc.PooledDataSource;
 import org.apache.ibatis.migration.ScriptRunner;
 import org.junit.Test;
 
@@ -20,9 +20,9 @@
   public static final String JPETSTORE_DDL = "databases/jpetstore/jpetstore-hsqldb-schema.sql";
   public static final String JPETSTORE_DATA = "databases/jpetstore/jpetstore-hsqldb-dataload.sql";
 
-  public static SimpleDataSource createSimpleDataSource(String resource) throws IOException {
+  public static PooledDataSource createPooledDataSource(String resource) throws IOException {
     Properties props = Resources.getResourceAsProperties(resource);
-    SimpleDataSource ds = new SimpleDataSource();
+    PooledDataSource ds = new PooledDataSource();
     ds.setJdbcDriver(props.getProperty("driver"));
     ds.setJdbcUrl(props.getProperty("url"));
     ds.setJdbcUsername(props.getProperty("username"));
@@ -33,7 +33,9 @@
   public static void runScript(DataSource ds, String resource) throws IOException, SQLException {
     Connection connection = ds.getConnection();
     try {
-      ScriptRunner runner = new ScriptRunner(connection, true, false);
+      ScriptRunner runner = new ScriptRunner(connection);
+      runner.setAutoCommit(true);
+      runner.setStopOnError(false);
       runner.setLogWriter(null);
       runScript(runner, resource);
     } finally {