Update the internal fork of Commons DBCP 2 to 2.4.0.

git-svn-id: https://svn.apache.org/repos/asf/tomcat/tc8.0.x/trunk@1833816 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/AbandonedTrace.java b/java/org/apache/tomcat/dbcp/dbcp2/AbandonedTrace.java
index 9345482..ea6d5a2 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/AbandonedTrace.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/AbandonedTrace.java
@@ -25,43 +25,43 @@
 import org.apache.tomcat.dbcp.pool2.TrackedUse;
 
 /**
- * Tracks db connection usage for recovering and reporting
- * abandoned db connections.
+ * Tracks db connection usage for recovering and reporting abandoned db connections.
+ * <p>
+ * The JDBC Connection, Statement, and ResultSet classes extend this class.
+ * </p>
  *
- * The JDBC Connection, Statement, and ResultSet classes
- * extend this class.
- *
- * @author Glenn L. Nielsen
  * @since 2.0
  */
 public class AbandonedTrace implements TrackedUse {
 
-    /** A list of objects created by children of this object */
+    /** A list of objects created by children of this object. */
     private final List<WeakReference<AbandonedTrace>> traceList = new ArrayList<>();
-    /** Last time this connection was used */
-    private volatile long lastUsed = 0;
+
+    /** Last time this connection was used. */
+    private volatile long lastUsedMillis = 0;
 
     /**
-     * Create a new AbandonedTrace without config and
-     * without doing abandoned tracing.
+     * Creates a new AbandonedTrace without config and without doing abandoned tracing.
      */
     public AbandonedTrace() {
         init(null);
     }
 
     /**
-     * Construct a new AbandonedTrace with a parent object.
+     * Constructs a new AbandonedTrace with a parent object.
      *
-     * @param parent AbandonedTrace parent object
+     * @param parent
+     *            AbandonedTrace parent object.
      */
     public AbandonedTrace(final AbandonedTrace parent) {
         init(parent);
     }
 
     /**
-     * Initialize abandoned tracing for this object.
+     * Initializes abandoned tracing for this object.
      *
-     * @param parent AbandonedTrace parent object
+     * @param parent
+     *            AbandonedTrace parent object.
      */
     private void init(final AbandonedTrace parent) {
         if (parent != null) {
@@ -70,37 +70,37 @@
     }
 
     /**
-     * Get the last time this object was used in ms.
+     * Gets the last time this object was used in milliseconds.
      *
-     * @return long time in ms
+     * @return long time in milliseconds.
      */
     @Override
     public long getLastUsed() {
-        return lastUsed;
+        return lastUsedMillis;
     }
 
     /**
-     * Set the time this object was last used to the
-     * current time in ms.
+     * Sets the time this object was last used to the current time in milliseconds.
      */
     protected void setLastUsed() {
-        lastUsed = System.currentTimeMillis();
+        lastUsedMillis = System.currentTimeMillis();
     }
 
     /**
-     * Set the time in ms this object was last used.
+     * Sets the time in milliseconds this object was last used.
      *
-     * @param time time in ms
+     * @param lastUsedMillis
+     *            time in milliseconds.
      */
-    protected void setLastUsed(final long time) {
-        lastUsed = time;
+    protected void setLastUsed(final long lastUsedMillis) {
+        this.lastUsedMillis = lastUsedMillis;
     }
 
     /**
-     * Add an object to the list of objects being
-     * traced.
+     * Adds an object to the list of objects being traced.
      *
-     * @param trace AbandonedTrace object to add
+     * @param trace
+     *            AbandonedTrace object to add.
      */
     protected void addTrace(final AbandonedTrace trace) {
         synchronized (this.traceList) {
@@ -110,19 +110,18 @@
     }
 
     /**
-     * Clear the list of objects being traced by this
-     * object.
+     * Clears the list of objects being traced by this object.
      */
     protected void clearTrace() {
-        synchronized(this.traceList) {
+        synchronized (this.traceList) {
             this.traceList.clear();
         }
     }
 
     /**
-     * Get a list of objects being traced by this object.
+     * Gets a list of objects being traced by this object.
      *
-     * @return List of objects
+     * @return List of objects.
      */
     protected List<AbandonedTrace> getTrace() {
         final int size = traceList.size();
@@ -133,12 +132,12 @@
         synchronized (this.traceList) {
             final Iterator<WeakReference<AbandonedTrace>> iter = traceList.iterator();
             while (iter.hasNext()) {
-                final WeakReference<AbandonedTrace> ref = iter.next();
-                if (ref.get() == null) {
+                final AbandonedTrace trace = iter.next().get();
+                if (trace == null) {
                     // Clean-up since we are here anyway
                     iter.remove();
                 } else {
-                    result.add(ref.get());
+                    result.add(trace);
                 }
             }
         }
@@ -146,19 +145,20 @@
     }
 
     /**
-     * Remove a child object this object is tracing.
+     * Removes a child object this object is tracing.
      *
-     * @param trace AbandonedTrace object to remove
+     * @param trace
+     *            AbandonedTrace object to remove.
      */
     protected void removeTrace(final AbandonedTrace trace) {
-        synchronized(this.traceList) {
+        synchronized (this.traceList) {
             final Iterator<WeakReference<AbandonedTrace>> iter = traceList.iterator();
             while (iter.hasNext()) {
-                final WeakReference<AbandonedTrace> ref = iter.next();
-                if (trace.equals(ref.get())) {
+                final AbandonedTrace traceInList = iter.next().get();
+                if (trace.equals(traceInList)) {
                     iter.remove();
                     break;
-                } else if (ref.get() == null) {
+                } else if (traceInList == null) {
                     // Clean-up since we are here anyway
                     iter.remove();
                 }
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSource.java b/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSource.java
index bd66fb0..3504d32 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSource.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSource.java
@@ -18,7 +18,6 @@
 
 import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
-import java.lang.management.ManagementFactory;
 import java.nio.charset.StandardCharsets;
 import java.security.AccessController;
 import java.security.PrivilegedActionException;
@@ -33,17 +32,14 @@
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Objects;
 import java.util.Properties;
 import java.util.Set;
 import java.util.logging.Logger;
 
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.JMException;
 import javax.management.MBeanRegistration;
-import javax.management.MBeanRegistrationException;
 import javax.management.MBeanServer;
 import javax.management.MalformedObjectNameException;
-import javax.management.NotCompliantMBeanException;
 import javax.management.ObjectName;
 import javax.sql.DataSource;
 
@@ -57,14 +53,12 @@
 import org.apache.tomcat.dbcp.pool2.impl.GenericObjectPoolConfig;
 
 /**
- * <p>Basic implementation of <code>javax.sql.DataSource</code> that is
- * configured via JavaBeans properties.  This is not the only way to
- * combine the <em>commons-dbcp2</em> and <em>commons-pool2</em> packages,
- * but provides a "one stop shopping" solution for basic requirements.</p>
+ * <p>
+ * Basic implementation of <code>javax.sql.DataSource</code> that is configured via JavaBeans properties. This is not
+ * the only way to combine the <em>commons-dbcp2</em> and <em>commons-pool2</em> packages, but provides a "one stop
+ * shopping" solution for basic requirements.
+ * </p>
  *
- * @author Glenn L. Nielsen
- * @author Craig R. McClanahan
- * @author Dirk Verbeeck
  * @since 2.0
  */
 public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBeanRegistration, AutoCloseable {
@@ -119,21 +113,22 @@
     }
 
     /**
-     * <p>Sets default auto-commit state of connections returned by this
-     * datasource.</p>
      * <p>
-     * Note: this method currently has no effect once the pool has been
-     * initialized.  The pool is initialized the first time one of the
-     * following methods is invoked: <code>getConnection, setLogwriter,
-     * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
+     * Sets default auto-commit state of connections returned by this datasource.
+     * </p>
+     * <p>
+     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
+     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+     * </p>
      *
-     * @param defaultAutoCommit default auto-commit value
+     * @param defaultAutoCommit
+     *            default auto-commit value
      */
     public void setDefaultAutoCommit(final Boolean defaultAutoCommit) {
         this.defaultAutoCommit = defaultAutoCommit;
     }
 
-
     /**
      * The default read-only state of connections created by this pool.
      */
@@ -150,14 +145,17 @@
     }
 
     /**
-     * <p>Sets defaultReadonly property.</p>
      * <p>
-     * Note: this method currently has no effect once the pool has been
-     * initialized.  The pool is initialized the first time one of the
-     * following methods is invoked: <code>getConnection, setLogwriter,
-     * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
+     * Sets defaultReadonly property.
+     * </p>
+     * <p>
+     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
+     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+     * </p>
      *
-     * @param defaultReadOnly default read-only value
+     * @param defaultReadOnly
+     *            default read-only value
      */
     public void setDefaultReadOnly(final Boolean defaultReadOnly) {
         this.defaultReadOnly = defaultReadOnly;
@@ -166,8 +164,7 @@
     /**
      * The default TransactionIsolation state of connections created by this pool.
      */
-    private volatile int defaultTransactionIsolation =
-        PoolableConnectionFactory.UNKNOWN_TRANSACTIONISOLATION;
+    private volatile int defaultTransactionIsolation = PoolableConnectionFactory.UNKNOWN_TRANSACTIONISOLATION;
 
     /**
      * Returns the default transaction isolation state of returned connections.
@@ -181,45 +178,46 @@
     }
 
     /**
-     * <p>Sets the default transaction isolation state for returned
-     * connections.</p>
      * <p>
-     * Note: this method currently has no effect once the pool has been
-     * initialized.  The pool is initialized the first time one of the
-     * following methods is invoked: <code>getConnection, setLogwriter,
-     * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
+     * Sets the default transaction isolation state for returned connections.
+     * </p>
+     * <p>
+     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
+     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+     * </p>
      *
-     * @param defaultTransactionIsolation the default transaction isolation
-     * state
+     * @param defaultTransactionIsolation
+     *            the default transaction isolation state
      * @see Connection#getTransactionIsolation
      */
     public void setDefaultTransactionIsolation(final int defaultTransactionIsolation) {
         this.defaultTransactionIsolation = defaultTransactionIsolation;
     }
 
-
-    private Integer defaultQueryTimeout;
+    private Integer defaultQueryTimeoutSeconds;
 
     /**
-     * Obtain the default query timeout that will be used for {@link java.sql.Statement Statement}s
-     * created from this connection. <code>null</code> means that the driver
-     * default will be used.
+     * Gets the default query timeout that will be used for {@link java.sql.Statement Statement}s created from this
+     * connection. <code>null</code> means that the driver default will be used.
+     *
+     * @return The default query timeout in seconds.
      */
     public Integer getDefaultQueryTimeout() {
-        return defaultQueryTimeout;
+        return defaultQueryTimeoutSeconds;
     }
 
-
     /**
-     * Set the default query timeout that will be used for {@link java.sql.Statement Statement}s
-     * created from this connection. <code>null</code> means that the driver
-     * default will be used.
+     * Sets the default query timeout that will be used for {@link java.sql.Statement Statement}s created from this
+     * connection. <code>null</code> means that the driver default will be used.
+     *
+     * @param defaultQueryTimeoutSeconds
+     *            The default query timeout in seconds.
      */
-    public void setDefaultQueryTimeout(final Integer defaultQueryTimeout) {
-        this.defaultQueryTimeout = defaultQueryTimeout;
+    public void setDefaultQueryTimeout(final Integer defaultQueryTimeoutSeconds) {
+        this.defaultQueryTimeoutSeconds = defaultQueryTimeoutSeconds;
     }
 
-
     /**
      * The default "catalog" of connections created by this pool.
      */
@@ -236,34 +234,36 @@
     }
 
     /**
-     * <p>Sets the default catalog.</p>
      * <p>
-     * Note: this method currently has no effect once the pool has been
-     * initialized.  The pool is initialized the first time one of the
-     * following methods is invoked: <code>getConnection, setLogwriter,
-     * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
+     * Sets the default catalog.
+     * </p>
+     * <p>
+     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
+     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+     * </p>
      *
-     * @param defaultCatalog the default catalog
+     * @param defaultCatalog
+     *            the default catalog
      */
     public void setDefaultCatalog(final String defaultCatalog) {
         if (defaultCatalog != null && defaultCatalog.trim().length() > 0) {
             this.defaultCatalog = defaultCatalog;
-        }
-        else {
+        } else {
             this.defaultCatalog = null;
         }
     }
 
     /**
-     * The property that controls if the pooled connections cache some state
-     * rather than query the database for current state to improve performance.
+     * The property that controls if the pooled connections cache some state rather than query the database for current
+     * state to improve performance.
      */
     private boolean cacheState = true;
 
     /**
      * Returns the state caching flag.
      *
-     * @return  the state caching flag
+     * @return the state caching flag
      */
     @Override
     public boolean getCacheState() {
@@ -273,7 +273,8 @@
     /**
      * Sets the state caching flag.
      *
-     * @param cacheState    The new value for the state caching flag
+     * @param cacheState
+     *            The new value for the state caching flag
      */
     public void setCacheState(final boolean cacheState) {
         this.cacheState = cacheState;
@@ -287,10 +288,9 @@
     /**
      * Returns the JDBC Driver that has been configured for use by this pool.
      * <p>
-     * Note: This getter only returns the last value set by a call to
-     * {@link #setDriver(Driver)}. It does not return any driver instance that
-     * may have been created from the value set via
-     * {@link #setDriverClassName(String)}.
+     * Note: This getter only returns the last value set by a call to {@link #setDriver(Driver)}. It does not return any
+     * driver instance that may have been created from the value set via {@link #setDriverClassName(String)}.
+     * </p>
      *
      * @return the JDBC Driver that has been configured for use by this pool
      */
@@ -301,12 +301,13 @@
     /**
      * Sets the JDBC Driver instance to use for this pool.
      * <p>
-     * Note: this method currently has no effect once the pool has been
-     * initialized.  The pool is initialized the first time one of the
-     * following methods is invoked: <code>getConnection, setLogwriter,
-     * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
+     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
+     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+     * </p>
      *
      * @param driver
+     *            The JDBC Driver instance to use for this pool.
      */
     public synchronized void setDriver(final Driver driver) {
         this.driver = driver;
@@ -320,9 +321,9 @@
     /**
      * Returns the JDBC driver class name.
      * <p>
-     * Note: This getter only returns the last value set by a call to
-     * {@link #setDriverClassName(String)}. It does not return the class name of
-     * any driver that may have been set via {@link #setDriver(Driver)}.
+     * Note: This getter only returns the last value set by a call to {@link #setDriverClassName(String)}. It does not
+     * return the class name of any driver that may have been set via {@link #setDriver(Driver)}.
+     * </p>
      *
      * @return the JDBC driver class name
      */
@@ -332,66 +333,67 @@
     }
 
     /**
-     * <p>Sets the JDBC driver class name.</p>
      * <p>
-     * Note: this method currently has no effect once the pool has been
-     * initialized.  The pool is initialized the first time one of the
-     * following methods is invoked: <code>getConnection, setLogwriter,
-     * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
+     * Sets the JDBC driver class name.
+     * </p>
+     * <p>
+     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
+     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+     * </p>
      *
-     * @param driverClassName the class name of the JDBC driver
+     * @param driverClassName
+     *            the class name of the JDBC driver
      */
     public synchronized void setDriverClassName(final String driverClassName) {
         if (driverClassName != null && driverClassName.trim().length() > 0) {
             this.driverClassName = driverClassName;
-        }
-        else {
+        } else {
             this.driverClassName = null;
         }
     }
 
     /**
-     * The class loader instance to use to load the JDBC driver. If not
-     * specified, {@link Class#forName(String)} is used to load the JDBC driver.
-     * If specified, {@link Class#forName(String, boolean, ClassLoader)} is
-     * used.
+     * The class loader instance to use to load the JDBC driver. If not specified, {@link Class#forName(String)} is used
+     * to load the JDBC driver. If specified, {@link Class#forName(String, boolean, ClassLoader)} is used.
      */
     private ClassLoader driverClassLoader;
 
     /**
-     * Returns the class loader specified for loading the JDBC driver. Returns
-     * <code>null</code> if no class loader has been explicitly specified.
+     * Returns the class loader specified for loading the JDBC driver. Returns <code>null</code> if no class loader has
+     * been explicitly specified.
      * <p>
-     * Note: This getter only returns the last value set by a call to
-     * {@link #setDriverClassLoader(ClassLoader)}. It does not return the class
-     * loader of any driver that may have been set via
-     * {@link #setDriver(Driver)}.
+     * Note: This getter only returns the last value set by a call to {@link #setDriverClassLoader(ClassLoader)}. It
+     * does not return the class loader of any driver that may have been set via {@link #setDriver(Driver)}.
+     * </p>
+     *
+     * @return The class loader specified for loading the JDBC driver.
      */
     public synchronized ClassLoader getDriverClassLoader() {
         return this.driverClassLoader;
     }
 
     /**
-     * <p>Sets the class loader to be used to load the JDBC driver.</p>
      * <p>
-     * Note: this method currently has no effect once the pool has been
-     * initialized.  The pool is initialized the first time one of the
-     * following methods is invoked: <code>getConnection, setLogwriter,
-     * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
+     * Sets the class loader to be used to load the JDBC driver.
+     * </p>
+     * <p>
+     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
+     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+     * </p>
      *
-     * @param driverClassLoader the class loader with which to load the JDBC
-     *                          driver
+     * @param driverClassLoader
+     *            the class loader with which to load the JDBC driver
      */
-    public synchronized void setDriverClassLoader(
-            final ClassLoader driverClassLoader) {
+    public synchronized void setDriverClassLoader(final ClassLoader driverClassLoader) {
         this.driverClassLoader = driverClassLoader;
     }
 
     /**
-     * True means that borrowObject returns the most recently used ("last in")
-     * connection in the pool (if there are idle connections available).  False
-     * means that the pool behaves as a FIFO queue - connections are taken from
-     * the idle instance pool in the order that they are returned to the pool.
+     * True means that borrowObject returns the most recently used ("last in") connection in the pool (if there are idle
+     * connections available). False means that the pool behaves as a FIFO queue - connections are taken from the idle
+     * instance pool in the order that they are returned to the pool.
      */
     private boolean lifo = BaseObjectPoolConfig.DEFAULT_LIFO;
 
@@ -406,10 +408,10 @@
     }
 
     /**
-     * Sets the LIFO property. True means the pool behaves as a LIFO queue;
-     * false means FIFO.
+     * Sets the LIFO property. True means the pool behaves as a LIFO queue; false means FIFO.
      *
-     * @param lifo the new value for the LIFO property
+     * @param lifo
+     *            the new value for the LIFO property
      *
      */
     public synchronized void setLifo(final boolean lifo) {
@@ -420,16 +422,18 @@
     }
 
     /**
-     * The maximum number of active connections that can be allocated from
-     * this pool at the same time, or negative for no limit.
+     * The maximum number of active connections that can be allocated from this pool at the same time, or negative for
+     * no limit.
      */
     private int maxTotal = GenericObjectPoolConfig.DEFAULT_MAX_TOTAL;
 
     /**
-     * <p>Returns the maximum number of active connections that can be
-     * allocated at the same time.
+     * <p>
+     * Returns the maximum number of active connections that can be allocated at the same time.
      * </p>
-     * <p>A negative number means that there is no limit.</p>
+     * <p>
+     * A negative number means that there is no limit.
+     * </p>
      *
      * @return the maximum number of active connections
      */
@@ -439,10 +443,11 @@
     }
 
     /**
-     * Sets the maximum total number of idle and borrows connections that can be
-     * active at the same time. Use a negative value for no limit.
+     * Sets the maximum total number of idle and borrows connections that can be active at the same time. Use a negative
+     * value for no limit.
      *
-     * @param maxTotal the new value for maxTotal
+     * @param maxTotal
+     *            the new value for maxTotal
      * @see #getMaxTotal()
      */
     public synchronized void setMaxTotal(final int maxTotal) {
@@ -453,22 +458,23 @@
     }
 
     /**
-     * The maximum number of connections that can remain idle in the
-     * pool, without extra ones being destroyed, or negative for no limit.
-     * If maxIdle is set too low on heavily loaded systems it is possible you
-     * will see connections being closed and almost immediately new connections
-     * being opened. This is a result of the active threads momentarily closing
-     * connections faster than they are opening them, causing the number of idle
-     * connections to rise above maxIdle. The best value for maxIdle for heavily
-     * loaded system will vary but the default is a good starting point.
+     * The maximum number of connections that can remain idle in the pool, without extra ones being destroyed, or
+     * negative for no limit. If maxIdle is set too low on heavily loaded systems it is possible you will see
+     * connections being closed and almost immediately new connections being opened. This is a result of the active
+     * threads momentarily closing connections faster than they are opening them, causing the number of idle connections
+     * to rise above maxIdle. The best value for maxIdle for heavily loaded system will vary but the default is a good
+     * starting point.
      */
     private int maxIdle = GenericObjectPoolConfig.DEFAULT_MAX_IDLE;
 
     /**
-     * <p>Returns the maximum number of connections that can remain idle in the
-     * pool. Excess idle connections are destroyed on return to the pool.
+     * <p>
+     * Returns the maximum number of connections that can remain idle in the pool. Excess idle connections are destroyed
+     * on return to the pool.
      * </p>
-     * <p>A negative value indicates that there is no limit</p>
+     * <p>
+     * A negative value indicates that there is no limit
+     * </p>
      *
      * @return the maximum number of idle connections
      */
@@ -478,11 +484,12 @@
     }
 
     /**
-     * Sets the maximum number of connections that can remain idle in the
-     * pool. Excess idle connections are destroyed on return to the pool.
+     * Sets the maximum number of connections that can remain idle in the pool. Excess idle connections are destroyed on
+     * return to the pool.
      *
      * @see #getMaxIdle()
-     * @param maxIdle the new value for maxIdle
+     * @param maxIdle
+     *            the new value for maxIdle
      */
     public synchronized void setMaxIdle(final int maxIdle) {
         this.maxIdle = maxIdle;
@@ -492,19 +499,17 @@
     }
 
     /**
-     * The minimum number of active connections that can remain idle in the
-     * pool, without extra ones being created when the evictor runs, or 0 to create none.
-     * The pool attempts to ensure that minIdle connections are available when the idle object evictor
-     * runs. The value of this property has no effect unless {@link #timeBetweenEvictionRunsMillis}
-     * has a positive value.
+     * The minimum number of active connections that can remain idle in the pool, without extra ones being created when
+     * the evictor runs, or 0 to create none. The pool attempts to ensure that minIdle connections are available when
+     * the idle object evictor runs. The value of this property has no effect unless
+     * {@link #timeBetweenEvictionRunsMillis} has a positive value.
      */
     private int minIdle = GenericObjectPoolConfig.DEFAULT_MIN_IDLE;
 
     /**
-     * Returns the minimum number of idle connections in the pool. The pool attempts
-     * to ensure that minIdle connections are available when the idle object evictor
-     * runs. The value of this property has no effect unless {@link #timeBetweenEvictionRunsMillis}
-     * has a positive value.
+     * Returns the minimum number of idle connections in the pool. The pool attempts to ensure that minIdle connections
+     * are available when the idle object evictor runs. The value of this property has no effect unless
+     * {@link #timeBetweenEvictionRunsMillis} has a positive value.
      *
      * @return the minimum number of idle connections
      * @see GenericObjectPool#getMinIdle()
@@ -515,24 +520,23 @@
     }
 
     /**
-     * Sets the minimum number of idle connections in the pool. The pool attempts
-     * to ensure that minIdle connections are available when the idle object evictor
-     * runs. The value of this property has no effect unless {@link #timeBetweenEvictionRunsMillis}
-     * has a positive value.
+     * Sets the minimum number of idle connections in the pool. The pool attempts to ensure that minIdle connections are
+     * available when the idle object evictor runs. The value of this property has no effect unless
+     * {@link #timeBetweenEvictionRunsMillis} has a positive value.
      *
-     * @param minIdle the new value for minIdle
+     * @param minIdle
+     *            the new value for minIdle
      * @see GenericObjectPool#setMinIdle(int)
      */
     public synchronized void setMinIdle(final int minIdle) {
-       this.minIdle = minIdle;
-       if (connectionPool != null) {
-           connectionPool.setMinIdle(minIdle);
-       }
+        this.minIdle = minIdle;
+        if (connectionPool != null) {
+            connectionPool.setMinIdle(minIdle);
+        }
     }
 
     /**
-     * The initial number of connections that are created when the pool
-     * is started.
+     * The initial number of connections that are created when the pool is started.
      */
     private int initialSize = 0;
 
@@ -547,32 +551,31 @@
     }
 
     /**
-     * <p>Sets the initial size of the connection pool.</p>
      * <p>
-     * Note: this method currently has no effect once the pool has been
-     * initialized.  The pool is initialized the first time one of the
-     * following methods is invoked: <code>getConnection, setLogwriter,
-     * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
+     * Sets the initial size of the connection pool.
+     * </p>
+     * <p>
+     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
+     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+     * </p>
      *
-     * @param initialSize the number of connections created when the pool
-     * is initialized
+     * @param initialSize
+     *            the number of connections created when the pool is initialized
      */
     public synchronized void setInitialSize(final int initialSize) {
         this.initialSize = initialSize;
     }
 
     /**
-     * The maximum number of milliseconds that the pool will wait (when there
-     * are no available connections) for a connection to be returned before
-     * throwing an exception, or <= 0 to wait indefinitely.
+     * The maximum number of milliseconds that the pool will wait (when there are no available connections) for a
+     * connection to be returned before throwing an exception, or <= 0 to wait indefinitely.
      */
-    private long maxWaitMillis =
-            BaseObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS;
+    private long maxWaitMillis = BaseObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS;
 
     /**
-     * Returns the maximum number of milliseconds that the pool will wait
-     * for a connection to be returned before throwing an exception. A value
-     * less than or equal to zero means the pool is set to wait indefinitely.
+     * Returns the maximum number of milliseconds that the pool will wait for a connection to be returned before
+     * throwing an exception. A value less than or equal to zero means the pool is set to wait indefinitely.
      *
      * @return the maxWaitMillis property value
      */
@@ -582,10 +585,10 @@
     }
 
     /**
-     * Sets the MaxWaitMillis property. Use -1 to make the pool wait
-     * indefinitely.
+     * Sets the MaxWaitMillis property. Use -1 to make the pool wait indefinitely.
      *
-     * @param maxWaitMillis the new value for MaxWaitMillis
+     * @param maxWaitMillis
+     *            the new value for MaxWaitMillis
      * @see #getMaxWaitMillis()
      */
     public synchronized void setMaxWaitMillis(final long maxWaitMillis) {
@@ -596,8 +599,8 @@
     }
 
     /**
-     * Prepared statement pooling for this pool. When this property is set to <code>true</code>
-     * both PreparedStatements and CallableStatements are pooled.
+     * Prepared statement pooling for this pool. When this property is set to <code>true</code> both PreparedStatements
+     * and CallableStatements are pooled.
      */
     private boolean poolPreparedStatements = false;
 
@@ -612,32 +615,36 @@
     }
 
     /**
-     * <p>Sets whether to pool statements or not.</p>
      * <p>
-     * Note: this method currently has no effect once the pool has been
-     * initialized.  The pool is initialized the first time one of the
-     * following methods is invoked: <code>getConnection, setLogwriter,
-     * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
+     * Sets whether to pool statements or not.
+     * </p>
+     * <p>
+     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
+     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+     * </p>
      *
-     * @param poolingStatements pooling on or off
+     * @param poolingStatements
+     *            pooling on or off
      */
     public synchronized void setPoolPreparedStatements(final boolean poolingStatements) {
         this.poolPreparedStatements = poolingStatements;
     }
 
     /**
-     * <p>The maximum number of open statements that can be allocated from
-     * the statement pool at the same time, or negative for no limit.  Since
-     * a connection usually only uses one or two statements at a time, this is
-     * mostly used to help detect resource leaks.</p>
-     *
-     * <p>Note: As of version 1.3, CallableStatements (those produced by {@link Connection#prepareCall})
-     * are pooled along with PreparedStatements (produced by {@link Connection#prepareStatement})
-     * and <code>maxOpenPreparedStatements</code> limits the total number of prepared or callable statements
-     * that may be in use at a given time.</p>
+     * <p>
+     * The maximum number of open statements that can be allocated from the statement pool at the same time, or negative
+     * for no limit. Since a connection usually only uses one or two statements at a time, this is mostly used to help
+     * detect resource leaks.
+     * </p>
+     * <p>
+     * Note: As of version 1.3, CallableStatements (those produced by {@link Connection#prepareCall}) are pooled along
+     * with PreparedStatements (produced by {@link Connection#prepareStatement}) and
+     * <code>maxOpenPreparedStatements</code> limits the total number of prepared or callable statements that may be in
+     * use at a given time.
+     * </p>
      */
-    private int maxOpenPreparedStatements =
-        GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL;
+    private int maxOpenPreparedStatements = GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL;
 
     /**
      * Gets the value of the <code>maxOpenPreparedStatements</code> property.
@@ -650,33 +657,32 @@
     }
 
     /**
-     * <p>Sets the value of the <code>maxOpenPreparedStatements</code>
-     * property.</p>
      * <p>
-     * Note: this method currently has no effect once the pool has been
-     * initialized.  The pool is initialized the first time one of the
-     * following methods is invoked: <code>getConnection, setLogwriter,
-     * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
+     * Sets the value of the <code>maxOpenPreparedStatements</code> property.
+     * </p>
+     * <p>
+     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
+     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+     * </p>
      *
-     * @param maxOpenStatements the new maximum number of prepared statements
+     * @param maxOpenStatements
+     *            the new maximum number of prepared statements
      */
     public synchronized void setMaxOpenPreparedStatements(final int maxOpenStatements) {
         this.maxOpenPreparedStatements = maxOpenStatements;
     }
 
     /**
-     * The indication of whether objects will be validated as soon as they have
-     * been created by the pool. If the object fails to validate, the borrow
-     * operation that triggered the creation will fail.
+     * The indication of whether objects will be validated as soon as they have been created by the pool. If the object
+     * fails to validate, the borrow operation that triggered the creation will fail.
      */
     private boolean testOnCreate = false;
 
     /**
      * Returns the {@link #testOnCreate} property.
      *
-     * @return true if objects are validated immediately after they are created
-     * by the pool
-     *
+     * @return true if objects are validated immediately after they are created by the pool
      * @see #testOnCreate
      */
     @Override
@@ -685,11 +691,11 @@
     }
 
     /**
-     * Sets the {@link #testOnCreate} property. This property determines
-     * whether or not the pool will validate objects immediately after they are
-     * created by the pool
+     * Sets the {@link #testOnCreate} property. This property determines whether or not the pool will validate objects
+     * immediately after they are created by the pool
      *
-     * @param testOnCreate new value for testOnCreate property
+     * @param testOnCreate
+     *            new value for testOnCreate property
      */
     public synchronized void setTestOnCreate(final boolean testOnCreate) {
         this.testOnCreate = testOnCreate;
@@ -699,17 +705,15 @@
     }
 
     /**
-     * The indication of whether objects will be validated before being
-     * borrowed from the pool.  If the object fails to validate, it will be
-     * dropped from the pool, and we will attempt to borrow another.
+     * The indication of whether objects will be validated before being borrowed from the pool. If the object fails to
+     * validate, it will be dropped from the pool, and we will attempt to borrow another.
      */
     private boolean testOnBorrow = true;
 
     /**
      * Returns the {@link #testOnBorrow} property.
      *
-     * @return true if objects are validated before being borrowed from the
-     * pool
+     * @return true if objects are validated before being borrowed from the pool
      *
      * @see #testOnBorrow
      */
@@ -719,11 +723,11 @@
     }
 
     /**
-     * Sets the {@link #testOnBorrow} property. This property determines
-     * whether or not the pool will validate objects before they are borrowed
-     * from the pool.
+     * Sets the {@link #testOnBorrow} property. This property determines whether or not the pool will validate objects
+     * before they are borrowed from the pool.
      *
-     * @param testOnBorrow new value for testOnBorrow property
+     * @param testOnBorrow
+     *            new value for testOnBorrow property
      */
     public synchronized void setTestOnBorrow(final boolean testOnBorrow) {
         this.testOnBorrow = testOnBorrow;
@@ -733,16 +737,14 @@
     }
 
     /**
-     * The indication of whether objects will be validated before being
-     * returned to the pool.
+     * The indication of whether objects will be validated before being returned to the pool.
      */
     private boolean testOnReturn = false;
 
     /**
      * Returns the value of the {@link #testOnReturn} property.
      *
-     * @return true if objects are validated before being returned to the
-     * pool
+     * @return true if objects are validated before being returned to the pool
      * @see #testOnReturn
      */
     public synchronized boolean getTestOnReturn() {
@@ -750,11 +752,11 @@
     }
 
     /**
-     * Sets the <code>testOnReturn</code> property. This property determines
-     * whether or not the pool will validate objects before they are returned
-     * to the pool.
+     * Sets the <code>testOnReturn</code> property. This property determines whether or not the pool will validate
+     * objects before they are returned to the pool.
      *
-     * @param testOnReturn new value for testOnReturn property
+     * @param testOnReturn
+     *            new value for testOnReturn property
      */
     public synchronized void setTestOnReturn(final boolean testOnReturn) {
         this.testOnReturn = testOnReturn;
@@ -764,16 +766,13 @@
     }
 
     /**
-     * The number of milliseconds to sleep between runs of the idle object
-     * evictor thread.  When non-positive, no idle object evictor thread will
-     * be run.
+     * The number of milliseconds to sleep between runs of the idle object evictor thread. When non-positive, no idle
+     * object evictor thread will be run.
      */
-    private long timeBetweenEvictionRunsMillis =
-        BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
+    private long timeBetweenEvictionRunsMillis = BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
 
     /**
-     * Returns the value of the {@link #timeBetweenEvictionRunsMillis}
-     * property.
+     * Returns the value of the {@link #timeBetweenEvictionRunsMillis} property.
      *
      * @return the time (in milliseconds) between evictor runs
      * @see #timeBetweenEvictionRunsMillis
@@ -786,7 +785,8 @@
     /**
      * Sets the {@link #timeBetweenEvictionRunsMillis} property.
      *
-     * @param timeBetweenEvictionRunsMillis the new time between evictor runs
+     * @param timeBetweenEvictionRunsMillis
+     *            the new time between evictor runs
      * @see #timeBetweenEvictionRunsMillis
      */
     public synchronized void setTimeBetweenEvictionRunsMillis(final long timeBetweenEvictionRunsMillis) {
@@ -797,17 +797,14 @@
     }
 
     /**
-     * The number of objects to examine during each run of the idle object
-     * evictor thread (if any).
+     * The number of objects to examine during each run of the idle object evictor thread (if any).
      */
-    private int numTestsPerEvictionRun =
-        BaseObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
+    private int numTestsPerEvictionRun = BaseObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
 
     /**
      * Returns the value of the {@link #numTestsPerEvictionRun} property.
      *
-     * @return the number of objects to examine during idle object evictor
-     * runs
+     * @return the number of objects to examine during idle object evictor runs
      * @see #numTestsPerEvictionRun
      */
     @Override
@@ -818,8 +815,8 @@
     /**
      * Sets the value of the {@link #numTestsPerEvictionRun} property.
      *
-     * @param numTestsPerEvictionRun the new {@link #numTestsPerEvictionRun}
-     * value
+     * @param numTestsPerEvictionRun
+     *            the new {@link #numTestsPerEvictionRun} value
      * @see #numTestsPerEvictionRun
      */
     public synchronized void setNumTestsPerEvictionRun(final int numTestsPerEvictionRun) {
@@ -830,11 +827,10 @@
     }
 
     /**
-     * The minimum amount of time an object may sit idle in the pool before it
-     * is eligible for eviction by the idle object evictor (if any).
+     * The minimum amount of time an object may sit idle in the pool before it is eligible for eviction by the idle
+     * object evictor (if any).
      */
-    private long minEvictableIdleTimeMillis =
-        BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
+    private long minEvictableIdleTimeMillis = BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
 
     /**
      * Returns the {@link #minEvictableIdleTimeMillis} property.
@@ -850,8 +846,8 @@
     /**
      * Sets the {@link #minEvictableIdleTimeMillis} property.
      *
-     * @param minEvictableIdleTimeMillis the minimum amount of time an object
-     * may sit idle in the pool
+     * @param minEvictableIdleTimeMillis
+     *            the minimum amount of time an object may sit idle in the pool
      * @see #minEvictableIdleTimeMillis
      */
     public synchronized void setMinEvictableIdleTimeMillis(final long minEvictableIdleTimeMillis) {
@@ -862,23 +858,20 @@
     }
 
     /**
-     * The minimum amount of time a connection may sit idle in the pool before
-     * it is eligible for eviction by the idle object evictor, with the extra
-     * condition that at least "minIdle" connections remain in the pool.
-     * Note that {@code minEvictableIdleTimeMillis} takes precedence over this
-     * parameter.  See {@link #getSoftMinEvictableIdleTimeMillis()}.
+     * The minimum amount of time a connection may sit idle in the pool before it is eligible for eviction by the idle
+     * object evictor, with the extra condition that at least "minIdle" connections remain in the pool. Note that
+     * {@code minEvictableIdleTimeMillis} takes precedence over this parameter. See
+     * {@link #getSoftMinEvictableIdleTimeMillis()}.
      */
-    private long softMinEvictableIdleTimeMillis =
-        BaseObjectPoolConfig.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
+    private long softMinEvictableIdleTimeMillis = BaseObjectPoolConfig.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
 
     /**
-     * Sets the minimum amount of time a connection may sit idle in the pool
-     * before it is eligible for eviction by the idle object evictor, with the
-     * extra condition that at least "minIdle" connections remain in the pool.
+     * Sets the minimum amount of time a connection may sit idle in the pool before it is eligible for eviction by the
+     * idle object evictor, with the extra condition that at least "minIdle" connections remain in the pool.
      *
-     * @param softMinEvictableIdleTimeMillis minimum amount of time a
-     * connection may sit idle in the pool before it is eligible for eviction,
-     * assuming there are minIdle idle connections in the pool.
+     * @param softMinEvictableIdleTimeMillis
+     *            minimum amount of time a connection may sit idle in the pool before it is eligible for eviction,
+     *            assuming there are minIdle idle connections in the pool.
      * @see #getSoftMinEvictableIdleTimeMillis
      */
     public synchronized void setSoftMinEvictableIdleTimeMillis(final long softMinEvictableIdleTimeMillis) {
@@ -889,34 +882,33 @@
     }
 
     /**
-     * <p>Returns the minimum amount of time a connection may sit idle in the
-     * pool before it is eligible for eviction by the idle object evictor, with
-     * the extra condition that at least "minIdle" connections remain in the
-     * pool.</p>
+     * <p>
+     * Returns the minimum amount of time a connection may sit idle in the pool before it is eligible for eviction by
+     * the idle object evictor, with the extra condition that at least "minIdle" connections remain in the pool.
+     * </p>
      *
-     * <p>When {@link #getMinEvictableIdleTimeMillis() minEvictableIdleTimeMillis}
-     * is set to a positive value, minEvictableIdleTimeMillis is examined
-     * first by the idle connection evictor - i.e. when idle connections are
-     * visited by the evictor, idle time is first compared against
-     * {@code minEvictableIdleTimeMillis} (without considering the number of idle
-     * connections in the pool) and then against
-     * {@code softMinEvictableIdleTimeMillis}, including the {@code minIdle},
-     * constraint.</p>
+     * <p>
+     * When {@link #getMinEvictableIdleTimeMillis() minEvictableIdleTimeMillis} is set to a positive value,
+     * minEvictableIdleTimeMillis is examined first by the idle connection evictor - i.e. when idle connections are
+     * visited by the evictor, idle time is first compared against {@code minEvictableIdleTimeMillis} (without
+     * considering the number of idle connections in the pool) and then against {@code softMinEvictableIdleTimeMillis},
+     * including the {@code minIdle}, constraint.
+     * </p>
      *
-     * @return minimum amount of time a connection may sit idle in the pool before
-     * it is eligible for eviction, assuming there are minIdle idle connections
-     * in the pool
+     * @return minimum amount of time a connection may sit idle in the pool before it is eligible for eviction, assuming
+     *         there are minIdle idle connections in the pool
      */
     @Override
     public synchronized long getSoftMinEvictableIdleTimeMillis() {
         return softMinEvictableIdleTimeMillis;
     }
 
-    private String evictionPolicyClassName =
-            BaseObjectPoolConfig.DEFAULT_EVICTION_POLICY_CLASS_NAME;
+    private String evictionPolicyClassName = BaseObjectPoolConfig.DEFAULT_EVICTION_POLICY_CLASS_NAME;
 
     /**
      * Gets the EvictionPolicy implementation in use with this connection pool.
+     *
+     * @return The EvictionPolicy implementation in use with this connection pool.
      */
     public synchronized String getEvictionPolicyClassName() {
         return evictionPolicyClassName;
@@ -925,11 +917,10 @@
     /**
      * Sets the EvictionPolicy implementation to use with this connection pool.
      *
-     * @param evictionPolicyClassName   The fully qualified class name of the
-     *                                  EvictionPolicy implementation
+     * @param evictionPolicyClassName
+     *            The fully qualified class name of the EvictionPolicy implementation
      */
-    public synchronized void setEvictionPolicyClassName(
-            final String evictionPolicyClassName) {
+    public synchronized void setEvictionPolicyClassName(final String evictionPolicyClassName) {
         if (connectionPool != null) {
             connectionPool.setEvictionPolicyClassName(evictionPolicyClassName);
         }
@@ -937,17 +928,15 @@
     }
 
     /**
-     * The indication of whether objects will be validated by the idle object
-     * evictor (if any).  If an object fails to validate, it will be dropped
-     * from the pool.
+     * The indication of whether objects will be validated by the idle object evictor (if any). If an object fails to
+     * validate, it will be dropped from the pool.
      */
     private boolean testWhileIdle = false;
 
     /**
      * Returns the value of the {@link #testWhileIdle} property.
      *
-     * @return true if objects examined by the idle object evictor are
-     * validated
+     * @return true if objects examined by the idle object evictor are validated
      * @see #testWhileIdle
      */
     @Override
@@ -956,10 +945,11 @@
     }
 
     /**
-     * Sets the <code>testWhileIdle</code> property. This property determines
-     * whether or not the idle object evictor will validate connections.
+     * Sets the <code>testWhileIdle</code> property. This property determines whether or not the idle object evictor
+     * will validate connections.
      *
-     * @param testWhileIdle new value for testWhileIdle property
+     * @param testWhileIdle
+     *            new value for testWhileIdle property
      */
     public synchronized void setTestWhileIdle(final boolean testWhileIdle) {
         this.testWhileIdle = testWhileIdle;
@@ -969,8 +959,7 @@
     }
 
     /**
-     * [Read Only] The current number of active connections that have been
-     * allocated from this data source.
+     * [Read Only] The current number of active connections that have been allocated from this data source.
      *
      * @return the current number of active connections
      */
@@ -984,10 +973,8 @@
         return 0;
     }
 
-
     /**
-     * [Read Only] The current number of idle connections that are waiting
-     * to be allocated from this data source.
+     * [Read Only] The current number of idle connections that are waiting to be allocated from this data source.
      *
      * @return the current number of idle connections
      */
@@ -1002,8 +989,7 @@
     }
 
     /**
-     * The connection password to be passed to our JDBC driver to establish
-     * a connection.
+     * The connection password to be passed to our JDBC driver to establish a connection.
      */
     private volatile String password;
 
@@ -1018,30 +1004,31 @@
     }
 
     /**
-     * <p>Sets the {@link #password}.</p>
      * <p>
-     * Note: this method currently has no effect once the pool has been
-     * initialized.  The pool is initialized the first time one of the
-     * following methods is invoked: <code>getConnection, setLogwriter,
-     * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
+     * Sets the {@link #password}.
+     * </p>
+     * <p>
+     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
+     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+     * </p>
      *
-     * @param password new value for the password
+     * @param password
+     *            new value for the password
      */
     public void setPassword(final String password) {
         this.password = password;
     }
 
     /**
-     * The connection URL to be passed to our JDBC driver to establish
-     * a connection.
+     * The connection URL to be passed to our JDBC driver to establish a connection.
      */
     private String url;
 
     /**
      * Returns the JDBC connection {@link #url} property.
      *
-     * @return the {@link #url} passed to the JDBC driver to establish
-     * connections
+     * @return the {@link #url} passed to the JDBC driver to establish connections
      */
     @Override
     public synchronized String getUrl() {
@@ -1049,62 +1036,63 @@
     }
 
     /**
-     * <p>Sets the {@link #url}.</p>
      * <p>
-     * Note: this method currently has no effect once the pool has been
-     * initialized.  The pool is initialized the first time one of the
-     * following methods is invoked: <code>getConnection, setLogwriter,
-     * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
+     * Sets the {@link #url}.
+     * </p>
+     * <p>
+     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
+     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+     * </p>
      *
-     * @param url the new value for the JDBC connection url
+     * @param url
+     *            the new value for the JDBC connection url
      */
     public synchronized void setUrl(final String url) {
         this.url = url;
     }
 
     /**
-     * The connection username to be passed to our JDBC driver to
-     * establish a connection.
+     * The connection user name to be passed to our JDBC driver to establish a connection.
      */
-    private String username;
+    private String userName;
 
     /**
-     * Returns the JDBC connection {@link #username} property.
+     * Returns the JDBC connection {@link #userName} property.
      *
-     * @return the {@link #username} passed to the JDBC driver to establish
-     * connections
+     * @return the {@link #userName} passed to the JDBC driver to establish connections
      */
     @Override
     public String getUsername() {
-        return this.username;
+        return this.userName;
     }
 
     /**
-     * <p>Sets the {@link #username}.</p>
      * <p>
-     * Note: this method currently has no effect once the pool has been
-     * initialized.  The pool is initialized the first time one of the
-     * following methods is invoked: <code>getConnection, setLogwriter,
-     * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
+     * Sets the {@link #userName}.
+     * </p>
+     * <p>
+     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
+     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+     * </p>
      *
-     * @param username the new value for the JDBC connection username
+     * @param userName
+     *            the new value for the JDBC connection user name
      */
-    public void setUsername(final String username) {
-        this.username = username;
+    public void setUsername(final String userName) {
+        this.userName = userName;
     }
 
     /**
-     * The SQL query that will be used to validate connections from this pool
-     * before returning them to the caller.  If specified, this query
-     * <strong>MUST</strong> be an SQL SELECT statement that returns at least
-     * one row. If not specified, {@link Connection#isValid(int)} will be used
-     * to validate connections.
+     * The SQL query that will be used to validate connections from this pool before returning them to the caller. If
+     * specified, this query <strong>MUST</strong> be an SQL SELECT statement that returns at least one row. If not
+     * specified, {@link Connection#isValid(int)} will be used to validate connections.
      */
     private volatile String validationQuery;
 
     /**
-     * Returns the validation query used to validate connections before
-     * returning them.
+     * Returns the validation query used to validate connections before returning them.
      *
      * @return the SQL validation query
      * @see #validationQuery
@@ -1115,14 +1103,17 @@
     }
 
     /**
-     * <p>Sets the {@link #validationQuery}.</p>
      * <p>
-     * Note: this method currently has no effect once the pool has been
-     * initialized.  The pool is initialized the first time one of the
-     * following methods is invoked: <code>getConnection, setLogwriter,
-     * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
+     * Sets the {@link #validationQuery}.
+     * </p>
+     * <p>
+     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
+     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+     * </p>
      *
-     * @param validationQuery the new value for the validation query
+     * @param validationQuery
+     *            the new value for the validation query
      */
     public void setValidationQuery(final String validationQuery) {
         if (validationQuery != null && validationQuery.trim().length() > 0) {
@@ -1135,7 +1126,7 @@
     /**
      * Timeout in seconds before connection validation queries fail.
      */
-    private volatile int validationQueryTimeout = -1;
+    private volatile int validationQueryTimeoutSeconds = -1;
 
     /**
      * Returns the validation query timeout.
@@ -1144,40 +1135,37 @@
      */
     @Override
     public int getValidationQueryTimeout() {
-        return validationQueryTimeout;
+        return validationQueryTimeoutSeconds;
     }
 
     /**
-     * Sets the validation query timeout, the amount of time, in seconds, that
-     * connection validation will wait for a response from the database when
-     * executing a validation query.  Use a value less than or equal to 0 for
-     * no timeout.
+     * Sets the validation query timeout, the amount of time, in seconds, that connection validation will wait for a
+     * response from the database when executing a validation query. Use a value less than or equal to 0 for no timeout.
      * <p>
-     * Note: this method currently has no effect once the pool has been
-     * initialized.  The pool is initialized the first time one of the
-     * following methods is invoked: <code>getConnection, setLogwriter,
-     * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
+     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
+     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+     * </p>
      *
-     * @param timeout new validation query timeout value in seconds
+     * @param validationQueryTimeoutSeconds
+     *            new validation query timeout value in seconds
      */
-    public void setValidationQueryTimeout(final int timeout) {
-        this.validationQueryTimeout = timeout;
+    public void setValidationQueryTimeout(final int validationQueryTimeoutSeconds) {
+        this.validationQueryTimeoutSeconds = validationQueryTimeoutSeconds;
     }
 
     /**
      * These SQL statements run once after a Connection is created.
      * <p>
-     * This property can be used for example to run ALTER SESSION SET
-     * NLS_SORT=XCYECH in an Oracle Database only once after connection
-     * creation.
+     * This property can be used for example to run ALTER SESSION SET NLS_SORT=XCYECH in an Oracle Database only once
+     * after connection creation.
      * </p>
      */
     private volatile List<String> connectionInitSqls;
 
     /**
-     * Returns the list of SQL statements executed when a physical connection
-     * is first created. Returns an empty list if there are no initialization
-     * statements configured.
+     * Returns the list of SQL statements executed when a physical connection is first created. Returns an empty list if
+     * there are no initialization statements configured.
      *
      * @return initialization SQL statements
      */
@@ -1190,8 +1178,7 @@
     }
 
     /**
-     * Provides the same data as {@link #getConnectionInitSqls()} but in an
-     * array so it is accessible via JMX.
+     * Provides the same data as {@link #getConnectionInitSqls()} but in an array so it is accessible via JMX.
      */
     @Override
     public String[] getConnectionInitSqlsAsArray() {
@@ -1200,22 +1187,21 @@
     }
 
     /**
-     * Sets the list of SQL statements to be executed when a physical
-     * connection is first created.
+     * Sets the list of SQL statements to be executed when a physical connection is first created.
      * <p>
-     * Note: this method currently has no effect once the pool has been
-     * initialized.  The pool is initialized the first time one of the
-     * following methods is invoked: <code>getConnection, setLogwriter,
-     * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
+     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
+     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+     * </p>
      *
-     * @param connectionInitSqls Collection of SQL statements to execute
-     * on connection creation
+     * @param connectionInitSqls
+     *            Collection of SQL statements to execute on connection creation
      */
     public void setConnectionInitSqls(final Collection<String> connectionInitSqls) {
         if (connectionInitSqls != null && connectionInitSqls.size() > 0) {
             ArrayList<String> newVal = null;
             for (final String s : connectionInitSqls) {
-            if (s != null && s.trim().length() > 0) {
+                if (s != null && s.trim().length() > 0) {
                     if (newVal == null) {
                         newVal = new ArrayList<>();
                     }
@@ -1228,7 +1214,6 @@
         }
     }
 
-
     /**
      * Controls access to the underlying connection.
      */
@@ -1237,8 +1222,7 @@
     /**
      * Returns the value of the accessToUnderlyingConnectionAllowed property.
      *
-     * @return true if access to the underlying connection is allowed, false
-     * otherwise.
+     * @return true if access to the underlying connection is allowed, false otherwise.
      */
     @Override
     public synchronized boolean isAccessToUnderlyingConnectionAllowed() {
@@ -1246,27 +1230,28 @@
     }
 
     /**
-     * <p>Sets the value of the accessToUnderlyingConnectionAllowed property.
-     * It controls if the PoolGuard allows access to the underlying connection.
-     * (Default: false)</p>
      * <p>
-     * Note: this method currently has no effect once the pool has been
-     * initialized.  The pool is initialized the first time one of the
-     * following methods is invoked: <code>getConnection, setLogwriter,
-     * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
+     * Sets the value of the accessToUnderlyingConnectionAllowed property. It controls if the PoolGuard allows access to
+     * the underlying connection. (Default: false)
+     * </p>
+     * <p>
+     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
+     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+     * </p>
      *
-     * @param allow Access to the underlying connection is granted when true.
+     * @param allow
+     *            Access to the underlying connection is granted when true.
      */
     public synchronized void setAccessToUnderlyingConnectionAllowed(final boolean allow) {
         this.accessToUnderlyingConnectionAllowed = allow;
     }
 
-
     private long maxConnLifetimeMillis = -1;
 
     /**
-     * Returns the maximum permitted lifetime of a connection in milliseconds. A
-     * value of zero or less indicates an infinite lifetime.
+     * Returns the maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an
+     * infinite lifetime.
      */
     @Override
     public long getMaxConnLifetimeMillis() {
@@ -1276,9 +1261,8 @@
     private boolean logExpiredConnections = true;
 
     /**
-     * When {@link #getMaxConnLifetimeMillis()} is set to limit connection lifetime,
-     * this property determines whether or not log messages are generated when the
-     * pool closes connections due to maximum lifetime exceeded.
+     * When {@link #getMaxConnLifetimeMillis()} is set to limit connection lifetime, this property determines whether or
+     * not log messages are generated when the pool closes connections due to maximum lifetime exceeded.
      *
      * @since 2.1
      */
@@ -1288,23 +1272,31 @@
     }
 
     /**
-     * <p>Sets the maximum permitted lifetime of a connection in
-     * milliseconds. A value of zero or less indicates an infinite lifetime.</p>
      * <p>
-     * Note: this method currently has no effect once the pool has been
-     * initialized.  The pool is initialized the first time one of the
-     * following methods is invoked: <code>getConnection, setLogwriter,
-     * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
+     * Sets the maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an
+     * infinite lifetime.
+     * </p>
+     * <p>
+     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
+     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+     * </p>
+     *
+     * @param maxConnLifetimeMillis
+     *            The maximum permitted lifetime of a connection in milliseconds.
      */
     public void setMaxConnLifetimeMillis(final long maxConnLifetimeMillis) {
         this.maxConnLifetimeMillis = maxConnLifetimeMillis;
     }
 
     /**
-     * When {@link #getMaxConnLifetimeMillis()} is set to limit connection lifetime,
-     * this property determines whether or not log messages are generated when the
-     * pool closes connections due to maximum lifetime exceeded.  Set this property
-     * to false to suppress log messages when connections expire.
+     * When {@link #getMaxConnLifetimeMillis()} is set to limit connection lifetime, this property determines whether or
+     * not log messages are generated when the pool closes connections due to maximum lifetime exceeded. Set this
+     * property to false to suppress log messages when connections expire.
+     *
+     * @param logExpiredConnections
+     *            Whether or not log messages are generated when the pool closes connections due to maximum lifetime
+     *            exceeded.
      */
     public void setLogExpiredConnections(final boolean logExpiredConnections) {
         this.logExpiredConnections = logExpiredConnections;
@@ -1313,44 +1305,48 @@
     private String jmxName;
 
     /**
-     * Returns the JMX name that has been requested for this DataSource. If the
-     * requested name is not valid, an alternative may be chosen.
+     * Returns the JMX name that has been requested for this DataSource. If the requested name is not valid, an
+     * alternative may be chosen.
+     *
+     * @return The JMX name that has been requested for this DataSource.
      */
     public String getJmxName() {
         return jmxName;
     }
 
     /**
-     * Sets the JMX name that has been requested for this DataSource. If the
-     * requested name is not valid, an alternative may be chosen. This
-     * DataSource will attempt to register itself using this name. If another
-     * component registers this DataSource with JMX and this name is valid this
-     * name will be used in preference to any specified by the other component.
+     * Sets the JMX name that has been requested for this DataSource. If the requested name is not valid, an alternative
+     * may be chosen. This DataSource will attempt to register itself using this name. If another component registers
+     * this DataSource with JMX and this name is valid this name will be used in preference to any specified by the
+     * other component.
+     *
+     * @param jmxName
+     *            The JMX name that has been requested for this DataSource
      */
     public void setJmxName(final String jmxName) {
         this.jmxName = jmxName;
     }
 
-
     private boolean enableAutoCommitOnReturn = true;
 
     /**
-     * Returns the value of the flag that controls whether or not connections
-     * being returned to the pool will be checked and configured with
-     * {@link Connection#setAutoCommit(boolean) Connection.setAutoCommit(true)}
-     * if the auto commit setting is {@code false} when the connection
-     * is returned. It is <code>true</code> by default.
+     * Returns the value of the flag that controls whether or not connections being returned to the pool will be checked
+     * and configured with {@link Connection#setAutoCommit(boolean) Connection.setAutoCommit(true)} if the auto commit
+     * setting is {@code false} when the connection is returned. It is <code>true</code> by default.
+     *
+     * @return Whether or not connections being returned to the pool will be checked and configured with auto-commit.
      */
     public boolean getEnableAutoCommitOnReturn() {
         return enableAutoCommitOnReturn;
     }
 
     /**
-     * Sets the value of the flag that controls whether or not connections
-     * being returned to the pool will be checked and configured with
-     * {@link Connection#setAutoCommit(boolean) Connection.setAutoCommit(true)}
-     * if the auto commit setting is {@code false} when the connection
-     * is returned. It is <code>true</code> by default.
+     * Sets the value of the flag that controls whether or not connections being returned to the pool will be checked
+     * and configured with {@link Connection#setAutoCommit(boolean) Connection.setAutoCommit(true)} if the auto commit
+     * setting is {@code false} when the connection is returned. It is <code>true</code> by default.
+     *
+     * @param enableAutoCommitOnReturn
+     *            Whether or not connections being returned to the pool will be checked and configured with auto-commit.
      */
     public void setEnableAutoCommitOnReturn(final boolean enableAutoCommitOnReturn) {
         this.enableAutoCommitOnReturn = enableAutoCommitOnReturn;
@@ -1359,18 +1355,21 @@
     private boolean rollbackOnReturn = true;
 
     /**
-     * Gets the current value of the flag that controls if a connection will be
-     * rolled back when it is returned to the pool if auto commit is not enabled
-     * and the connection is not read only.
+     * Gets the current value of the flag that controls whether a connection will be rolled back when it is returned to
+     * the pool if auto commit is not enabled and the connection is not read only.
+     *
+     * @return whether a connection will be rolled back when it is returned to the pool.
      */
     public boolean getRollbackOnReturn() {
         return rollbackOnReturn;
     }
 
     /**
-     * Sets the flag that controls if a connection will be rolled back when it
-     * is returned to the pool if auto commit is not enabled and the connection
-     * is not read only.
+     * Sets the flag that controls if a connection will be rolled back when it is returned to the pool if auto commit is
+     * not enabled and the connection is not read only.
+     *
+     * @param rollbackOnReturn
+     *            whether a connection will be rolled back when it is returned to the pool.
      */
     public void setRollbackOnReturn(final boolean rollbackOnReturn) {
         this.rollbackOnReturn = rollbackOnReturn;
@@ -1380,6 +1379,7 @@
 
     /**
      * Returns the set of SQL_STATE codes considered to signal fatal conditions.
+     *
      * @return fatal disconnection state codes
      * @see #setDisconnectionSqlCodes(Collection)
      * @since 2.1
@@ -1393,8 +1393,8 @@
     }
 
     /**
-     * Provides the same data as {@link #getDisconnectionSqlCodes} but in an
-     * array so it is accessible via JMX.
+     * Provides the same data as {@link #getDisconnectionSqlCodes} but in an array so it is accessible via JMX.
+     *
      * @since 2.1
      */
     @Override
@@ -1406,30 +1406,30 @@
     /**
      * Sets the SQL_STATE codes considered to signal fatal conditions.
      * <p>
-     * Overrides the defaults in {@link Utils#DISCONNECTION_SQL_CODES}
-     * (plus anything starting with {@link Utils#DISCONNECTION_SQL_CODE_PREFIX}).
-     * If this property is non-null and {@link #getFastFailValidation()} is
-     * {@code true}, whenever connections created by this datasource generate exceptions
-     * with SQL_STATE codes in this list, they will be marked as "fatally disconnected"
-     * and subsequent validations will fail fast (no attempt at isValid or validation
-     * query).</p>
+     * Overrides the defaults in {@link Utils#DISCONNECTION_SQL_CODES} (plus anything starting with
+     * {@link Utils#DISCONNECTION_SQL_CODE_PREFIX}). If this property is non-null and {@link #getFastFailValidation()}
+     * is {@code true}, whenever connections created by this datasource generate exceptions with SQL_STATE codes in this
+     * list, they will be marked as "fatally disconnected" and subsequent validations will fail fast (no attempt at
+     * isValid or validation query).
+     * </p>
      * <p>
-     * If {@link #getFastFailValidation()} is {@code false} setting this property has no
-     * effect.</p>
+     * If {@link #getFastFailValidation()} is {@code false} setting this property has no effect.
+     * </p>
      * <p>
-     * Note: this method currently has no effect once the pool has been
-     * initialized.  The pool is initialized the first time one of the
-     * following methods is invoked: {@code getConnection, setLogwriter,
-     * setLoginTimeout, getLoginTimeout, getLogWriter}.</p>
+     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+     * time one of the following methods is invoked: {@code getConnection, setLogwriter,
+     * setLoginTimeout, getLoginTimeout, getLogWriter}.
+     * </p>
      *
-     * @param disconnectionSqlCodes SQL_STATE codes considered to signal fatal conditions
+     * @param disconnectionSqlCodes
+     *            SQL_STATE codes considered to signal fatal conditions
      * @since 2.1
      */
     public void setDisconnectionSqlCodes(final Collection<String> disconnectionSqlCodes) {
         if (disconnectionSqlCodes != null && disconnectionSqlCodes.size() > 0) {
             HashSet<String> newVal = null;
             for (final String s : disconnectionSqlCodes) {
-            if (s != null && s.trim().length() > 0) {
+                if (s != null && s.trim().length() > 0) {
                     if (newVal == null) {
                         newVal = new HashSet<>();
                     }
@@ -1445,9 +1445,8 @@
     private boolean fastFailValidation;
 
     /**
-     * True means that validation will fail immediately for connections that
-     * have previously thrown SQLExceptions with SQL_STATE indicating fatal
-     * disconnection errors.
+     * True means that validation will fail immediately for connections that have previously thrown SQLExceptions with
+     * SQL_STATE indicating fatal disconnection errors.
      *
      * @return true if connections created by this datasource will fast fail validation.
      * @see #setDisconnectionSqlCodes(Collection)
@@ -1460,16 +1459,14 @@
 
     /**
      * @see #getFastFailValidation()
-     * @param fastFailValidation true means connections created by this factory will
-     * fast fail validation
+     * @param fastFailValidation
+     *            true means connections created by this factory will fast fail validation
      * @since 2.1
      */
     public void setFastFailValidation(final boolean fastFailValidation) {
         this.fastFailValidation = fastFailValidation;
     }
 
-    // ----------------------------------------------------- Instance Variables
-
     /**
      * The object pool that internally manages our connections.
      */
@@ -1480,10 +1477,9 @@
     }
 
     /**
-     * The connection properties that will be sent to our JDBC driver when
-     * establishing new connections.  <strong>NOTE</strong> - The "user" and
-     * "password" properties will be passed explicitly, so they do not need
-     * to be included here.
+     * The connection properties that will be sent to our JDBC driver when establishing new connections.
+     * <strong>NOTE</strong> - The "user" and "password" properties will be passed explicitly, so they do not need to be
+     * included here.
      */
     private Properties connectionProperties = new Properties();
 
@@ -1493,26 +1489,24 @@
     }
 
     /**
-     * The data source we will use to manage connections.  This object should
-     * be acquired <strong>ONLY</strong> by calls to the
-     * <code>createDataSource()</code> method.
+     * The data source we will use to manage connections. This object should be acquired <strong>ONLY</strong> by calls
+     * to the <code>createDataSource()</code> method.
      */
     private volatile DataSource dataSource;
 
     /**
      * The PrintWriter to which log messages should be directed.
      */
-    private volatile PrintWriter logWriter = new PrintWriter(new OutputStreamWriter(
-            System.out, StandardCharsets.UTF_8));
-
+    private volatile PrintWriter logWriter = new PrintWriter(
+            new OutputStreamWriter(System.out, StandardCharsets.UTF_8));
 
     // ----------------------------------------------------- DataSource Methods
 
-
     /**
-     * Create (if necessary) and return a connection to the database.
+     * Creates (if necessary) and return a connection to the database.
      *
-     * @throws SQLException if a database access error occurs
+     * @throws SQLException
+     *             if a database access error occurs
      * @return a database connection
      */
     @Override
@@ -1532,54 +1526,58 @@
         return createDataSource().getConnection();
     }
 
-
     /**
-     * <strong>BasicDataSource does NOT support this method. </strong>
+     * <strong>BasicDataSource does NOT support this method.</strong>
      *
-     * @param user Database user on whose behalf the Connection
-     *   is being made
-     * @param pass The database user's password
+     * @param user
+     *            Database user on whose behalf the Connection is being made
+     * @param pass
+     *            The database user's password
      *
      * @throws UnsupportedOperationException
-     * @throws SQLException if a database access error occurs
+     *             always thrown.
+     * @throws SQLException
+     *             if a database access error occurs
      * @return nothing - always throws UnsupportedOperationException
      */
     @Override
     public Connection getConnection(final String user, final String pass) throws SQLException {
-        // This method isn't supported by the PoolingDataSource returned by
-        // the createDataSource
+        // This method isn't supported by the PoolingDataSource returned by the createDataSource
         throw new UnsupportedOperationException("Not supported by BasicDataSource");
     }
 
-
     /**
-     * <strong>BasicDataSource does NOT support this method. </strong>
+     * <strong>BasicDataSource does NOT support this method.</strong>
      *
-     * <p>Returns the login timeout (in seconds) for connecting to the database.
+     * <p>
+     * Returns the login timeout (in seconds) for connecting to the database.
      * </p>
-     * <p>Calls {@link #createDataSource()}, so has the side effect
-     * of initializing the connection pool.</p>
+     * <p>
+     * Calls {@link #createDataSource()}, so has the side effect of initializing the connection pool.
+     * </p>
      *
-     * @throws SQLException if a database access error occurs
-     * @throws UnsupportedOperationException If the DataSource implementation
-     *   does not support the login timeout feature.
+     * @throws SQLException
+     *             if a database access error occurs
+     * @throws UnsupportedOperationException
+     *             If the DataSource implementation does not support the login timeout feature.
      * @return login timeout in seconds
      */
     @Override
     public int getLoginTimeout() throws SQLException {
-        // This method isn't supported by the PoolingDataSource returned by
-        // the createDataSource
+        // This method isn't supported by the PoolingDataSource returned by the createDataSource
         throw new UnsupportedOperationException("Not supported by BasicDataSource");
     }
 
-
     /**
-     * <p>Returns the log writer being used by this data source.</p>
      * <p>
-     * Calls {@link #createDataSource()}, so has the side effect
-     * of initializing the connection pool.</p>
+     * Returns the log writer being used by this data source.
+     * </p>
+     * <p>
+     * Calls {@link #createDataSource()}, so has the side effect of initializing the connection pool.
+     * </p>
      *
-     * @throws SQLException if a database access error occurs
+     * @throws SQLException
+     *             if a database access error occurs
      * @return log writer in use
      */
     @Override
@@ -1587,37 +1585,41 @@
         return createDataSource().getLogWriter();
     }
 
-
     /**
      * <strong>BasicDataSource does NOT support this method. </strong>
      *
-     * <p>Set the login timeout (in seconds) for connecting to the
-     * database.</p>
      * <p>
-     * Calls {@link #createDataSource()}, so has the side effect
-     * of initializing the connection pool.</p>
+     * Set the login timeout (in seconds) for connecting to the database.
+     * </p>
+     * <p>
+     * Calls {@link #createDataSource()}, so has the side effect of initializing the connection pool.
+     * </p>
      *
-     * @param loginTimeout The new login timeout, or zero for no timeout
-     * @throws UnsupportedOperationException If the DataSource implementation
-     *   does not support the login timeout feature.
-     * @throws SQLException if a database access error occurs
+     * @param loginTimeout
+     *            The new login timeout, or zero for no timeout
+     * @throws UnsupportedOperationException
+     *             If the DataSource implementation does not support the login timeout feature.
+     * @throws SQLException
+     *             if a database access error occurs
      */
     @Override
     public void setLoginTimeout(final int loginTimeout) throws SQLException {
-        // This method isn't supported by the PoolingDataSource returned by
-        // the createDataSource
+        // This method isn't supported by the PoolingDataSource returned by the createDataSource
         throw new UnsupportedOperationException("Not supported by BasicDataSource");
     }
 
-
     /**
-     * <p>Sets the log writer being used by this data source.</p>
      * <p>
-     * Calls {@link #createDataSource()}, so has the side effect
-     * of initializing the connection pool.</p>
+     * Sets the log writer being used by this data source.
+     * </p>
+     * <p>
+     * Calls {@link #createDataSource()}, so has the side effect of initializing the connection pool.
+     * </p>
      *
-     * @param logWriter The new log writer
-     * @throws SQLException if a database access error occurs
+     * @param logWriter
+     *            The new log writer
+     * @throws SQLException
+     *             if a database access error occurs
      */
     @Override
     public void setLogWriter(final PrintWriter logWriter) throws SQLException {
@@ -1628,21 +1630,25 @@
     private AbandonedConfig abandonedConfig;
 
     /**
-     * <p>Flag to remove abandoned connections if they exceed the
-     * removeAbandonedTimeout when borrowObject is invoked.</p>
-     *
-     * <p>The default value is false.</p>
-     *
-     * <p>If set to true a connection is considered abandoned and eligible
-     * for removal if it has not been used for more than
-     * {@link #getRemoveAbandonedTimeout() removeAbandonedTimeout} seconds.</p>
-     *
-     * <p>Abandoned connections are identified and removed when
-     * {@link #getConnection()} is invoked and all of the following conditions hold:
+     * <p>
+     * Flag to remove abandoned connections if they exceed the removeAbandonedTimeout when borrowObject is invoked.
      * </p>
-     * <ul><li>{@link #getRemoveAbandonedOnBorrow()} </li>
-     *     <li>{@link #getNumActive()} &gt; {@link #getMaxTotal()} - 3 </li>
-     *     <li>{@link #getNumIdle()} &lt; 2 </li></ul>
+     * <p>
+     * The default value is false.
+     * </p>
+     * <p>
+     * If set to true a connection is considered abandoned and eligible for removal if it has not been used for more
+     * than {@link #getRemoveAbandonedTimeout() removeAbandonedTimeout} seconds.
+     * </p>
+     * <p>
+     * Abandoned connections are identified and removed when {@link #getConnection()} is invoked and all of the
+     * following conditions hold:
+     * </p>
+     * <ul>
+     * <li>{@link #getRemoveAbandonedOnBorrow()}</li>
+     * <li>{@link #getNumActive()} &gt; {@link #getMaxTotal()} - 3</li>
+     * <li>{@link #getNumIdle()} &lt; 2</li>
+     * </ul>
      *
      * @see #getRemoveAbandonedTimeout()
      */
@@ -1655,17 +1661,15 @@
     }
 
     /**
-     * @param removeAbandonedOnMaintenance true means abandoned connections may
-     *                                     be removed on pool maintenance.
+     * @param removeAbandonedOnMaintenance
+     *            true means abandoned connections may be removed on pool maintenance.
      * @see #getRemoveAbandonedOnMaintenance()
      */
-    public void setRemoveAbandonedOnMaintenance(
-            final boolean removeAbandonedOnMaintenance) {
+    public void setRemoveAbandonedOnMaintenance(final boolean removeAbandonedOnMaintenance) {
         if (abandonedConfig == null) {
             abandonedConfig = new AbandonedConfig();
         }
-        abandonedConfig.setRemoveAbandonedOnMaintenance(
-                removeAbandonedOnMaintenance);
+        abandonedConfig.setRemoveAbandonedOnMaintenance(removeAbandonedOnMaintenance);
         final GenericObjectPool<?> gop = this.connectionPool;
         if (gop != null) {
             gop.setAbandonedConfig(abandonedConfig);
@@ -1673,14 +1677,18 @@
     }
 
     /**
-     * <p>Flag to remove abandoned connections if they exceed the
-     * removeAbandonedTimeout during pool maintenance.</p>
+     * <p>
+     * Flag to remove abandoned connections if they exceed the removeAbandonedTimeout during pool maintenance.
+     * </p>
      *
-     * <p>The default value is false.</p>
+     * <p>
+     * The default value is false.
+     * </p>
      *
-     * <p>If set to true a connection is considered abandoned and eligible
-     * for removal if it has not been used for more than
-     * {@link #getRemoveAbandonedTimeout() removeAbandonedTimeout} seconds.</p>
+     * <p>
+     * If set to true a connection is considered abandoned and eligible for removal if it has not been used for more
+     * than {@link #getRemoveAbandonedTimeout() removeAbandonedTimeout} seconds.
+     * </p>
      *
      * @see #getRemoveAbandonedTimeout()
      */
@@ -1693,8 +1701,8 @@
     }
 
     /**
-     * @param removeAbandonedOnBorrow true means abandoned connections may be
-     *                                removed when connections are borrowed from the pool.
+     * @param removeAbandonedOnBorrow
+     *            true means abandoned connections may be removed when connections are borrowed from the pool.
      * @see #getRemoveAbandonedOnBorrow()
      */
     public void setRemoveAbandonedOnBorrow(final boolean removeAbandonedOnBorrow) {
@@ -1709,21 +1717,24 @@
     }
 
     /**
-     * <p>Timeout in seconds before an abandoned connection can be removed.</p>
-     *
-     * <p>Creating a Statement, PreparedStatement or CallableStatement or using
-     * one of these to execute a query (using one of the execute methods)
-     * resets the lastUsed property of the parent connection.</p>
-     *
-     * <p>Abandoned connection cleanup happens when:</p>
+     * <p>
+     * Timeout in seconds before an abandoned connection can be removed.
+     * </p>
+     * <p>
+     * Creating a Statement, PreparedStatement or CallableStatement or using one of these to execute a query (using one
+     * of the execute methods) resets the lastUsed property of the parent connection.
+     * </p>
+     * <p>
+     * Abandoned connection cleanup happens when:
+     * </p>
      * <ul>
-     * <li>{@link #getRemoveAbandonedOnBorrow()} or
-     *     {@link #getRemoveAbandonedOnMaintenance()} = true</li>
+     * <li>{@link #getRemoveAbandonedOnBorrow()} or {@link #getRemoveAbandonedOnMaintenance()} = true</li>
      * <li>{@link #getNumIdle() numIdle} &lt; 2</li>
      * <li>{@link #getNumActive() numActive} &gt; {@link #getMaxTotal() maxTotal} - 3</li>
      * </ul>
-     *
-     * <p>The default value is 300 seconds.</p>
+     * <p>
+     * The default value is 300 seconds.
+     * </p>
      */
     @Override
     public int getRemoveAbandonedTimeout() {
@@ -1734,14 +1745,17 @@
     }
 
     /**
-     * <p>Sets the timeout in seconds before an abandoned connection can be
-     * removed.</p>
+     * <p>
+     * Sets the timeout in seconds before an abandoned connection can be removed.
+     * </p>
      *
-     * <p>Setting this property has no effect if
-     * {@link #getRemoveAbandonedOnBorrow()} and
-     * {@link #getRemoveAbandonedOnMaintenance()} are false.</p>
+     * <p>
+     * Setting this property has no effect if {@link #getRemoveAbandonedOnBorrow()} and
+     * {@link #getRemoveAbandonedOnMaintenance()} are false.
+     * </p>
      *
-     * @param removeAbandonedTimeout new abandoned timeout in seconds
+     * @param removeAbandonedTimeout
+     *            new abandoned timeout in seconds
      * @see #getRemoveAbandonedTimeout()
      * @see #getRemoveAbandonedOnBorrow()
      * @see #getRemoveAbandonedOnMaintenance()
@@ -1758,14 +1772,16 @@
     }
 
     /**
-     * <p>Flag to log stack traces for application code which abandoned
-     * a Statement or Connection.
+     * <p>
+     * Flag to log stack traces for application code which abandoned a Statement or Connection.
      * </p>
-     * <p>Defaults to false.
+     * <p>
+     * Defaults to false.
      * </p>
-     * <p>Logging of abandoned Statements and Connections adds overhead
-     * for every Connection open or new Statement because a stack
-     * trace has to be generated. </p>
+     * <p>
+     * Logging of abandoned Statements and Connections adds overhead for every Connection open or new Statement because
+     * a stack trace has to be generated.
+     * </p>
      */
     @Override
     public boolean getLogAbandoned() {
@@ -1776,7 +1792,8 @@
     }
 
     /**
-     * @param logAbandoned new logAbandoned property value
+     * @param logAbandoned
+     *            new logAbandoned property value
      */
     public void setLogAbandoned(final boolean logAbandoned) {
         if (abandonedConfig == null) {
@@ -1790,8 +1807,9 @@
     }
 
     /**
-     * Gets the log writer to be used by this configuration to log
-     * information on abandoned objects.
+     * Gets the print writer used by this configuration to log information on abandoned objects.
+     *
+     * @return The print writer used by this configuration to log information on abandoned objects.
      */
     public PrintWriter getAbandonedLogWriter() {
         if (abandonedConfig != null) {
@@ -1801,10 +1819,10 @@
     }
 
     /**
-     * Sets the log writer to be used by this configuration to log
-     * information on abandoned objects.
+     * Sets the print writer to be used by this configuration to log information on abandoned objects.
      *
-     * @param logWriter The new log writer
+     * @param logWriter
+     *            The new log writer
      */
     public void setAbandonedLogWriter(final PrintWriter logWriter) {
         if (abandonedConfig == null) {
@@ -1819,9 +1837,8 @@
 
     /**
      * If the connection pool implements {@link org.apache.tomcat.dbcp.pool2.UsageTracking UsageTracking}, should the
-     * connection pool record a stack trace every time a method is called on a
-     * pooled connection and retain the most recent stack trace to aid debugging
-     * of abandoned connections?
+     * connection pool record a stack trace every time a method is called on a pooled connection and retain the most
+     * recent stack trace to aid debugging of abandoned connections?
      *
      * @return <code>true</code> if usage tracking is enabled
      */
@@ -1834,14 +1851,13 @@
     }
 
     /**
-     * If the connection pool implements {@link org.apache.tomcat.dbcp.pool2.UsageTracking UsageTracking}, configure
-     * whether the connection pool should record a stack trace every time a
-     * method is called on a pooled connection and retain the most recent stack
-     * trace to aid debugging of abandoned connections.
+     * If the connection pool implements {@link org.apache.tomcat.dbcp.pool2.UsageTracking UsageTracking}, configure whether
+     * the connection pool should record a stack trace every time a method is called on a pooled connection and retain
+     * the most recent stack trace to aid debugging of abandoned connections.
      *
-     * @param   usageTracking    A value of <code>true</code> will enable
-     *                              the recording of a stack trace on every use
-     *                              of a pooled connection
+     * @param usageTracking
+     *            A value of <code>true</code> will enable the recording of a stack trace on every use of a pooled
+     *            connection
      */
     public void setAbandonedUsageTracking(final boolean usageTracking) {
         if (abandonedConfig == null) {
@@ -1854,26 +1870,25 @@
         }
     }
 
-    // --------------------------------------------------------- Public Methods
-
     /**
-     * Add a custom connection property to the set that will be passed to our
-     * JDBC driver. This <strong>MUST</strong> be called before the first
-     * connection is retrieved (along with all the other configuration
-     * property setters). Calls to this method after the connection pool
-     * has been initialized have no effect.
+     * Adds a custom connection property to the set that will be passed to our JDBC driver. This <strong>MUST</strong>
+     * be called before the first connection is retrieved (along with all the other configuration property setters).
+     * Calls to this method after the connection pool has been initialized have no effect.
      *
-     * @param name Name of the custom connection property
-     * @param value Value of the custom connection property
+     * @param name
+     *            Name of the custom connection property
+     * @param value
+     *            Value of the custom connection property
      */
     public void addConnectionProperty(final String name, final String value) {
         connectionProperties.put(name, value);
     }
 
     /**
-     * Remove a custom connection property.
+     * Removes a custom connection property.
      *
-     * @param name Name of the custom connection property to remove
+     * @param name
+     *            Name of the custom connection property to remove
      * @see #addConnectionProperty(String, String)
      */
     public void removeConnectionProperty(final String name) {
@@ -1882,20 +1897,18 @@
 
     /**
      * Sets the connection properties passed to driver.connect(...).
-     *
+     * <p>
      * Format of the string must be [propertyName=property;]*
+     * </p>
+     * <p>
+     * NOTE - The "user" and "password" properties will be added explicitly, so they do not need to be included here.
+     * </p>
      *
-     * NOTE - The "user" and "password" properties will be added
-     * explicitly, so they do not need to be included here.
-     *
-     * @param connectionProperties the connection properties used to
-     * create new connections
+     * @param connectionProperties
+     *            the connection properties used to create new connections
      */
     public void setConnectionProperties(final String connectionProperties) {
-        if (connectionProperties == null) {
-            throw new NullPointerException("connectionProperties is null");
-        }
-
+        Objects.requireNonNull(connectionProperties, "connectionProperties is null");
         final String[] entries = connectionProperties.split(";");
         final Properties properties = new Properties();
         for (final String entry : entries) {
@@ -1917,32 +1930,32 @@
     private boolean closed;
 
     /**
-     * <p>Closes and releases all idle connections that are currently stored in the connection pool
-     * associated with this data source.</p>
+     * <p>
+     * Closes and releases all idle connections that are currently stored in the connection pool associated with this
+     * data source.
+     * </p>
+     * <p>
+     * Connections that are checked out to clients when this method is invoked are not affected. When client
+     * applications subsequently invoke {@link Connection#close()} to return these connections to the pool, the
+     * underlying JDBC connections are closed.
+     * </p>
+     * <p>
+     * Attempts to acquire connections using {@link #getConnection()} after this method has been invoked result in
+     * SQLExceptions.
+     * </p>
+     * <p>
+     * This method is idempotent - i.e., closing an already closed BasicDataSource has no effect and does not generate
+     * exceptions.
+     * </p>
      *
-     * <p>Connections that are checked out to clients when this method is invoked are not affected.
-     * When client applications subsequently invoke {@link Connection#close()} to return
-     * these connections to the pool, the underlying JDBC connections are closed.</p>
-     *
-     * <p>Attempts to acquire connections using {@link #getConnection()} after this method has been
-     * invoked result in SQLExceptions.</p>
-     *
-     * <p>This method is idempotent - i.e., closing an already closed BasicDataSource has no effect
-     * and does not generate exceptions.</p>
-     *
-     * @throws SQLException if an error occurs closing idle connections
+     * @throws SQLException
+     *             if an error occurs closing idle connections
      */
     @Override
     public synchronized void close() throws SQLException {
-        if (registeredJmxName != null) {
-            final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
-            try {
-                mbs.unregisterMBean(registeredJmxName);
-            } catch (final JMException e) {
-                log.warn("Failed to unregister the JMX name: " + registeredJmxName, e);
-            } finally {
-                registeredJmxName = null;
-            }
+        if (registeredJmxObjectName != null) {
+            registeredJmxObjectName.unregisterMBean();
+            registeredJmxObjectName = null;
         }
         closed = true;
         final GenericObjectPool<?> oldpool = connectionPool;
@@ -1952,15 +1965,16 @@
             if (oldpool != null) {
                 oldpool.close();
             }
-        } catch(final RuntimeException e) {
+        } catch (final RuntimeException e) {
             throw e;
-        } catch(final Exception e) {
+        } catch (final Exception e) {
             throw new SQLException(Utils.getMessage("pool.close.fail"), e);
         }
     }
 
     /**
      * If true, this data source is closed and no more connections can be retrieved from this datasource.
+     *
      * @return true, if the data source is closed; false otherwise
      */
     @Override
@@ -1984,8 +1998,11 @@
     }
 
     /**
-     * Manually invalidates a connection, effectively requesting the pool to try
-     * to close it, remove it from the pool and reclaim pool capacity.
+     * Manually invalidates a connection, effectively requesting the pool to try to close it, remove it from the pool
+     * and reclaim pool capacity.
+     *
+     * @param connection
+     *            The Connection to invalidate.
      *
      * @throws IllegalStateException
      *             if invalidating the connection failed.
@@ -2026,15 +2043,15 @@
 
     // ------------------------------------------------------ Protected Methods
 
-
     /**
-     * <p>Create (if necessary) and return the internal data source we are
-     * using to manage our connections.</p>
+     * <p>
+     * Creates (if necessary) and return the internal data source we are using to manage our connections.
+     * </p>
      *
-     * @throws SQLException if the object pool cannot be created.
+     * @throws SQLException
+     *             if the object pool cannot be created.
      */
-    protected DataSource createDataSource()
-        throws SQLException {
+    protected DataSource createDataSource() throws SQLException {
         if (closed) {
             throw new SQLException("Data source is closed");
         }
@@ -2059,12 +2076,9 @@
             boolean success = false;
             PoolableConnectionFactory poolableConnectionFactory;
             try {
-                poolableConnectionFactory = createPoolableConnectionFactory(
-                        driverConnectionFactory);
-                poolableConnectionFactory.setPoolStatements(
-                        poolPreparedStatements);
-                poolableConnectionFactory.setMaxOpenPreparedStatements(
-                        maxOpenPreparedStatements);
+                poolableConnectionFactory = createPoolableConnectionFactory(driverConnectionFactory);
+                poolableConnectionFactory.setPoolStatements(poolPreparedStatements);
+                poolableConnectionFactory.setMaxOpenPreparedStatements(maxOpenPreparedStatements);
                 success = true;
             } catch (final SQLException se) {
                 throw se;
@@ -2100,7 +2114,7 @@
 
             // If initialSize > 0, preload the pool
             try {
-                for (int i = 0 ; i < initialSize ; i++) {
+                for (int i = 0; i < initialSize; i++) {
                     connectionPool.addObject();
                 }
             } catch (final Exception e) {
@@ -2117,20 +2131,15 @@
     }
 
     /**
-     * Creates a JDBC connection factory for this datasource.  The JDBC driver
-     * is loaded using the following algorithm:
+     * Creates a JDBC connection factory for this datasource. The JDBC driver is loaded using the following algorithm:
      * <ol>
-     * <li>If a Driver instance has been specified via
-     * {@link #setDriver(Driver)} use it</li>
-     * <li>If no Driver instance was specified and {@link #driverClassName} is
-     * specified that class is loaded using the {@link ClassLoader} of this
-     * class or, if {@link #driverClassLoader} is set, {@link #driverClassName}
-     * is loaded with the specified {@link ClassLoader}.</li>
-     * <li>If {@link #driverClassName} is specified and the previous attempt
-     * fails, the class is loaded using the context class loader of the current
-     * thread.</li>
-     * <li>If a driver still isn't loaded one is loaded via the
-     * {@link DriverManager} using the specified {@link #url}.
+     * <li>If a Driver instance has been specified via {@link #setDriver(Driver)} use it</li>
+     * <li>If no Driver instance was specified and {@link #driverClassName} is specified that class is loaded using the
+     * {@link ClassLoader} of this class or, if {@link #driverClassLoader} is set, {@link #driverClassName} is loaded
+     * with the specified {@link ClassLoader}.</li>
+     * <li>If {@link #driverClassName} is specified and the previous attempt fails, the class is loaded using the
+     * context class loader of the current thread.</li>
+     * <li>If a driver still isn't loaded one is loaded via the {@link DriverManager} using the specified {@link #url}.
      * </ol>
      * This method exists so subclasses can replace the implementation class.
      */
@@ -2146,17 +2155,13 @@
                         if (driverClassLoader == null) {
                             driverFromCCL = Class.forName(driverClassName);
                         } else {
-                            driverFromCCL = Class.forName(
-                                    driverClassName, true, driverClassLoader);
+                            driverFromCCL = Class.forName(driverClassName, true, driverClassLoader);
                         }
                     } catch (final ClassNotFoundException cnfe) {
-                        driverFromCCL = Thread.currentThread(
-                                ).getContextClassLoader().loadClass(
-                                        driverClassName);
+                        driverFromCCL = Thread.currentThread().getContextClassLoader().loadClass(driverClassName);
                     }
                 } catch (final Exception t) {
-                    final String message = "Cannot load JDBC driver class '" +
-                        driverClassName + "'";
+                    final String message = "Cannot load JDBC driver class '" + driverClassName + "'";
                     logWriter.println(message);
                     t.printStackTrace(logWriter);
                     throw new SQLException(message, t);
@@ -2176,9 +2181,8 @@
                     }
                 }
             } catch (final Exception t) {
-                final String message = "Cannot create JDBC driver of class '" +
-                    (driverClassName != null ? driverClassName : "") +
-                    "' for connect URL '" + url + "'";
+                final String message = "Cannot create JDBC driver of class '"
+                        + (driverClassName != null ? driverClassName : "") + "' for connect URL '" + url + "'";
                 logWriter.println(message);
                 t.printStackTrace(logWriter);
                 throw new SQLException(message, t);
@@ -2186,7 +2190,7 @@
         }
 
         // Set up the driver connection factory we will use
-        final String user = username;
+        final String user = userName;
         if (user != null) {
             connectionProperties.put("user", user);
         } else {
@@ -2200,26 +2204,26 @@
             log("DBCP DataSource configured without a 'password'");
         }
 
-        final ConnectionFactory driverConnectionFactory =
-                new DriverConnectionFactory(driverToUse, url, connectionProperties);
+        final ConnectionFactory driverConnectionFactory = new DriverConnectionFactory(driverToUse, url,
+                connectionProperties);
         return driverConnectionFactory;
     }
 
     /**
-     * Creates a connection pool for this datasource.  This method only exists
-     * so subclasses can replace the implementation class.
-     *
-     * This implementation configures all pool properties other than
-     * timeBetweenEvictionRunsMillis.  Setting that property is deferred to
-     * {@link #startPoolMaintenance()}, since setting timeBetweenEvictionRunsMillis
-     * to a positive value causes {@link GenericObjectPool}'s eviction timer
-     * to be started.
+     * Creates a connection pool for this datasource. This method only exists so subclasses can replace the
+     * implementation class.
+     * <p>
+     * This implementation configures all pool properties other than timeBetweenEvictionRunsMillis. Setting that
+     * property is deferred to {@link #startPoolMaintenance()}, since setting timeBetweenEvictionRunsMillis to a
+     * positive value causes {@link GenericObjectPool}'s eviction timer to be started.
+     * </p>
      */
     protected void createConnectionPool(final PoolableConnectionFactory factory) {
         // Create an object pool to contain our active connections
-        final GenericObjectPoolConfig<PoolableConnection> config = new GenericObjectPoolConfig<>();
+        final GenericObjectPoolConfig config = new GenericObjectPoolConfig();
         updateJmxName(config);
-        config.setJmxEnabled(registeredJmxName != null);  // Disable JMX on the underlying pool if the DS is not registered.
+        // Disable JMX on the underlying pool if the DS is not registered:
+        config.setJmxEnabled(registeredJmxObjectName != null);
         final GenericObjectPool<PoolableConnection> gop = createObjectPool(factory, config, abandonedConfig);
         gop.setMaxTotal(maxTotal);
         gop.setMaxIdle(maxIdle);
@@ -2242,21 +2246,21 @@
     /**
      * Creates an object pool used to provide pooling support for {@link Connection JDBC connections}.
      *
-     * @param factory         the object factory
-     * @param poolConfig      the object pool configuration
-     * @param abandonedConfig the abandoned objects configuration
+     * @param factory
+     *            the object factory
+     * @param poolConfig
+     *            the object pool configuration
+     * @param abandonedConfig
+     *            the abandoned objects configuration
      * @return a non-null instance
      */
-    protected  GenericObjectPool<PoolableConnection> createObjectPool(
-            final PoolableConnectionFactory factory, final GenericObjectPoolConfig<PoolableConnection> poolConfig,
-            final AbandonedConfig abandonedConfig) {
+    protected GenericObjectPool<PoolableConnection> createObjectPool(final PoolableConnectionFactory factory,
+            final GenericObjectPoolConfig poolConfig, final AbandonedConfig abandonedConfig) {
         GenericObjectPool<PoolableConnection> gop;
-        if (abandonedConfig != null &&
-                (abandonedConfig.getRemoveAbandonedOnBorrow() ||
-                        abandonedConfig.getRemoveAbandonedOnMaintenance())) {
+        if (abandonedConfig != null && (abandonedConfig.getRemoveAbandonedOnBorrow()
+                || abandonedConfig.getRemoveAbandonedOnMaintenance())) {
             gop = new GenericObjectPool<>(factory, poolConfig, abandonedConfig);
-        }
-        else {
+        } else {
             gop = new GenericObjectPool<>(factory, poolConfig);
         }
         return gop;
@@ -2272,7 +2276,7 @@
             if (oldpool != null) {
                 oldpool.close();
             }
-        } catch(final Exception e) {
+        } catch (final Exception e) {
             /* Ignore */
         }
     }
@@ -2287,10 +2291,11 @@
     }
 
     /**
-     * Creates the actual data source instance.  This method only exists so
-     * that subclasses can replace the implementation class.
+     * Creates the actual data source instance. This method only exists so that subclasses can replace the
+     * implementation class.
      *
-     * @throws SQLException if unable to create a datasource instance
+     * @throws SQLException
+     *             if unable to create a datasource instance
      */
     protected DataSource createDataSourceInstance() throws SQLException {
         final PoolingDataSource<PoolableConnection> pds = new PoolingDataSource<>(connectionPool);
@@ -2299,19 +2304,22 @@
     }
 
     /**
-     * Creates the PoolableConnectionFactory and attaches it to the connection pool.  This method only exists
-     * so subclasses can replace the default implementation.
+     * Creates the PoolableConnectionFactory and attaches it to the connection pool. This method only exists so
+     * subclasses can replace the default implementation.
      *
-     * @param driverConnectionFactory JDBC connection factory
-     * @throws SQLException if an error occurs creating the PoolableConnectionFactory
+     * @param driverConnectionFactory
+     *            JDBC connection factory
+     * @throws SQLException
+     *             if an error occurs creating the PoolableConnectionFactory
      */
-    protected PoolableConnectionFactory createPoolableConnectionFactory(
-            final ConnectionFactory driverConnectionFactory) throws SQLException {
+    protected PoolableConnectionFactory createPoolableConnectionFactory(final ConnectionFactory driverConnectionFactory)
+            throws SQLException {
         PoolableConnectionFactory connectionFactory = null;
         try {
-            connectionFactory = new PoolableConnectionFactory(driverConnectionFactory, registeredJmxName);
+            connectionFactory = new PoolableConnectionFactory(driverConnectionFactory,
+                    ObjectNameWrapper.unwrap(registeredJmxObjectName));
             connectionFactory.setValidationQuery(validationQuery);
-            connectionFactory.setValidationQueryTimeout(validationQueryTimeout);
+            connectionFactory.setValidationQueryTimeout(validationQueryTimeoutSeconds);
             connectionFactory.setConnectionInitSql(connectionInitSqls);
             connectionFactory.setDefaultReadOnly(defaultReadOnly);
             connectionFactory.setDefaultAutoCommit(defaultAutoCommit);
@@ -2335,8 +2343,8 @@
         return connectionFactory;
     }
 
-    protected static void validateConnectionFactory(
-            final PoolableConnectionFactory connectionFactory) throws Exception {
+    protected static void validateConnectionFactory(final PoolableConnectionFactory connectionFactory)
+            throws Exception {
         PoolableConnection conn = null;
         PooledObject<PoolableConnection> p = null;
         try {
@@ -2345,8 +2353,7 @@
             connectionFactory.activateObject(p);
             connectionFactory.validateConnection(conn);
             connectionFactory.passivateObject(p);
-        }
-        finally {
+        } finally {
             if (p != null) {
                 connectionFactory.destroyObject(p);
             }
@@ -2362,11 +2369,11 @@
     /**
      * Actual name under which this component has been registered.
      */
-    private ObjectName registeredJmxName = null;
+    private ObjectNameWrapper registeredJmxObjectName;
 
     private void jmxRegister() {
         // Return immediately if this DataSource has already been registered
-        if (registeredJmxName != null) {
+        if (registeredJmxObjectName != null) {
             return;
         }
         // Return immediately if no JMX name has been specified
@@ -2374,39 +2381,27 @@
         if (requestedName == null) {
             return;
         }
-        ObjectName oname;
         try {
-             oname = new ObjectName(requestedName);
+            ObjectNameWrapper.wrap(requestedName).registerMBean(this);
         } catch (final MalformedObjectNameException e) {
-            log.warn("The requested JMX name [" + requestedName +
-                    "] was not valid and will be ignored.");
-            return;
-        }
-
-        final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
-        try {
-            mbs.registerMBean(this, oname);
-        } catch (InstanceAlreadyExistsException | MBeanRegistrationException
-                | NotCompliantMBeanException e) {
-            log.warn("Failed to complete JMX registration", e);
+            log.warn("The requested JMX name [" + requestedName + "] was not valid and will be ignored.");
         }
     }
 
     @Override
-    public ObjectName preRegister(final MBeanServer server, final ObjectName name) {
+    public ObjectName preRegister(final MBeanServer server, final ObjectName objectName) {
         final String requestedName = getJmxName();
         if (requestedName != null) {
             try {
-                registeredJmxName = new ObjectName(requestedName);
+                registeredJmxObjectName = ObjectNameWrapper.wrap(requestedName);
             } catch (final MalformedObjectNameException e) {
-                log.warn("The requested JMX name [" + requestedName +
-                        "] was not valid and will be ignored.");
+                log.warn("The requested JMX name [" + requestedName + "] was not valid and will be ignored.");
             }
         }
-        if (registeredJmxName == null) {
-            registeredJmxName = name;
+        if (registeredJmxObjectName == null) {
+            registeredJmxObjectName = ObjectNameWrapper.wrap(objectName);
         }
-        return registeredJmxName;
+        return ObjectNameWrapper.unwrap(registeredJmxObjectName);
     }
 
     @Override
@@ -2424,18 +2419,18 @@
         // NO-OP
     }
 
-    private void updateJmxName(final GenericObjectPoolConfig<PoolableConnection> config) {
-        if (registeredJmxName == null) {
+    private void updateJmxName(final GenericObjectPoolConfig config) {
+        if (registeredJmxObjectName == null) {
             return;
         }
-        final StringBuilder base = new StringBuilder(registeredJmxName.toString());
+        final StringBuilder base = new StringBuilder(registeredJmxObjectName.toString());
         base.append(Constants.JMX_CONNECTION_POOL_BASE_EXT);
         config.setJmxNameBase(base.toString());
         config.setJmxNamePrefix(Constants.JMX_CONNECTION_POOL_PREFIX);
     }
 
     protected ObjectName getRegisteredJmxName() {
-        return registeredJmxName;
+        return ObjectNameWrapper.unwrap(registeredJmxObjectName);
     }
 
     /**
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceFactory.java b/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceFactory.java
index fc9f915..671d012 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceFactory.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceFactory.java
@@ -43,19 +43,16 @@
 import org.apache.tomcat.dbcp.pool2.impl.GenericObjectPoolConfig;
 
 /**
- * <p>JNDI object factory that creates an instance of
- * <code>BasicDataSource</code> that has been configured based on the
- * <code>RefAddr</code> values of the specified <code>Reference</code>, which
- * must match the names and data types of the <code>BasicDataSource</code> bean
- * properties with the following exceptions:</p>
+ * <p>
+ * JNDI object factory that creates an instance of <code>BasicDataSource</code> that has been configured based on the
+ * <code>RefAddr</code> values of the specified <code>Reference</code>, which must match the names and data types of the
+ * <code>BasicDataSource</code> bean properties with the following exceptions:
+ * </p>
  * <ul>
- * <li><code>connectionInitSqls</code> must be passed to this factory as a
- *     single String using semi-colon to delimit the statements whereas
- *     <code>BasicDataSource</code> requires a collection of Strings.</li>
+ * <li><code>connectionInitSqls</code> must be passed to this factory as a single String using semi-colon to delimit the
+ * statements whereas <code>BasicDataSource</code> requires a collection of Strings.</li>
  * </ul>
  *
- * @author Craig R. McClanahan
- * @author Dirk Verbeeck
  * @since 2.0
  */
 public class BasicDataSourceFactory implements ObjectFactory {
@@ -66,7 +63,7 @@
     private static final String PROP_DEFAULTREADONLY = "defaultReadOnly";
     private static final String PROP_DEFAULTTRANSACTIONISOLATION = "defaultTransactionIsolation";
     private static final String PROP_DEFAULTCATALOG = "defaultCatalog";
-    private static final String PROP_CACHESTATE ="cacheState";
+    private static final String PROP_CACHESTATE = "cacheState";
     private static final String PROP_DRIVERCLASSNAME = "driverClassName";
     private static final String PROP_LIFO = "lifo";
     private static final String PROP_MAXTOTAL = "maxTotal";
@@ -91,8 +88,7 @@
     private static final String PROP_JMX_NAME = "jmxName";
 
     /**
-     * The property name for connectionInitSqls.
-     * The associated value String must be of the form [query;]*
+     * The property name for connectionInitSqls. The associated value String must be of the form [query;]*
      */
     private static final String PROP_CONNECTIONINITSQLS = "connectionInitSqls";
     private static final String PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED = "accessToUnderlyingConnectionAllowed";
@@ -117,98 +113,58 @@
     private static final String PROP_DISCONNECTION_SQL_CODES = "disconnectionSqlCodes";
 
     /*
-     * Block with obsolete properties from DBCP 1.x.
-     * Warn users that these are ignored and they should use the 2.x properties.
+     * Block with obsolete properties from DBCP 1.x. Warn users that these are ignored and they should use the 2.x
+     * properties.
      */
     private static final String NUPROP_MAXACTIVE = "maxActive";
     private static final String NUPROP_REMOVEABANDONED = "removeAbandoned";
     private static final String NUPROP_MAXWAIT = "maxWait";
 
     /*
-     * Block with properties expected in a DataSource
-     * This props will not be listed as ignored - we know that they may appear in Resource,
-     * and not listing them as ignored.
+     * Block with properties expected in a DataSource This props will not be listed as ignored - we know that they may
+     * appear in Resource, and not listing them as ignored.
      */
     private static final String SILENTPROP_FACTORY = "factory";
     private static final String SILENTPROP_SCOPE = "scope";
     private static final String SILENTPROP_SINGLETON = "singleton";
     private static final String SILENTPROP_AUTH = "auth";
 
-    private static final String[] ALL_PROPERTIES = {
-        PROP_DEFAULTAUTOCOMMIT,
-        PROP_DEFAULTREADONLY,
-        PROP_DEFAULTTRANSACTIONISOLATION,
-        PROP_DEFAULTCATALOG,
-        PROP_CACHESTATE,
-        PROP_DRIVERCLASSNAME,
-        PROP_LIFO,
-        PROP_MAXTOTAL,
-        PROP_MAXIDLE,
-        PROP_MINIDLE,
-        PROP_INITIALSIZE,
-        PROP_MAXWAITMILLIS,
-        PROP_TESTONCREATE,
-        PROP_TESTONBORROW,
-        PROP_TESTONRETURN,
-        PROP_TIMEBETWEENEVICTIONRUNSMILLIS,
-        PROP_NUMTESTSPEREVICTIONRUN,
-        PROP_MINEVICTABLEIDLETIMEMILLIS,
-        PROP_SOFTMINEVICTABLEIDLETIMEMILLIS,
-        PROP_EVICTIONPOLICYCLASSNAME,
-        PROP_TESTWHILEIDLE,
-        PROP_PASSWORD,
-        PROP_URL,
-        PROP_USERNAME,
-        PROP_VALIDATIONQUERY,
-        PROP_VALIDATIONQUERY_TIMEOUT,
-        PROP_CONNECTIONINITSQLS,
-        PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED,
-        PROP_REMOVEABANDONEDONBORROW,
-        PROP_REMOVEABANDONEDONMAINTENANCE,
-        PROP_REMOVEABANDONEDTIMEOUT,
-        PROP_LOGABANDONED,
-        PROP_ABANDONEDUSAGETRACKING,
-        PROP_POOLPREPAREDSTATEMENTS,
-        PROP_MAXOPENPREPAREDSTATEMENTS,
-        PROP_CONNECTIONPROPERTIES,
-        PROP_MAXCONNLIFETIMEMILLIS,
-        PROP_LOGEXPIREDCONNECTIONS,
-        PROP_ROLLBACK_ON_RETURN,
-        PROP_ENABLE_AUTOCOMMIT_ON_RETURN,
-        PROP_DEFAULT_QUERYTIMEOUT,
-        PROP_FASTFAIL_VALIDATION,
-        PROP_DISCONNECTION_SQL_CODES
-    };
+    private static final String[] ALL_PROPERTIES = {PROP_DEFAULTAUTOCOMMIT, PROP_DEFAULTREADONLY,
+            PROP_DEFAULTTRANSACTIONISOLATION, PROP_DEFAULTCATALOG, PROP_CACHESTATE, PROP_DRIVERCLASSNAME, PROP_LIFO,
+            PROP_MAXTOTAL, PROP_MAXIDLE, PROP_MINIDLE, PROP_INITIALSIZE, PROP_MAXWAITMILLIS, PROP_TESTONCREATE,
+            PROP_TESTONBORROW, PROP_TESTONRETURN, PROP_TIMEBETWEENEVICTIONRUNSMILLIS, PROP_NUMTESTSPEREVICTIONRUN,
+            PROP_MINEVICTABLEIDLETIMEMILLIS, PROP_SOFTMINEVICTABLEIDLETIMEMILLIS, PROP_EVICTIONPOLICYCLASSNAME,
+            PROP_TESTWHILEIDLE, PROP_PASSWORD, PROP_URL, PROP_USERNAME, PROP_VALIDATIONQUERY,
+            PROP_VALIDATIONQUERY_TIMEOUT, PROP_CONNECTIONINITSQLS, PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED,
+            PROP_REMOVEABANDONEDONBORROW, PROP_REMOVEABANDONEDONMAINTENANCE, PROP_REMOVEABANDONEDTIMEOUT,
+            PROP_LOGABANDONED, PROP_ABANDONEDUSAGETRACKING, PROP_POOLPREPAREDSTATEMENTS, PROP_MAXOPENPREPAREDSTATEMENTS,
+            PROP_CONNECTIONPROPERTIES, PROP_MAXCONNLIFETIMEMILLIS, PROP_LOGEXPIREDCONNECTIONS, PROP_ROLLBACK_ON_RETURN,
+            PROP_ENABLE_AUTOCOMMIT_ON_RETURN, PROP_DEFAULT_QUERYTIMEOUT, PROP_FASTFAIL_VALIDATION,
+            PROP_DISCONNECTION_SQL_CODES, PROP_JMX_NAME };
 
     /**
-     * Obsolete properties from DBCP 1.x. with warning strings suggesting
-     * new properties. LinkedHashMap will guarantee that properties will be listed
-     * to output in order of insertion into map.
+     * Obsolete properties from DBCP 1.x. with warning strings suggesting new properties. LinkedHashMap will guarantee
+     * that properties will be listed to output in order of insertion into map.
      */
     private static final Map<String, String> NUPROP_WARNTEXT = new LinkedHashMap<>();
 
     static {
-        NUPROP_WARNTEXT.put(
-                NUPROP_MAXACTIVE,
+        NUPROP_WARNTEXT.put(NUPROP_MAXACTIVE,
                 "Property " + NUPROP_MAXACTIVE + " is not used in DBCP2, use " + PROP_MAXTOTAL + " instead. "
-                        + PROP_MAXTOTAL + " default value is " + GenericObjectPoolConfig.DEFAULT_MAX_TOTAL+".");
-        NUPROP_WARNTEXT.put(
-                NUPROP_REMOVEABANDONED,
-                "Property " + NUPROP_REMOVEABANDONED + " is not used in DBCP2,"
-                        + " use one or both of "
+                        + PROP_MAXTOTAL + " default value is " + GenericObjectPoolConfig.DEFAULT_MAX_TOTAL + ".");
+        NUPROP_WARNTEXT.put(NUPROP_REMOVEABANDONED,
+                "Property " + NUPROP_REMOVEABANDONED + " is not used in DBCP2," + " use one or both of "
                         + PROP_REMOVEABANDONEDONBORROW + " or " + PROP_REMOVEABANDONEDONMAINTENANCE + " instead. "
                         + "Both have default value set to false.");
-        NUPROP_WARNTEXT.put(
-                NUPROP_MAXWAIT,
-                "Property " + NUPROP_MAXWAIT + " is not used in DBCP2"
-                        + " , use " + PROP_MAXWAITMILLIS + " instead. "
-                        + PROP_MAXWAITMILLIS + " default value is " + BaseObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS+".");
+        NUPROP_WARNTEXT.put(NUPROP_MAXWAIT,
+                "Property " + NUPROP_MAXWAIT + " is not used in DBCP2" + " , use " + PROP_MAXWAITMILLIS + " instead. "
+                        + PROP_MAXWAITMILLIS + " default value is " + BaseObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS
+                        + ".");
     }
 
     /**
-     * Silent Properties.
-     * These properties will not be listed as ignored - we know that they may appear in JDBC Resource references,
-     * and we will not list them as ignored.
+     * Silent Properties. These properties will not be listed as ignored - we know that they may appear in JDBC Resource
+     * references, and we will not list them as ignored.
      */
     private static final List<String> SILENT_PROPERTIES = new ArrayList<>();
 
@@ -223,23 +179,28 @@
     // -------------------------------------------------- ObjectFactory Methods
 
     /**
-     * <p>Create and return a new <code>BasicDataSource</code> instance.  If no
-     * instance can be created, return <code>null</code> instead.</p>
+     * <p>
+     * Create and return a new <code>BasicDataSource</code> instance. If no instance can be created, return
+     * <code>null</code> instead.
+     * </p>
      *
-     * @param obj The possibly null object containing location or
-     *  reference information that can be used in creating an object
-     * @param name The name of this object relative to <code>nameCtx</code>
-     * @param nameCtx The context relative to which the <code>name</code>
-     *  parameter is specified, or <code>null</code> if <code>name</code>
-     *  is relative to the default initial context
-     * @param environment The possibly null environment that is used in
-     *  creating this object
+     * @param obj
+     *            The possibly null object containing location or reference information that can be used in creating an
+     *            object
+     * @param name
+     *            The name of this object relative to <code>nameCtx</code>
+     * @param nameCtx
+     *            The context relative to which the <code>name</code> parameter is specified, or <code>null</code> if
+     *            <code>name</code> is relative to the default initial context
+     * @param environment
+     *            The possibly null environment that is used in creating this object
      *
-     * @throws Exception if an exception occurs creating the instance
+     * @throws Exception
+     *             if an exception occurs creating the instance
      */
     @Override
-    public Object getObjectInstance(final Object obj, final Name name, final Context nameCtx, final Hashtable<?,?> environment)
-        throws Exception {
+    public Object getObjectInstance(final Object obj, final Name name, final Context nameCtx,
+            final Hashtable<?, ?> environment) throws Exception {
 
         // We only know how to deal with <code>javax.naming.Reference</code>s
         // that specify a class name of "javax.sql.DataSource"
@@ -275,29 +236,30 @@
     }
 
     /**
-     * Collects warnings and info messages.  Warnings are generated when an obsolete
-     * property is set.  Unknown properties generate info messages.
+     * Collects warnings and info messages. Warnings are generated when an obsolete property is set. Unknown properties
+     * generate info messages.
      *
-     * @param ref Reference to check properties of
-     * @param name Name provided to getObject
-     * @param warnings container for warning messages
-     * @param infoMessages container for info messages
+     * @param ref
+     *            Reference to check properties of
+     * @param name
+     *            Name provided to getObject
+     * @param warnings
+     *            container for warning messages
+     * @param infoMessages
+     *            container for info messages
      */
     private void validatePropertyNames(final Reference ref, final Name name, final List<String> warnings,
-                                      final List<String> infoMessages) {
+            final List<String> infoMessages) {
         final List<String> allPropsAsList = Arrays.asList(ALL_PROPERTIES);
         final String nameString = name != null ? "Name = " + name.toString() + " " : "";
-        if (NUPROP_WARNTEXT!=null && !NUPROP_WARNTEXT.keySet().isEmpty()) {
+        if (NUPROP_WARNTEXT != null && !NUPROP_WARNTEXT.keySet().isEmpty()) {
             for (final String propertyName : NUPROP_WARNTEXT.keySet()) {
                 final RefAddr ra = ref.get(propertyName);
                 if (ra != null && !allPropsAsList.contains(ra.getType())) {
                     final StringBuilder stringBuilder = new StringBuilder(nameString);
                     final String propertyValue = ra.getContent().toString();
-                    stringBuilder.append(NUPROP_WARNTEXT.get(propertyName))
-                            .append(" You have set value of \"")
-                            .append(propertyValue)
-                            .append("\" for \"")
-                            .append(propertyName)
+                    stringBuilder.append(NUPROP_WARNTEXT.get(propertyName)).append(" You have set value of \"")
+                            .append(propertyValue).append("\" for \"").append(propertyName)
                             .append("\" property, which is being ignored.");
                     warnings.add(stringBuilder.toString());
                 }
@@ -310,28 +272,25 @@
             final String propertyName = ra.getType();
             // If property name is not in the properties list, we haven't warned on it
             // and it is not in the "silent" list, tell user we are ignoring it.
-            if (!(allPropsAsList.contains(propertyName)
-                    || NUPROP_WARNTEXT.keySet().contains(propertyName)
+            if (!(allPropsAsList.contains(propertyName) || NUPROP_WARNTEXT.keySet().contains(propertyName)
                     || SILENT_PROPERTIES.contains(propertyName))) {
                 final String propertyValue = ra.getContent().toString();
                 final StringBuilder stringBuilder = new StringBuilder(nameString);
-                stringBuilder.append("Ignoring unknown property: ")
-                        .append("value of \"")
-                        .append(propertyValue)
-                        .append("\" for \"")
-                        .append(propertyName)
-                        .append("\" property");
+                stringBuilder.append("Ignoring unknown property: ").append("value of \"").append(propertyValue)
+                        .append("\" for \"").append(propertyName).append("\" property");
                 infoMessages.add(stringBuilder.toString());
             }
         }
     }
 
     /**
-     * Creates and configures a {@link BasicDataSource} instance based on the
-     * given properties.
+     * Creates and configures a {@link BasicDataSource} instance based on the given properties.
      *
-     * @param properties the datasource configuration properties
-     * @throws Exception if an error occurs creating the data source
+     * @param properties
+     *            The data source configuration properties.
+     * @return A new a {@link BasicDataSource} instance based on the given properties.
+     * @throws Exception
+     *             Thrown when an error occurs creating the data source.
      */
     public static BasicDataSource createDataSource(final Properties properties) throws Exception {
         final BasicDataSource dataSource = new BasicDataSource();
@@ -352,20 +311,15 @@
             int level = PoolableConnectionFactory.UNKNOWN_TRANSACTIONISOLATION;
             if ("NONE".equalsIgnoreCase(value)) {
                 level = Connection.TRANSACTION_NONE;
-            }
-            else if ("READ_COMMITTED".equalsIgnoreCase(value)) {
+            } else if ("READ_COMMITTED".equalsIgnoreCase(value)) {
                 level = Connection.TRANSACTION_READ_COMMITTED;
-            }
-            else if ("READ_UNCOMMITTED".equalsIgnoreCase(value)) {
+            } else if ("READ_UNCOMMITTED".equalsIgnoreCase(value)) {
                 level = Connection.TRANSACTION_READ_UNCOMMITTED;
-            }
-            else if ("REPEATABLE_READ".equalsIgnoreCase(value)) {
+            } else if ("REPEATABLE_READ".equalsIgnoreCase(value)) {
                 level = Connection.TRANSACTION_REPEATABLE_READ;
-            }
-            else if ("SERIALIZABLE".equalsIgnoreCase(value)) {
+            } else if ("SERIALIZABLE".equalsIgnoreCase(value)) {
                 level = Connection.TRANSACTION_SERIALIZABLE;
-            }
-            else {
+            } else {
                 try {
                     level = Integer.parseInt(value);
                 } catch (final NumberFormatException e) {
@@ -540,12 +494,12 @@
 
         value = properties.getProperty(PROP_CONNECTIONPROPERTIES);
         if (value != null) {
-          final Properties p = getProperties(value);
-          final Enumeration<?> e = p.propertyNames();
-          while (e.hasMoreElements()) {
-            final String propertyName = (String) e.nextElement();
-            dataSource.addConnectionProperty(propertyName, p.getProperty(propertyName));
-          }
+            final Properties p = getProperties(value);
+            final Enumeration<?> e = p.propertyNames();
+            while (e.hasMoreElements()) {
+                final String propertyName = (String) e.nextElement();
+                dataSource.addConnectionProperty(propertyName, p.getProperty(propertyName));
+            }
         }
 
         value = properties.getProperty(PROP_MAXCONNLIFETIMEMILLIS);
@@ -599,24 +553,29 @@
     }
 
     /**
-     * <p>Parse properties from the string. Format of the string must be [propertyName=property;]*<p>
+     * <p>
+     * Parse properties from the string. Format of the string must be [propertyName=property;]*
+     * <p>
+     *
      * @param propText
      * @return Properties
      * @throws Exception
      */
     private static Properties getProperties(final String propText) throws Exception {
-      final Properties p = new Properties();
-      if (propText != null) {
-        p.load(new ByteArrayInputStream(
-                propText.replace(';', '\n').getBytes(StandardCharsets.ISO_8859_1)));
-      }
-      return p;
+        final Properties p = new Properties();
+        if (propText != null) {
+            p.load(new ByteArrayInputStream(propText.replace(';', '\n').getBytes(StandardCharsets.ISO_8859_1)));
+        }
+        return p;
     }
 
     /**
      * Parse list of property values from a delimited string
-     * @param value delimited list of values
-     * @param delimiter character used to separate values in the list
+     *
+     * @param value
+     *            delimited list of values
+     * @param delimiter
+     *            character used to separate values in the list
      * @return String Collection of values
      */
     private static Collection<String> parseList(final String value, final char delimiter) {
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceMXBean.java b/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceMXBean.java
index ed797ad..0878d14 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceMXBean.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceMXBean.java
@@ -25,198 +25,231 @@
 
     /**
      * See {@link BasicDataSource#getAbandonedUsageTracking()}
+     *
      * @return {@link BasicDataSource#getAbandonedUsageTracking()}
      */
     boolean getAbandonedUsageTracking();
 
     /**
      * See {@link BasicDataSource#getDefaultAutoCommit()}
+     *
      * @return {@link BasicDataSource#getDefaultAutoCommit()}
      */
     Boolean getDefaultAutoCommit();
 
     /**
      * See {@link BasicDataSource#getDefaultReadOnly()}
+     *
      * @return {@link BasicDataSource#getDefaultReadOnly()}
      */
     Boolean getDefaultReadOnly();
 
     /**
      * See {@link BasicDataSource#getDefaultTransactionIsolation()}
+     *
      * @return {@link BasicDataSource#getDefaultTransactionIsolation()}
      */
     int getDefaultTransactionIsolation();
 
     /**
      * See {@link BasicDataSource#getDefaultCatalog()}
+     *
      * @return {@link BasicDataSource#getDefaultCatalog()}
      */
     String getDefaultCatalog();
 
     /**
      * See {@link BasicDataSource#getCacheState()}
+     *
      * @return {@link BasicDataSource#getCacheState()}
      */
     boolean getCacheState();
 
     /**
      * See {@link BasicDataSource#getDriverClassName()}
+     *
      * @return {@link BasicDataSource#getDriverClassName()}
      */
     String getDriverClassName();
 
     /**
      * See {@link BasicDataSource#getLifo()}
+     *
      * @return {@link BasicDataSource#getLifo()}
      */
     boolean getLifo();
 
     /**
      * See {@link BasicDataSource#getMaxTotal()}
+     *
      * @return {@link BasicDataSource#getMaxTotal()}
      */
     int getMaxTotal();
 
     /**
      * See {@link BasicDataSource#getMaxIdle()}
+     *
      * @return {@link BasicDataSource#getMaxIdle()}
      */
     int getMaxIdle();
 
     /**
      * See {@link BasicDataSource#getMinIdle()}
+     *
      * @return {@link BasicDataSource#getMinIdle()}
      */
     int getMinIdle();
 
     /**
      * See {@link BasicDataSource#getInitialSize()}
+     *
      * @return {@link BasicDataSource#getInitialSize()}
      */
     int getInitialSize();
 
     /**
      * See {@link BasicDataSource#getMaxWaitMillis()}
+     *
      * @return {@link BasicDataSource#getMaxWaitMillis()}
      */
     long getMaxWaitMillis();
 
     /**
      * See {@link BasicDataSource#isPoolPreparedStatements()}
+     *
      * @return {@link BasicDataSource#isPoolPreparedStatements()}
      */
     boolean isPoolPreparedStatements();
 
     /**
      * See {@link BasicDataSource#getMaxOpenPreparedStatements()}
+     *
      * @return {@link BasicDataSource#getMaxOpenPreparedStatements()}
      */
     int getMaxOpenPreparedStatements();
 
     /**
      * See {@link BasicDataSource#getTestOnCreate()}
+     *
      * @return {@link BasicDataSource#getTestOnCreate()}
      */
     boolean getTestOnCreate();
 
     /**
      * See {@link BasicDataSource#getTestOnBorrow()}
+     *
      * @return {@link BasicDataSource#getTestOnBorrow()}
      */
     boolean getTestOnBorrow();
 
     /**
      * See {@link BasicDataSource#getTimeBetweenEvictionRunsMillis()}
+     *
      * @return {@link BasicDataSource#getTimeBetweenEvictionRunsMillis()}
      */
     long getTimeBetweenEvictionRunsMillis();
 
     /**
      * See {@link BasicDataSource#getNumTestsPerEvictionRun()}
+     *
      * @return {@link BasicDataSource#getNumTestsPerEvictionRun()}
      */
     int getNumTestsPerEvictionRun();
 
     /**
      * See {@link BasicDataSource#getMinEvictableIdleTimeMillis()}
+     *
      * @return {@link BasicDataSource#getMinEvictableIdleTimeMillis()}
      */
     long getMinEvictableIdleTimeMillis();
 
     /**
      * See {@link BasicDataSource#getSoftMinEvictableIdleTimeMillis()}
+     *
      * @return {@link BasicDataSource#getSoftMinEvictableIdleTimeMillis()}
      */
     long getSoftMinEvictableIdleTimeMillis();
 
     /**
      * See {@link BasicDataSource#getTestWhileIdle()}
+     *
      * @return {@link BasicDataSource#getTestWhileIdle()}
      */
     boolean getTestWhileIdle();
 
     /**
      * See {@link BasicDataSource#getNumActive()}
+     *
      * @return {@link BasicDataSource#getNumActive()}
      */
     int getNumActive();
 
     /**
      * See {@link BasicDataSource#getNumIdle()}
+     *
      * @return {@link BasicDataSource#getNumIdle()}
      */
     int getNumIdle();
 
     /**
      * See {@link BasicDataSource#getPassword()}
+     *
      * @return {@link BasicDataSource#getPassword()}
      */
     String getPassword();
 
     /**
      * See {@link BasicDataSource#getUrl()}
+     *
      * @return {@link BasicDataSource#getUrl()}
      */
     String getUrl();
 
     /**
      * See {@link BasicDataSource#getUsername()}
+     *
      * @return {@link BasicDataSource#getUsername()}
      */
     String getUsername();
 
     /**
      * See {@link BasicDataSource#getValidationQuery()}
+     *
      * @return {@link BasicDataSource#getValidationQuery()}
      */
     String getValidationQuery();
 
     /**
      * See {@link BasicDataSource#getValidationQueryTimeout()}
+     *
      * @return {@link BasicDataSource#getValidationQueryTimeout()}
      */
     int getValidationQueryTimeout();
 
     /**
      * See {@link BasicDataSource#getConnectionInitSqlsAsArray()}
+     *
      * @return {@link BasicDataSource#getConnectionInitSqlsAsArray()}
      */
     String[] getConnectionInitSqlsAsArray();
 
     /**
      * See {@link BasicDataSource#isAccessToUnderlyingConnectionAllowed()}
+     *
      * @return {@link BasicDataSource#isAccessToUnderlyingConnectionAllowed()}
      */
     boolean isAccessToUnderlyingConnectionAllowed();
 
     /**
      * See {@link BasicDataSource#getMaxConnLifetimeMillis()}
+     *
      * @return {@link BasicDataSource#getMaxConnLifetimeMillis()}
      */
     long getMaxConnLifetimeMillis();
 
     /**
      * See {@link BasicDataSource#getLogExpiredConnections()}
+     *
      * @return {@link BasicDataSource#getLogExpiredConnections()}
      * @since 2.1
      */
@@ -224,36 +257,42 @@
 
     /**
      * See {@link BasicDataSource#getRemoveAbandonedOnBorrow()}
+     *
      * @return {@link BasicDataSource#getRemoveAbandonedOnBorrow()}
      */
     boolean getRemoveAbandonedOnBorrow();
 
     /**
      * See {@link BasicDataSource#getRemoveAbandonedOnMaintenance()}
+     *
      * @return {@link BasicDataSource#getRemoveAbandonedOnMaintenance()}
      */
     boolean getRemoveAbandonedOnMaintenance();
 
     /**
      * See {@link BasicDataSource#getRemoveAbandonedTimeout()}
+     *
      * @return {@link BasicDataSource#getRemoveAbandonedTimeout()}
      */
     int getRemoveAbandonedTimeout();
 
     /**
      * See {@link BasicDataSource#getLogAbandoned()}
+     *
      * @return {@link BasicDataSource#getLogAbandoned()}
      */
     boolean getLogAbandoned();
 
     /**
      * See {@link BasicDataSource#isClosed()}
+     *
      * @return {@link BasicDataSource#isClosed()}
      */
     boolean isClosed();
 
     /**
      * See {@link BasicDataSource#getFastFailValidation()}
+     *
      * @return {@link BasicDataSource#getFastFailValidation()}
      * @since 2.1
      */
@@ -261,6 +300,7 @@
 
     /**
      * See {@link BasicDataSource#getDisconnectionSqlCodesAsArray()}
+     *
      * @return {@link BasicDataSource#getDisconnectionSqlCodesAsArray()}
      * @since 2.1
      */
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/ConnectionFactory.java b/java/org/apache/tomcat/dbcp/dbcp2/ConnectionFactory.java
index 7dd9682..d01c3e4 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/ConnectionFactory.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/ConnectionFactory.java
@@ -22,16 +22,15 @@
 /**
  * Abstract factory interface for creating {@link java.sql.Connection}s.
  *
- * @author Rodney Waldhoff
  * @since 2.0
  */
 public interface ConnectionFactory {
     /**
-     * Create a new {@link java.sql.Connection} in an
-     * implementation specific fashion.
+     * Create a new {@link java.sql.Connection} in an implementation specific fashion.
      *
      * @return a new {@link java.sql.Connection}
-     * @throws SQLException if a database error occurs creating the connection
+     * @throws SQLException
+     *             if a database error occurs creating the connection
      */
     Connection createConnection() throws SQLException;
 }
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/Constants.java b/java/org/apache/tomcat/dbcp/dbcp2/Constants.java
index dd3506d..d9278cf 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/Constants.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/Constants.java
@@ -17,19 +17,18 @@
 package org.apache.tomcat.dbcp.dbcp2;
 
 /**
- * Constants for use with JMX
+ * Constants for use with JMX.
+ *
  * @since 2.0
  */
 public class Constants {
+
     public static final String JMX_CONNECTION_POOL_BASE_EXT = ",connectionpool=";
     public static final String JMX_CONNECTION_POOL_PREFIX = "connections";
 
-    public static final String JMX_CONNECTION_BASE_EXT =
-            JMX_CONNECTION_POOL_BASE_EXT +
-            JMX_CONNECTION_POOL_PREFIX +
-            ",connection=";
+    public static final String JMX_CONNECTION_BASE_EXT = JMX_CONNECTION_POOL_BASE_EXT + JMX_CONNECTION_POOL_PREFIX
+            + ",connection=";
 
-    public static final String JMX_STATEMENT_POOL_BASE_EXT =
-            JMX_CONNECTION_BASE_EXT;
+    public static final String JMX_STATEMENT_POOL_BASE_EXT = JMX_CONNECTION_BASE_EXT;
     public static final String JMX_STATEMENT_POOL_PREFIX = ",statementpool=statements";
 }
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/DataSourceConnectionFactory.java b/java/org/apache/tomcat/dbcp/dbcp2/DataSourceConnectionFactory.java
index 0a9e3a6..c56b500 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/DataSourceConnectionFactory.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/DataSourceConnectionFactory.java
@@ -24,29 +24,64 @@
 /**
  * A {@link DataSource}-based implementation of {@link ConnectionFactory}.
  *
- * @author Rodney Waldhoff
  * @since 2.0
  */
 public class DataSourceConnectionFactory implements ConnectionFactory {
-    public DataSourceConnectionFactory(final DataSource source) {
-        this(source,null,null);
+
+    private final DataSource dataSource;
+
+    private final String userName;
+
+    private final char[] userPassword;
+
+    /**
+     * Constructs an instance for the given DataSource.
+     *
+     * @param dataSource
+     *            The DataSource for this factory.
+     */
+    public DataSourceConnectionFactory(final DataSource dataSource) {
+        this(dataSource, null, (char[]) null);
     }
 
-    public DataSourceConnectionFactory(final DataSource source, final String uname, final String passwd) {
-        _source = source;
-        _uname = uname;
-        _passwd = passwd;
+    /**
+     * Constructs an instance for the given DataSource.
+     *
+     * @param dataSource
+     *            The DataSource for this factory.
+     * @param userName
+     *            The user name.
+     * @param userPassword
+     *            The user password.
+     * @since 2.4.0
+     */
+    public DataSourceConnectionFactory(final DataSource dataSource, final String userName, final char[] userPassword) {
+        this.dataSource = dataSource;
+        this.userName = userName;
+        this.userPassword = userPassword;
+    }
+
+    /**
+     * Constructs an instance for the given DataSource.
+     *
+     * @param dataSource
+     *            The DataSource for this factory.
+     * @param userName
+     *            The user name.
+     * @param password
+     *            The user password.
+     */
+    public DataSourceConnectionFactory(final DataSource dataSource, final String userName, final String password) {
+        this.dataSource = dataSource;
+        this.userName = userName;
+        this.userPassword = Utils.toCharArray(password);
     }
 
     @Override
     public Connection createConnection() throws SQLException {
-        if(null == _uname && null == _passwd) {
-            return _source.getConnection();
+        if (null == userName && null == userPassword) {
+            return dataSource.getConnection();
         }
-        return _source.getConnection(_uname,_passwd);
+        return dataSource.getConnection(userName, Utils.toString(userPassword));
     }
-
-    private final String _uname;
-    private final String _passwd;
-    private final DataSource _source;
 }
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingCallableStatement.java b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingCallableStatement.java
index a0b166a..3b4119b 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingCallableStatement.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingCallableStatement.java
@@ -39,362 +39,882 @@
 /**
  * A base delegating implementation of {@link CallableStatement}.
  * <p>
- * All of the methods from the {@link CallableStatement} interface
- * simply call the corresponding method on the "delegate"
- * provided in my constructor.
+ * All of the methods from the {@link CallableStatement} interface simply call the corresponding method on the
+ * "delegate" provided in my constructor.
+ * </p>
  * <p>
- * Extends AbandonedTrace to implement Statement tracking and
- * logging of code which created the Statement. Tracking the
- * Statement ensures that the Connection which created it can
- * close any open Statement's on Connection close.
+ * Extends AbandonedTrace to implement Statement tracking and logging of code which created the Statement. Tracking the
+ * Statement ensures that the Connection which created it can close any open Statement's on Connection close.
+ * </p>
  *
- * @author Glenn L. Nielsen
- * @author James House
- * @author Dirk Verbeeck
  * @since 2.0
  */
-public class DelegatingCallableStatement extends DelegatingPreparedStatement
-        implements CallableStatement {
+public class DelegatingCallableStatement extends DelegatingPreparedStatement implements CallableStatement {
 
     /**
-     * Create a wrapper for the Statement which traces this
-     * Statement to the Connection which created it and the
-     * code which created it.
+     * Creates a wrapper for the Statement which traces this Statement to the Connection which created it and the code
+     * which created it.
      *
-     * @param c the {@link DelegatingConnection} that created this statement
-     * @param s the {@link CallableStatement} to delegate all calls to
+     * @param c
+     *            the {@link DelegatingConnection} that created this statement
+     * @param s
+     *            the {@link CallableStatement} to delegate all calls to
      */
-    public DelegatingCallableStatement(final DelegatingConnection<?> c,
-                                       final CallableStatement s) {
+    public DelegatingCallableStatement(final DelegatingConnection<?> c, final CallableStatement s) {
         super(c, s);
     }
 
     @Override
-    public void registerOutParameter(final int parameterIndex, final int sqlType) throws SQLException
-    { checkOpen(); try { ((CallableStatement)getDelegate()).registerOutParameter( parameterIndex,  sqlType); } catch (final SQLException e) { handleException(e); } }
+    public void registerOutParameter(final int parameterIndex, final int sqlType) throws SQLException {
+        checkOpen();
+        try {
+            getDelegateCallableStatement().registerOutParameter(parameterIndex, sqlType);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void registerOutParameter(final int parameterIndex, final int sqlType, final int scale) throws SQLException
-    { checkOpen(); try { ((CallableStatement)getDelegate()).registerOutParameter( parameterIndex,  sqlType,  scale); } catch (final SQLException e) { handleException(e); } }
+    public void registerOutParameter(final int parameterIndex, final int sqlType, final int scale) throws SQLException {
+        checkOpen();
+        try {
+            getDelegateCallableStatement().registerOutParameter(parameterIndex, sqlType, scale);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public boolean wasNull() throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).wasNull(); } catch (final SQLException e) { handleException(e); return false; } }
+    public boolean wasNull() throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().wasNull();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
+    }
 
     @Override
-    public String getString(final int parameterIndex) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getString( parameterIndex); } catch (final SQLException e) { handleException(e); return null; } }
+    public String getString(final int parameterIndex) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getString(parameterIndex);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public boolean getBoolean(final int parameterIndex) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getBoolean( parameterIndex); } catch (final SQLException e) { handleException(e); return false; } }
+    public boolean getBoolean(final int parameterIndex) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getBoolean(parameterIndex);
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
+    }
 
     @Override
-    public byte getByte(final int parameterIndex) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getByte( parameterIndex); } catch (final SQLException e) { handleException(e); return 0; } }
+    public byte getByte(final int parameterIndex) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getByte(parameterIndex);
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
     @Override
-    public short getShort(final int parameterIndex) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getShort( parameterIndex); } catch (final SQLException e) { handleException(e); return 0; } }
+    public short getShort(final int parameterIndex) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getShort(parameterIndex);
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
     @Override
-    public int getInt(final int parameterIndex) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getInt( parameterIndex); } catch (final SQLException e) { handleException(e); return 0; } }
+    public int getInt(final int parameterIndex) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getInt(parameterIndex);
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
     @Override
-    public long getLong(final int parameterIndex) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getLong( parameterIndex); } catch (final SQLException e) { handleException(e); return 0; } }
+    public long getLong(final int parameterIndex) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getLong(parameterIndex);
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
     @Override
-    public float getFloat(final int parameterIndex) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getFloat( parameterIndex); } catch (final SQLException e) { handleException(e); return 0; } }
+    public float getFloat(final int parameterIndex) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getFloat(parameterIndex);
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
     @Override
-    public double getDouble(final int parameterIndex) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getDouble( parameterIndex); } catch (final SQLException e) { handleException(e); return 0; } }
+    public double getDouble(final int parameterIndex) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getDouble(parameterIndex);
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
     /** @deprecated */
     @Override
     @Deprecated
-    public BigDecimal getBigDecimal(final int parameterIndex, final int scale) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getBigDecimal( parameterIndex,  scale); } catch (final SQLException e) { handleException(e); return null; } }
+    public BigDecimal getBigDecimal(final int parameterIndex, final int scale) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getBigDecimal(parameterIndex, scale);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public byte[] getBytes(final int parameterIndex) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getBytes( parameterIndex); } catch (final SQLException e) { handleException(e); return null; } }
+    public byte[] getBytes(final int parameterIndex) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getBytes(parameterIndex);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Date getDate(final int parameterIndex) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getDate( parameterIndex); } catch (final SQLException e) { handleException(e); return null; } }
+    public Date getDate(final int parameterIndex) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getDate(parameterIndex);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Time getTime(final int parameterIndex) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getTime( parameterIndex); } catch (final SQLException e) { handleException(e); return null; } }
+    public Time getTime(final int parameterIndex) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getTime(parameterIndex);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Timestamp getTimestamp(final int parameterIndex) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getTimestamp( parameterIndex); } catch (final SQLException e) { handleException(e); return null; } }
+    public Timestamp getTimestamp(final int parameterIndex) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getTimestamp(parameterIndex);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Object getObject(final int parameterIndex) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getObject( parameterIndex); } catch (final SQLException e) { handleException(e); return null; } }
+    public Object getObject(final int parameterIndex) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getObject(parameterIndex);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public BigDecimal getBigDecimal(final int parameterIndex) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getBigDecimal( parameterIndex); } catch (final SQLException e) { handleException(e); return null; } }
+    public BigDecimal getBigDecimal(final int parameterIndex) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getBigDecimal(parameterIndex);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Object getObject(final int i, final Map<String,Class<?>> map) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getObject( i, map); } catch (final SQLException e) { handleException(e); return null; } }
+    public Object getObject(final int i, final Map<String, Class<?>> map) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getObject(i, map);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Ref getRef(final int i) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getRef( i); } catch (final SQLException e) { handleException(e); return null; } }
+    public Ref getRef(final int i) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getRef(i);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Blob getBlob(final int i) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getBlob( i); } catch (final SQLException e) { handleException(e); return null; } }
+    public Blob getBlob(final int i) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getBlob(i);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Clob getClob(final int i) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getClob( i); } catch (final SQLException e) { handleException(e); return null; } }
+    public Clob getClob(final int i) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getClob(i);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Array getArray(final int i) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getArray( i); } catch (final SQLException e) { handleException(e); return null; } }
+    public Array getArray(final int i) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getArray(i);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Date getDate(final int parameterIndex, final Calendar cal) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getDate( parameterIndex,  cal); } catch (final SQLException e) { handleException(e); return null; } }
+    public Date getDate(final int parameterIndex, final Calendar cal) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getDate(parameterIndex, cal);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Time getTime(final int parameterIndex, final Calendar cal) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getTime( parameterIndex,  cal); } catch (final SQLException e) { handleException(e); return null; } }
+    public Time getTime(final int parameterIndex, final Calendar cal) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getTime(parameterIndex, cal);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Timestamp getTimestamp(final int parameterIndex, final Calendar cal) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getTimestamp( parameterIndex,  cal); } catch (final SQLException e) { handleException(e); return null; } }
+    public Timestamp getTimestamp(final int parameterIndex, final Calendar cal) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getTimestamp(parameterIndex, cal);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public void registerOutParameter(final int paramIndex, final int sqlType, final String typeName) throws SQLException
-    { checkOpen(); try { ((CallableStatement)getDelegate()).registerOutParameter( paramIndex,  sqlType,  typeName); } catch (final SQLException e) { handleException(e); } }
+    public void registerOutParameter(final int paramIndex, final int sqlType, final String typeName)
+            throws SQLException {
+        checkOpen();
+        try {
+            getDelegateCallableStatement().registerOutParameter(paramIndex, sqlType, typeName);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void registerOutParameter(final String parameterName, final int sqlType) throws SQLException
-    { checkOpen(); try { ((CallableStatement)getDelegate()).registerOutParameter(parameterName, sqlType); } catch (final SQLException e) { handleException(e); } }
+    public void registerOutParameter(final String parameterName, final int sqlType) throws SQLException {
+        checkOpen();
+        try {
+            getDelegateCallableStatement().registerOutParameter(parameterName, sqlType);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void registerOutParameter(final String parameterName, final int sqlType, final int scale) throws SQLException
-    { checkOpen(); try { ((CallableStatement)getDelegate()).registerOutParameter(parameterName, sqlType, scale); } catch (final SQLException e) { handleException(e); } }
+    public void registerOutParameter(final String parameterName, final int sqlType, final int scale)
+            throws SQLException {
+        checkOpen();
+        try {
+            getDelegateCallableStatement().registerOutParameter(parameterName, sqlType, scale);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void registerOutParameter(final String parameterName, final int sqlType, final String typeName) throws SQLException
-    { checkOpen(); try { ((CallableStatement)getDelegate()).registerOutParameter(parameterName, sqlType, typeName); } catch (final SQLException e) { handleException(e); } }
+    public void registerOutParameter(final String parameterName, final int sqlType, final String typeName)
+            throws SQLException {
+        checkOpen();
+        try {
+            getDelegateCallableStatement().registerOutParameter(parameterName, sqlType, typeName);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public URL getURL(final int parameterIndex) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getURL(parameterIndex); } catch (final SQLException e) { handleException(e); return null; } }
+    public URL getURL(final int parameterIndex) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getURL(parameterIndex);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public void setURL(final String parameterName, final URL val) throws SQLException
-    { checkOpen(); try { ((CallableStatement)getDelegate()).setURL(parameterName, val); } catch (final SQLException e) { handleException(e); } }
+    public void setURL(final String parameterName, final URL val) throws SQLException {
+        checkOpen();
+        try {
+            getDelegateCallableStatement().setURL(parameterName, val);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setNull(final String parameterName, final int sqlType) throws SQLException
-    { checkOpen(); try { ((CallableStatement)getDelegate()).setNull(parameterName, sqlType); } catch (final SQLException e) { handleException(e); } }
+    public void setNull(final String parameterName, final int sqlType) throws SQLException {
+        checkOpen();
+        try {
+            getDelegateCallableStatement().setNull(parameterName, sqlType);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setBoolean(final String parameterName, final boolean x) throws SQLException
-    { checkOpen(); try { ((CallableStatement)getDelegate()).setBoolean(parameterName, x); } catch (final SQLException e) { handleException(e); } }
+    public void setBoolean(final String parameterName, final boolean x) throws SQLException {
+        checkOpen();
+        try {
+            getDelegateCallableStatement().setBoolean(parameterName, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setByte(final String parameterName, final byte x) throws SQLException
-    { checkOpen(); try { ((CallableStatement)getDelegate()).setByte(parameterName, x); } catch (final SQLException e) { handleException(e); } }
+    public void setByte(final String parameterName, final byte x) throws SQLException {
+        checkOpen();
+        try {
+            getDelegateCallableStatement().setByte(parameterName, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setShort(final String parameterName, final short x) throws SQLException
-    { checkOpen(); try { ((CallableStatement)getDelegate()).setShort(parameterName, x); } catch (final SQLException e) { handleException(e); } }
+    public void setShort(final String parameterName, final short x) throws SQLException {
+        checkOpen();
+        try {
+            getDelegateCallableStatement().setShort(parameterName, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setInt(final String parameterName, final int x) throws SQLException
-    { checkOpen(); try { ((CallableStatement)getDelegate()).setInt(parameterName, x); } catch (final SQLException e) { handleException(e); } }
+    public void setInt(final String parameterName, final int x) throws SQLException {
+        checkOpen();
+        try {
+            getDelegateCallableStatement().setInt(parameterName, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setLong(final String parameterName, final long x) throws SQLException
-    { checkOpen(); try { ((CallableStatement)getDelegate()).setLong(parameterName, x); } catch (final SQLException e) { handleException(e); } }
+    public void setLong(final String parameterName, final long x) throws SQLException {
+        checkOpen();
+        try {
+            getDelegateCallableStatement().setLong(parameterName, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setFloat(final String parameterName, final float x) throws SQLException
-    { checkOpen(); try { ((CallableStatement)getDelegate()).setFloat(parameterName, x); } catch (final SQLException e) { handleException(e); } }
+    public void setFloat(final String parameterName, final float x) throws SQLException {
+        checkOpen();
+        try {
+            getDelegateCallableStatement().setFloat(parameterName, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setDouble(final String parameterName, final double x) throws SQLException
-    { checkOpen(); try { ((CallableStatement)getDelegate()).setDouble(parameterName, x); } catch (final SQLException e) { handleException(e); } }
+    public void setDouble(final String parameterName, final double x) throws SQLException {
+        checkOpen();
+        try {
+            getDelegateCallableStatement().setDouble(parameterName, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setBigDecimal(final String parameterName, final BigDecimal x) throws SQLException
-    { checkOpen(); try { ((CallableStatement)getDelegate()).setBigDecimal(parameterName, x); } catch (final SQLException e) { handleException(e); } }
+    public void setBigDecimal(final String parameterName, final BigDecimal x) throws SQLException {
+        checkOpen();
+        try {
+            getDelegateCallableStatement().setBigDecimal(parameterName, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setString(final String parameterName, final String x) throws SQLException
-    { checkOpen(); try { ((CallableStatement)getDelegate()).setString(parameterName, x); } catch (final SQLException e) { handleException(e); } }
+    public void setString(final String parameterName, final String x) throws SQLException {
+        checkOpen();
+        try {
+            getDelegateCallableStatement().setString(parameterName, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setBytes(final String parameterName, final byte [] x) throws SQLException
-    { checkOpen(); try { ((CallableStatement)getDelegate()).setBytes(parameterName, x); } catch (final SQLException e) { handleException(e); } }
+    public void setBytes(final String parameterName, final byte[] x) throws SQLException {
+        checkOpen();
+        try {
+            getDelegateCallableStatement().setBytes(parameterName, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setDate(final String parameterName, final Date x) throws SQLException
-    { checkOpen(); try { ((CallableStatement)getDelegate()).setDate(parameterName, x); } catch (final SQLException e) { handleException(e); } }
+    public void setDate(final String parameterName, final Date x) throws SQLException {
+        checkOpen();
+        try {
+            getDelegateCallableStatement().setDate(parameterName, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setTime(final String parameterName, final Time x) throws SQLException
-    { checkOpen(); try { ((CallableStatement)getDelegate()).setTime(parameterName, x); } catch (final SQLException e) { handleException(e); } }
+    public void setTime(final String parameterName, final Time x) throws SQLException {
+        checkOpen();
+        try {
+            getDelegateCallableStatement().setTime(parameterName, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setTimestamp(final String parameterName, final Timestamp x) throws SQLException
-    { checkOpen(); try { ((CallableStatement)getDelegate()).setTimestamp(parameterName, x); } catch (final SQLException e) { handleException(e); } }
+    public void setTimestamp(final String parameterName, final Timestamp x) throws SQLException {
+        checkOpen();
+        try {
+            getDelegateCallableStatement().setTimestamp(parameterName, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setAsciiStream(final String parameterName, final InputStream x, final int length) throws SQLException
-    { checkOpen(); try { ((CallableStatement)getDelegate()).setAsciiStream(parameterName, x, length); } catch (final SQLException e) { handleException(e); } }
+    public void setAsciiStream(final String parameterName, final InputStream x, final int length) throws SQLException {
+        checkOpen();
+        try {
+            getDelegateCallableStatement().setAsciiStream(parameterName, x, length);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setBinaryStream(final String parameterName, final InputStream x, final int length) throws SQLException
-    { checkOpen(); try { ((CallableStatement)getDelegate()).setBinaryStream(parameterName, x, length); } catch (final SQLException e) { handleException(e); } }
+    public void setBinaryStream(final String parameterName, final InputStream x, final int length) throws SQLException {
+        checkOpen();
+        try {
+            getDelegateCallableStatement().setBinaryStream(parameterName, x, length);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setObject(final String parameterName, final Object x, final int targetSqlType, final int scale) throws SQLException
-    { checkOpen(); try { ((CallableStatement)getDelegate()).setObject(parameterName, x, targetSqlType, scale); } catch (final SQLException e) { handleException(e); } }
+    public void setObject(final String parameterName, final Object x, final int targetSqlType, final int scale)
+            throws SQLException {
+        checkOpen();
+        try {
+            getDelegateCallableStatement().setObject(parameterName, x, targetSqlType, scale);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setObject(final String parameterName, final Object x, final int targetSqlType) throws SQLException
-    { checkOpen(); try { ((CallableStatement)getDelegate()).setObject(parameterName, x, targetSqlType); } catch (final SQLException e) { handleException(e); } }
+    public void setObject(final String parameterName, final Object x, final int targetSqlType) throws SQLException {
+        checkOpen();
+        try {
+            getDelegateCallableStatement().setObject(parameterName, x, targetSqlType);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setObject(final String parameterName, final Object x) throws SQLException
-    { checkOpen(); try { ((CallableStatement)getDelegate()).setObject(parameterName, x); } catch (final SQLException e) { handleException(e); } }
+    public void setObject(final String parameterName, final Object x) throws SQLException {
+        checkOpen();
+        try {
+            getDelegateCallableStatement().setObject(parameterName, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setCharacterStream(final String parameterName, final Reader reader, final int length) throws SQLException
-    { checkOpen(); ((CallableStatement)getDelegate()).setCharacterStream(parameterName, reader, length); }
+    public void setCharacterStream(final String parameterName, final Reader reader, final int length)
+            throws SQLException {
+        checkOpen();
+        getDelegateCallableStatement().setCharacterStream(parameterName, reader, length);
+    }
 
     @Override
-    public void setDate(final String parameterName, final Date x, final Calendar cal) throws SQLException
-    { checkOpen(); try { ((CallableStatement)getDelegate()).setDate(parameterName, x, cal); } catch (final SQLException e) { handleException(e); } }
+    public void setDate(final String parameterName, final Date x, final Calendar cal) throws SQLException {
+        checkOpen();
+        try {
+            getDelegateCallableStatement().setDate(parameterName, x, cal);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setTime(final String parameterName, final Time x, final Calendar cal) throws SQLException
-    { checkOpen(); try { ((CallableStatement)getDelegate()).setTime(parameterName, x, cal); } catch (final SQLException e) { handleException(e); } }
+    public void setTime(final String parameterName, final Time x, final Calendar cal) throws SQLException {
+        checkOpen();
+        try {
+            getDelegateCallableStatement().setTime(parameterName, x, cal);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setTimestamp(final String parameterName, final Timestamp x, final Calendar cal) throws SQLException
-    { checkOpen(); try { ((CallableStatement)getDelegate()).setTimestamp(parameterName, x, cal); } catch (final SQLException e) { handleException(e); } }
+    public void setTimestamp(final String parameterName, final Timestamp x, final Calendar cal) throws SQLException {
+        checkOpen();
+        try {
+            getDelegateCallableStatement().setTimestamp(parameterName, x, cal);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setNull(final String parameterName, final int sqlType, final String typeName) throws SQLException
-    { checkOpen(); try { ((CallableStatement)getDelegate()).setNull(parameterName, sqlType, typeName); } catch (final SQLException e) { handleException(e); } }
+    public void setNull(final String parameterName, final int sqlType, final String typeName) throws SQLException {
+        checkOpen();
+        try {
+            getDelegateCallableStatement().setNull(parameterName, sqlType, typeName);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public String getString(final String parameterName) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getString(parameterName); } catch (final SQLException e) { handleException(e); return null; } }
+    public String getString(final String parameterName) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getString(parameterName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public boolean getBoolean(final String parameterName) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getBoolean(parameterName); } catch (final SQLException e) { handleException(e); return false; } }
+    public boolean getBoolean(final String parameterName) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getBoolean(parameterName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
+    }
 
     @Override
-    public byte getByte(final String parameterName) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getByte(parameterName); } catch (final SQLException e) { handleException(e); return 0; } }
+    public byte getByte(final String parameterName) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getByte(parameterName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
     @Override
-    public short getShort(final String parameterName) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getShort(parameterName); } catch (final SQLException e) { handleException(e); return 0; } }
+    public short getShort(final String parameterName) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getShort(parameterName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
     @Override
-    public int getInt(final String parameterName) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getInt(parameterName); } catch (final SQLException e) { handleException(e); return 0; } }
+    public int getInt(final String parameterName) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getInt(parameterName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
     @Override
-    public long getLong(final String parameterName) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getLong(parameterName); } catch (final SQLException e) { handleException(e); return 0; } }
+    public long getLong(final String parameterName) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getLong(parameterName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
     @Override
-    public float getFloat(final String parameterName) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getFloat(parameterName); } catch (final SQLException e) { handleException(e); return 0; } }
+    public float getFloat(final String parameterName) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getFloat(parameterName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
     @Override
-    public double getDouble(final String parameterName) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getDouble(parameterName); } catch (final SQLException e) { handleException(e); return 0; } }
+    public double getDouble(final String parameterName) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getDouble(parameterName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
     @Override
-    public byte[] getBytes(final String parameterName) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getBytes(parameterName); } catch (final SQLException e) { handleException(e); return null; } }
+    public byte[] getBytes(final String parameterName) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getBytes(parameterName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Date getDate(final String parameterName) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getDate(parameterName); } catch (final SQLException e) { handleException(e); return null; } }
+    public Date getDate(final String parameterName) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getDate(parameterName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Time getTime(final String parameterName) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getTime(parameterName); } catch (final SQLException e) { handleException(e); return null; } }
+    public Time getTime(final String parameterName) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getTime(parameterName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Timestamp getTimestamp(final String parameterName) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getTimestamp(parameterName); } catch (final SQLException e) { handleException(e); return null; } }
+    public Timestamp getTimestamp(final String parameterName) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getTimestamp(parameterName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Object getObject(final String parameterName) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getObject(parameterName); } catch (final SQLException e) { handleException(e); return null; } }
+    public Object getObject(final String parameterName) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getObject(parameterName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public BigDecimal getBigDecimal(final String parameterName) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getBigDecimal(parameterName); } catch (final SQLException e) { handleException(e); return null; } }
+    public BigDecimal getBigDecimal(final String parameterName) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getBigDecimal(parameterName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Object getObject(final String parameterName, final Map<String,Class<?>> map) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getObject(parameterName, map); } catch (final SQLException e) { handleException(e); return null; } }
+    public Object getObject(final String parameterName, final Map<String, Class<?>> map) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getObject(parameterName, map);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Ref getRef(final String parameterName) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getRef(parameterName); } catch (final SQLException e) { handleException(e); return null; } }
+    public Ref getRef(final String parameterName) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getRef(parameterName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Blob getBlob(final String parameterName) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getBlob(parameterName); } catch (final SQLException e) { handleException(e); return null; } }
+    public Blob getBlob(final String parameterName) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getBlob(parameterName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Clob getClob(final String parameterName) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getClob(parameterName); } catch (final SQLException e) { handleException(e); return null; } }
+    public Clob getClob(final String parameterName) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getClob(parameterName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Array getArray(final String parameterName) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getArray(parameterName); } catch (final SQLException e) { handleException(e); return null; } }
+    public Array getArray(final String parameterName) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getArray(parameterName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Date getDate(final String parameterName, final Calendar cal) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getDate(parameterName, cal); } catch (final SQLException e) { handleException(e); return null; } }
+    public Date getDate(final String parameterName, final Calendar cal) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getDate(parameterName, cal);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
+
+    private CallableStatement getDelegateCallableStatement() {
+        return (CallableStatement) getDelegate();
+    }
 
     @Override
-    public Time getTime(final String parameterName, final Calendar cal) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getTime(parameterName, cal); } catch (final SQLException e) { handleException(e); return null; } }
+    public Time getTime(final String parameterName, final Calendar cal) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getTime(parameterName, cal);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Timestamp getTimestamp(final String parameterName, final Calendar cal) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getTimestamp(parameterName, cal); } catch (final SQLException e) { handleException(e); return null; } }
+    public Timestamp getTimestamp(final String parameterName, final Calendar cal) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getTimestamp(parameterName, cal);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public URL getURL(final String parameterName) throws SQLException
-    { checkOpen(); try { return ((CallableStatement)getDelegate()).getURL(parameterName); } catch (final SQLException e) { handleException(e); return null; } }
-
+    public URL getURL(final String parameterName) throws SQLException {
+        checkOpen();
+        try {
+            return getDelegateCallableStatement().getURL(parameterName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
     public RowId getRowId(final int parameterIndex) throws SQLException {
         checkOpen();
         try {
-            return ((CallableStatement)getDelegate()).getRowId(parameterIndex);
-        }
-        catch (final SQLException e) {
+            return getDelegateCallableStatement().getRowId(parameterIndex);
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
@@ -404,9 +924,8 @@
     public RowId getRowId(final String parameterName) throws SQLException {
         checkOpen();
         try {
-            return ((CallableStatement)getDelegate()).getRowId(parameterName);
-        }
-        catch (final SQLException e) {
+            return getDelegateCallableStatement().getRowId(parameterName);
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
@@ -416,9 +935,8 @@
     public void setRowId(final String parameterName, final RowId value) throws SQLException {
         checkOpen();
         try {
-            ((CallableStatement)getDelegate()).setRowId(parameterName, value);
-        }
-        catch (final SQLException e) {
+            getDelegateCallableStatement().setRowId(parameterName, value);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -427,20 +945,19 @@
     public void setNString(final String parameterName, final String value) throws SQLException {
         checkOpen();
         try {
-            ((CallableStatement)getDelegate()).setNString(parameterName, value);
-        }
-        catch (final SQLException e) {
+            getDelegateCallableStatement().setNString(parameterName, value);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
 
     @Override
-    public void setNCharacterStream(final String parameterName, final Reader reader, final long length) throws SQLException {
+    public void setNCharacterStream(final String parameterName, final Reader reader, final long length)
+            throws SQLException {
         checkOpen();
         try {
-            ((CallableStatement)getDelegate()).setNCharacterStream(parameterName, reader, length);
-        }
-        catch (final SQLException e) {
+            getDelegateCallableStatement().setNCharacterStream(parameterName, reader, length);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -449,9 +966,8 @@
     public void setNClob(final String parameterName, final NClob value) throws SQLException {
         checkOpen();
         try {
-            ((CallableStatement)getDelegate()).setNClob(parameterName, value);
-        }
-        catch (final SQLException e) {
+            getDelegateCallableStatement().setNClob(parameterName, value);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -460,20 +976,19 @@
     public void setClob(final String parameterName, final Reader reader, final long length) throws SQLException {
         checkOpen();
         try {
-            ((CallableStatement)getDelegate()).setClob(parameterName, reader, length);
-        }
-        catch (final SQLException e) {
+            getDelegateCallableStatement().setClob(parameterName, reader, length);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
 
     @Override
-    public void setBlob(final String parameterName, final InputStream inputStream, final long length) throws SQLException {
+    public void setBlob(final String parameterName, final InputStream inputStream, final long length)
+            throws SQLException {
         checkOpen();
         try {
-            ((CallableStatement)getDelegate()).setBlob(parameterName, inputStream, length);
-        }
-        catch (final SQLException e) {
+            getDelegateCallableStatement().setBlob(parameterName, inputStream, length);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -482,9 +997,8 @@
     public void setNClob(final String parameterName, final Reader reader, final long length) throws SQLException {
         checkOpen();
         try {
-            ((CallableStatement)getDelegate()).setNClob(parameterName, reader, length);
-        }
-        catch (final SQLException e) {
+            getDelegateCallableStatement().setNClob(parameterName, reader, length);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -493,9 +1007,8 @@
     public NClob getNClob(final int parameterIndex) throws SQLException {
         checkOpen();
         try {
-            return ((CallableStatement)getDelegate()).getNClob(parameterIndex);
-        }
-        catch (final SQLException e) {
+            return getDelegateCallableStatement().getNClob(parameterIndex);
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
@@ -505,9 +1018,8 @@
     public NClob getNClob(final String parameterName) throws SQLException {
         checkOpen();
         try {
-            return ((CallableStatement)getDelegate()).getNClob(parameterName);
-        }
-        catch (final SQLException e) {
+            return getDelegateCallableStatement().getNClob(parameterName);
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
@@ -517,9 +1029,8 @@
     public void setSQLXML(final String parameterName, final SQLXML value) throws SQLException {
         checkOpen();
         try {
-            ((CallableStatement)getDelegate()).setSQLXML(parameterName, value);
-        }
-        catch (final SQLException e) {
+            getDelegateCallableStatement().setSQLXML(parameterName, value);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -528,9 +1039,8 @@
     public SQLXML getSQLXML(final int parameterIndex) throws SQLException {
         checkOpen();
         try {
-            return ((CallableStatement)getDelegate()).getSQLXML(parameterIndex);
-        }
-        catch (final SQLException e) {
+            return getDelegateCallableStatement().getSQLXML(parameterIndex);
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
@@ -540,9 +1050,8 @@
     public SQLXML getSQLXML(final String parameterName) throws SQLException {
         checkOpen();
         try {
-            return ((CallableStatement)getDelegate()).getSQLXML(parameterName);
-        }
-        catch (final SQLException e) {
+            return getDelegateCallableStatement().getSQLXML(parameterName);
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
@@ -552,9 +1061,8 @@
     public String getNString(final int parameterIndex) throws SQLException {
         checkOpen();
         try {
-            return ((CallableStatement)getDelegate()).getNString(parameterIndex);
-        }
-        catch (final SQLException e) {
+            return getDelegateCallableStatement().getNString(parameterIndex);
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
@@ -564,9 +1072,8 @@
     public String getNString(final String parameterName) throws SQLException {
         checkOpen();
         try {
-            return ((CallableStatement)getDelegate()).getNString(parameterName);
-        }
-        catch (final SQLException e) {
+            return getDelegateCallableStatement().getNString(parameterName);
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
@@ -576,9 +1083,8 @@
     public Reader getNCharacterStream(final int parameterIndex) throws SQLException {
         checkOpen();
         try {
-            return ((CallableStatement)getDelegate()).getNCharacterStream(parameterIndex);
-        }
-        catch (final SQLException e) {
+            return getDelegateCallableStatement().getNCharacterStream(parameterIndex);
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
@@ -588,9 +1094,8 @@
     public Reader getNCharacterStream(final String parameterName) throws SQLException {
         checkOpen();
         try {
-            return ((CallableStatement)getDelegate()).getNCharacterStream(parameterName);
-        }
-        catch (final SQLException e) {
+            return getDelegateCallableStatement().getNCharacterStream(parameterName);
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
@@ -600,9 +1105,8 @@
     public Reader getCharacterStream(final int parameterIndex) throws SQLException {
         checkOpen();
         try {
-            return ((CallableStatement)getDelegate()).getCharacterStream(parameterIndex);
-        }
-        catch (final SQLException e) {
+            return getDelegateCallableStatement().getCharacterStream(parameterIndex);
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
@@ -612,9 +1116,8 @@
     public Reader getCharacterStream(final String parameterName) throws SQLException {
         checkOpen();
         try {
-            return ((CallableStatement)getDelegate()).getCharacterStream(parameterName);
-        }
-        catch (final SQLException e) {
+            return getDelegateCallableStatement().getCharacterStream(parameterName);
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
@@ -624,9 +1127,8 @@
     public void setBlob(final String parameterName, final Blob blob) throws SQLException {
         checkOpen();
         try {
-            ((CallableStatement)getDelegate()).setBlob(parameterName, blob);
-        }
-        catch (final SQLException e) {
+            getDelegateCallableStatement().setBlob(parameterName, blob);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -635,42 +1137,41 @@
     public void setClob(final String parameterName, final Clob clob) throws SQLException {
         checkOpen();
         try {
-            ((CallableStatement)getDelegate()).setClob(parameterName, clob);
-        }
-        catch (final SQLException e) {
+            getDelegateCallableStatement().setClob(parameterName, clob);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
 
     @Override
-    public void setAsciiStream(final String parameterName, final InputStream inputStream, final long length) throws SQLException {
+    public void setAsciiStream(final String parameterName, final InputStream inputStream, final long length)
+            throws SQLException {
         checkOpen();
         try {
-            ((CallableStatement)getDelegate()).setAsciiStream(parameterName, inputStream, length);
-        }
-        catch (final SQLException e) {
+            getDelegateCallableStatement().setAsciiStream(parameterName, inputStream, length);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
 
     @Override
-    public void setBinaryStream(final String parameterName, final InputStream inputStream, final long length) throws SQLException {
+    public void setBinaryStream(final String parameterName, final InputStream inputStream, final long length)
+            throws SQLException {
         checkOpen();
         try {
-            ((CallableStatement)getDelegate()).setBinaryStream(parameterName, inputStream, length);
-        }
-        catch (final SQLException e) {
+            getDelegateCallableStatement().setBinaryStream(parameterName, inputStream, length);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
 
     @Override
-    public void setCharacterStream(final String parameterName, final Reader reader, final long length) throws SQLException {
+    public void setCharacterStream(final String parameterName, final Reader reader, final long length)
+            throws SQLException {
         checkOpen();
         try {
-            ((CallableStatement)getDelegate()).setCharacterStream(parameterName, reader, length);
-        }
-        catch (final SQLException e) {
+            getDelegateCallableStatement().setCharacterStream(parameterName, reader, length);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -679,9 +1180,8 @@
     public void setAsciiStream(final String parameterName, final InputStream inputStream) throws SQLException {
         checkOpen();
         try {
-            ((CallableStatement)getDelegate()).setAsciiStream(parameterName, inputStream);
-        }
-        catch (final SQLException e) {
+            getDelegateCallableStatement().setAsciiStream(parameterName, inputStream);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -690,9 +1190,8 @@
     public void setBinaryStream(final String parameterName, final InputStream inputStream) throws SQLException {
         checkOpen();
         try {
-            ((CallableStatement)getDelegate()).setBinaryStream(parameterName, inputStream);
-        }
-        catch (final SQLException e) {
+            getDelegateCallableStatement().setBinaryStream(parameterName, inputStream);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -701,9 +1200,8 @@
     public void setCharacterStream(final String parameterName, final Reader reader) throws SQLException {
         checkOpen();
         try {
-            ((CallableStatement)getDelegate()).setCharacterStream(parameterName, reader);
-        }
-        catch (final SQLException e) {
+            getDelegateCallableStatement().setCharacterStream(parameterName, reader);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -712,9 +1210,8 @@
     public void setNCharacterStream(final String parameterName, final Reader reader) throws SQLException {
         checkOpen();
         try {
-            ((CallableStatement)getDelegate()).setNCharacterStream(parameterName, reader);
-        }
-        catch (final SQLException e) {
+            getDelegateCallableStatement().setNCharacterStream(parameterName, reader);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -723,9 +1220,8 @@
     public void setClob(final String parameterName, final Reader reader) throws SQLException {
         checkOpen();
         try {
-            ((CallableStatement)getDelegate()).setClob(parameterName, reader);
-        }
-        catch (final SQLException e) {
+            getDelegateCallableStatement().setClob(parameterName, reader);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -734,9 +1230,8 @@
     public void setBlob(final String parameterName, final InputStream inputStream) throws SQLException {
         checkOpen();
         try {
-            ((CallableStatement)getDelegate()).setBlob(parameterName, inputStream);
-        }
-        catch (final SQLException e) {
+            getDelegateCallableStatement().setBlob(parameterName, inputStream);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -745,38 +1240,32 @@
     public void setNClob(final String parameterName, final Reader reader) throws SQLException {
         checkOpen();
         try {
-            ((CallableStatement)getDelegate()).setNClob(parameterName, reader);
-        }
-        catch (final SQLException e) {
+            getDelegateCallableStatement().setNClob(parameterName, reader);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
 
     @Override
-    public <T> T getObject(final int parameterIndex, final Class<T> type)
-            throws SQLException {
+    public <T> T getObject(final int parameterIndex, final Class<T> type) throws SQLException {
         checkOpen();
         try {
-            return ((CallableStatement)getDelegate()).getObject(parameterIndex, type);
-}
-        catch (final SQLException e) {
+            return getDelegateCallableStatement().getObject(parameterIndex, type);
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
     }
 
     @Override
-    public <T> T getObject(final String parameterName, final Class<T> type)
-            throws SQLException {
+    public <T> T getObject(final String parameterName, final Class<T> type) throws SQLException {
         checkOpen();
         try {
-            return ((CallableStatement)getDelegate()).getObject(parameterName, type);
-        }
-        catch (final SQLException e) {
+            return getDelegateCallableStatement().getObject(parameterName, type);
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
     }
 
-
 }
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingConnection.java b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingConnection.java
index 4ddb10f..735d267 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingConnection.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingConnection.java
@@ -44,57 +44,48 @@
 /**
  * A base delegating implementation of {@link Connection}.
  * <p>
- * All of the methods from the {@link Connection} interface
- * simply check to see that the {@link Connection} is active,
- * and call the corresponding method on the "delegate"
- * provided in my constructor.
+ * All of the methods from the {@link Connection} interface simply check to see that the {@link Connection} is active,
+ * and call the corresponding method on the "delegate" provided in my constructor.
+ * </p>
  * <p>
- * Extends AbandonedTrace to implement Connection tracking and
- * logging of code which created the Connection. Tracking the
- * Connection ensures that the AbandonedObjectPool can close
- * this connection and recycle it if its pool of connections
- * is nearing exhaustion and this connection's last usage is
- * older than the removeAbandonedTimeout.
+ * Extends AbandonedTrace to implement Connection tracking and logging of code which created the Connection. Tracking
+ * the Connection ensures that the AbandonedObjectPool can close this connection and recycle it if its pool of
+ * connections is nearing exhaustion and this connection's last usage is older than the removeAbandonedTimeout.
+ * </p>
  *
- * @param <C> the Connection type
+ * @param <C>
+ *            the Connection type
  *
- * @author Rodney Waldhoff
- * @author Glenn L. Nielsen
- * @author James House
- * @author Dirk Verbeeck
  * @since 2.0
  */
-public class DelegatingConnection<C extends Connection> extends AbandonedTrace
-        implements Connection {
+public class DelegatingConnection<C extends Connection> extends AbandonedTrace implements Connection {
 
-    private static final Map<String, ClientInfoStatus> EMPTY_FAILED_PROPERTIES =
-        Collections.<String, ClientInfoStatus>emptyMap();
+    private static final Map<String, ClientInfoStatus> EMPTY_FAILED_PROPERTIES = Collections
+            .<String, ClientInfoStatus>emptyMap();
 
     /** My delegate {@link Connection}. */
-    private volatile C _conn = null;
+    private volatile C connection;
 
-    private volatile boolean _closed = false;
+    private volatile boolean closed;
 
-    private boolean _cacheState = true;
-    private Boolean _autoCommitCached = null;
-    private Boolean _readOnlyCached = null;
-    private Integer defaultQueryTimeout = null;
+    private boolean cacheState = true;
+    private Boolean autoCommitCached;
+    private Boolean readOnlyCached;
+    private Integer defaultQueryTimeoutSeconds;
 
     /**
-     * Create a wrapper for the Connection which traces this
-     * Connection in the AbandonedObjectPool.
+     * Creates a wrapper for the Connection which traces this Connection in the AbandonedObjectPool.
      *
-     * @param c the {@link Connection} to delegate all calls to.
+     * @param c
+     *            the {@link Connection} to delegate all calls to.
      */
     public DelegatingConnection(final C c) {
         super();
-        _conn = c;
+        connection = c;
     }
 
-
     /**
-     * Returns a string representation of the metadata associated with
-     * the innermost delegate connection.
+     * Returns a string representation of the metadata associated with the innermost delegate connection.
      */
     @Override
     public String toString() {
@@ -105,8 +96,7 @@
             try {
                 if (c.isClosed()) {
                     s = "connection is closed";
-                }
-                else {
+                } else {
                     final StringBuffer sb = new StringBuffer();
                     sb.append(hashCode());
                     final DatabaseMetaData meta = c.getMetaData();
@@ -120,8 +110,7 @@
                         s = sb.toString();
                     }
                 }
-            }
-            catch (final SQLException ex) {
+            } catch (final SQLException ex) {
                 // Ignore
             }
         }
@@ -135,6 +124,7 @@
 
     /**
      * Returns my underlying {@link Connection}.
+     *
      * @return my underlying {@link Connection}.
      */
     public C getDelegate() {
@@ -142,13 +132,14 @@
     }
 
     protected final C getDelegateInternal() {
-        return _conn;
+        return connection;
     }
 
     /**
      * Compares innermost delegate to the given connection.
      *
-     * @param c connection to compare innermost delegate with
+     * @param c
+     *            connection to compare innermost delegate with
      * @return true if innermost delegate equals <code>c</code>
      */
     public boolean innermostDelegateEquals(final Connection c) {
@@ -159,85 +150,87 @@
         return innerCon.equals(c);
     }
 
-
     /**
-     * If my underlying {@link Connection} is not a
-     * {@code DelegatingConnection}, returns it,
-     * otherwise recursively invokes this method on
-     * my delegate.
+     * If my underlying {@link Connection} is not a {@code DelegatingConnection}, returns it, otherwise recursively
+     * invokes this method on my delegate.
      * <p>
-     * Hence this method will return the first
-     * delegate that is not a {@code DelegatingConnection},
-     * or {@code null} when no non-{@code DelegatingConnection}
-     * delegate can be found by traversing this chain.
+     * Hence this method will return the first delegate that is not a {@code DelegatingConnection}, or {@code null} when
+     * no non-{@code DelegatingConnection} delegate can be found by traversing this chain.
+     * </p>
      * <p>
-     * This method is useful when you may have nested
-     * {@code DelegatingConnection}s, and you want to make
-     * sure to obtain a "genuine" {@link Connection}.
+     * This method is useful when you may have nested {@code DelegatingConnection}s, and you want to make sure to obtain
+     * a "genuine" {@link Connection}.
+     * </p>
+     *
+     * @return innermost delegate.
      */
     public Connection getInnermostDelegate() {
         return getInnermostDelegateInternal();
     }
 
-
     /**
-     * Although this method is public, it is part of the internal API and should
-     * not be used by clients. The signature of this method may change at any
-     * time including in ways that break backwards compatibility.
+     * Although this method is public, it is part of the internal API and should not be used by clients. The signature
+     * of this method may change at any time including in ways that break backwards compatibility.
+     *
+     * @return innermost delegate.
      */
     public final Connection getInnermostDelegateInternal() {
-        Connection c = _conn;
-        while(c != null && c instanceof DelegatingConnection) {
-            c = ((DelegatingConnection<?>)c).getDelegateInternal();
-            if(this == c) {
+        Connection c = connection;
+        while (c != null && c instanceof DelegatingConnection) {
+            c = ((DelegatingConnection<?>) c).getDelegateInternal();
+            if (this == c) {
                 return null;
             }
         }
         return c;
     }
 
-    /** Sets my delegate. */
-    public void setDelegate(final C c) {
-        _conn = c;
+    /**
+     * Sets my delegate.
+     *
+     * @param connection
+     *            my delegate.
+     */
+    public void setDelegate(final C connection) {
+        this.connection = connection;
     }
 
     /**
-     * Closes the underlying connection, and close any Statements that were not
-     * explicitly closed. Sub-classes that override this method must:
+     * Closes the underlying connection, and close any Statements that were not explicitly closed. Sub-classes that
+     * override this method must:
      * <ol>
      * <li>Call passivate()</li>
-     * <li>Call close (or the equivalent appropriate action) on the wrapped
-     *     connection</li>
+     * <li>Call close (or the equivalent appropriate action) on the wrapped connection</li>
      * <li>Set _closed to <code>false</code></li>
      * </ol>
      */
     @Override
     public void close() throws SQLException {
-        if (!_closed) {
+        if (!closed) {
             closeInternal();
         }
     }
 
     protected boolean isClosedInternal() {
-        return _closed;
+        return closed;
     }
 
     protected void setClosedInternal(final boolean closed) {
-        this._closed = closed;
+        this.closed = closed;
     }
 
     protected final void closeInternal() throws SQLException {
         try {
             passivate();
         } finally {
-            if (_conn != null) {
+            if (connection != null) {
                 try {
-                    _conn.close();
+                    connection.close();
                 } finally {
-                    _closed = true;
+                    closed = true;
                 }
             } else {
-                _closed = true;
+                closed = true;
             }
         }
     }
@@ -247,9 +240,8 @@
     }
 
     private void initializeStatement(final DelegatingStatement ds) throws SQLException {
-        if (defaultQueryTimeout != null &&
-                defaultQueryTimeout.intValue() != ds.getQueryTimeout()) {
-            ds.setQueryTimeout(defaultQueryTimeout.intValue());
+        if (defaultQueryTimeoutSeconds != null && defaultQueryTimeoutSeconds.intValue() != ds.getQueryTimeout()) {
+            ds.setQueryTimeout(defaultQueryTimeoutSeconds.intValue());
         }
     }
 
@@ -257,28 +249,24 @@
     public Statement createStatement() throws SQLException {
         checkOpen();
         try {
-            final DelegatingStatement ds =
-                    new DelegatingStatement(this, _conn.createStatement());
+            final DelegatingStatement ds = new DelegatingStatement(this, connection.createStatement());
             initializeStatement(ds);
             return ds;
-        }
-        catch (final SQLException e) {
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
     }
 
     @Override
-    public Statement createStatement(final int resultSetType,
-                                     final int resultSetConcurrency) throws SQLException {
+    public Statement createStatement(final int resultSetType, final int resultSetConcurrency) throws SQLException {
         checkOpen();
         try {
-            final DelegatingStatement ds = new DelegatingStatement(
-                    this, _conn.createStatement(resultSetType,resultSetConcurrency));
+            final DelegatingStatement ds = new DelegatingStatement(this,
+                    connection.createStatement(resultSetType, resultSetConcurrency));
             initializeStatement(ds);
             return ds;
-        }
-        catch (final SQLException e) {
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
@@ -288,29 +276,26 @@
     public PreparedStatement prepareStatement(final String sql) throws SQLException {
         checkOpen();
         try {
-            final DelegatingPreparedStatement dps = new DelegatingPreparedStatement(
-                    this, _conn.prepareStatement(sql));
+            final DelegatingPreparedStatement dps = new DelegatingPreparedStatement(this,
+                    connection.prepareStatement(sql));
             initializeStatement(dps);
             return dps;
-        }
-        catch (final SQLException e) {
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
     }
 
     @Override
-    public PreparedStatement prepareStatement(final String sql,
-                                              final int resultSetType,
-                                              final int resultSetConcurrency) throws SQLException {
+    public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency)
+            throws SQLException {
         checkOpen();
         try {
-            final DelegatingPreparedStatement dps = new DelegatingPreparedStatement(
-                    this, _conn.prepareStatement(sql,resultSetType,resultSetConcurrency));
+            final DelegatingPreparedStatement dps = new DelegatingPreparedStatement(this,
+                    connection.prepareStatement(sql, resultSetType, resultSetConcurrency));
             initializeStatement(dps);
             return dps;
-        }
-        catch (final SQLException e) {
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
@@ -320,219 +305,205 @@
     public CallableStatement prepareCall(final String sql) throws SQLException {
         checkOpen();
         try {
-            final DelegatingCallableStatement dcs =
-                    new DelegatingCallableStatement(this, _conn.prepareCall(sql));
+            final DelegatingCallableStatement dcs = new DelegatingCallableStatement(this, connection.prepareCall(sql));
             initializeStatement(dcs);
             return dcs;
-        }
-        catch (final SQLException e) {
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
     }
 
     @Override
-    public CallableStatement prepareCall(final String sql,
-                                         final int resultSetType,
-                                         final int resultSetConcurrency) throws SQLException {
+    public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency)
+            throws SQLException {
         checkOpen();
         try {
-            final DelegatingCallableStatement dcs = new DelegatingCallableStatement(
-                    this, _conn.prepareCall(sql, resultSetType,resultSetConcurrency));
+            final DelegatingCallableStatement dcs = new DelegatingCallableStatement(this,
+                    connection.prepareCall(sql, resultSetType, resultSetConcurrency));
             initializeStatement(dcs);
             return dcs;
-        }
-        catch (final SQLException e) {
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
     }
 
-
     @Override
     public void clearWarnings() throws SQLException {
         checkOpen();
         try {
-            _conn.clearWarnings();
+            connection.clearWarnings();
         } catch (final SQLException e) {
             handleException(e);
         }
     }
 
-
     @Override
     public void commit() throws SQLException {
         checkOpen();
         try {
-            _conn.commit();
+            connection.commit();
         } catch (final SQLException e) {
             handleException(e);
         }
     }
 
-
     /**
      * Returns the state caching flag.
      *
-     * @return  the state caching flag
+     * @return the state caching flag
      */
     public boolean getCacheState() {
-        return _cacheState;
+        return cacheState;
     }
 
     @Override
     public boolean getAutoCommit() throws SQLException {
         checkOpen();
-        if (_cacheState && _autoCommitCached != null) {
-            return _autoCommitCached.booleanValue();
+        if (cacheState && autoCommitCached != null) {
+            return autoCommitCached.booleanValue();
         }
         try {
-            _autoCommitCached = Boolean.valueOf(_conn.getAutoCommit());
-            return _autoCommitCached.booleanValue();
+            autoCommitCached = Boolean.valueOf(connection.getAutoCommit());
+            return autoCommitCached.booleanValue();
         } catch (final SQLException e) {
             handleException(e);
             return false;
         }
     }
 
-
     @Override
     public String getCatalog() throws SQLException {
         checkOpen();
         try {
-            return _conn.getCatalog();
+            return connection.getCatalog();
         } catch (final SQLException e) {
             handleException(e);
             return null;
         }
     }
 
-
     @Override
     public DatabaseMetaData getMetaData() throws SQLException {
         checkOpen();
         try {
-            return new DelegatingDatabaseMetaData(this, _conn.getMetaData());
+            return new DelegatingDatabaseMetaData(this, connection.getMetaData());
         } catch (final SQLException e) {
             handleException(e);
             return null;
         }
     }
 
-
     @Override
     public int getTransactionIsolation() throws SQLException {
         checkOpen();
         try {
-            return _conn.getTransactionIsolation();
+            return connection.getTransactionIsolation();
         } catch (final SQLException e) {
             handleException(e);
             return -1;
         }
     }
 
-
     @Override
-    public Map<String,Class<?>> getTypeMap() throws SQLException {
+    public Map<String, Class<?>> getTypeMap() throws SQLException {
         checkOpen();
         try {
-            return _conn.getTypeMap();
+            return connection.getTypeMap();
         } catch (final SQLException e) {
             handleException(e);
             return null;
         }
     }
 
-
     @Override
     public SQLWarning getWarnings() throws SQLException {
         checkOpen();
         try {
-            return _conn.getWarnings();
+            return connection.getWarnings();
         } catch (final SQLException e) {
             handleException(e);
             return null;
         }
     }
 
-
     @Override
     public boolean isReadOnly() throws SQLException {
         checkOpen();
-        if (_cacheState && _readOnlyCached != null) {
-            return _readOnlyCached.booleanValue();
+        if (cacheState && readOnlyCached != null) {
+            return readOnlyCached.booleanValue();
         }
         try {
-            _readOnlyCached = Boolean.valueOf(_conn.isReadOnly());
-            return _readOnlyCached.booleanValue();
+            readOnlyCached = Boolean.valueOf(connection.isReadOnly());
+            return readOnlyCached.booleanValue();
         } catch (final SQLException e) {
             handleException(e);
             return false;
         }
     }
 
-
     @Override
     public String nativeSQL(final String sql) throws SQLException {
         checkOpen();
         try {
-            return _conn.nativeSQL(sql);
+            return connection.nativeSQL(sql);
         } catch (final SQLException e) {
             handleException(e);
             return null;
         }
     }
 
-
     @Override
     public void rollback() throws SQLException {
         checkOpen();
         try {
-            _conn.rollback();
+            connection.rollback();
         } catch (final SQLException e) {
             handleException(e);
         }
     }
 
-
     /**
-     * Obtain the default query timeout that will be used for {@link Statement}s
-     * created from this connection. <code>null</code> means that the driver
-     * default will be used.
+     * Gets the default query timeout that will be used for {@link Statement}s created from this connection.
+     * <code>null</code> means that the driver default will be used.
+     *
+     * @return query timeout limit in seconds; zero means there is no limit.
      */
     public Integer getDefaultQueryTimeout() {
-        return defaultQueryTimeout;
+        return defaultQueryTimeoutSeconds;
     }
 
-
     /**
-     * Set the default query timeout that will be used for {@link Statement}s
-     * created from this connection. <code>null</code> means that the driver
-     * default will be used.
+     * Sets the default query timeout that will be used for {@link Statement}s created from this connection.
+     * <code>null</code> means that the driver default will be used.
+     *
+     * @param defaultQueryTimeoutSeconds
+     *            the new query timeout limit in seconds; zero means there is no limit
      */
-    public void setDefaultQueryTimeout(final Integer defaultQueryTimeout) {
-        this.defaultQueryTimeout = defaultQueryTimeout;
+    public void setDefaultQueryTimeout(final Integer defaultQueryTimeoutSeconds) {
+        this.defaultQueryTimeoutSeconds = defaultQueryTimeoutSeconds;
     }
 
-
     /**
      * Sets the state caching flag.
      *
-     * @param cacheState    The new value for the state caching flag
+     * @param cacheState
+     *            The new value for the state caching flag
      */
     public void setCacheState(final boolean cacheState) {
-        this._cacheState = cacheState;
+        this.cacheState = cacheState;
     }
 
     /**
-     * Can be used to clear cached state when it is known that the underlying
-     * connection may have been accessed directly.
+     * Can be used to clear cached state when it is known that the underlying connection may have been accessed
+     * directly.
      */
     public void clearCachedState() {
-        _autoCommitCached = null;
-        _readOnlyCached = null;
-        if (_conn instanceof DelegatingConnection) {
-            ((DelegatingConnection<?>)_conn).clearCachedState();
+        autoCommitCached = null;
+        readOnlyCached = null;
+        if (connection instanceof DelegatingConnection) {
+            ((DelegatingConnection<?>) connection).clearCachedState();
         }
     }
 
@@ -540,51 +511,55 @@
     public void setAutoCommit(final boolean autoCommit) throws SQLException {
         checkOpen();
         try {
-            _conn.setAutoCommit(autoCommit);
-            if (_cacheState) {
-                _autoCommitCached = Boolean.valueOf(autoCommit);
+            connection.setAutoCommit(autoCommit);
+            if (cacheState) {
+                autoCommitCached = Boolean.valueOf(autoCommit);
             }
         } catch (final SQLException e) {
-            _autoCommitCached = null;
+            autoCommitCached = null;
             handleException(e);
         }
     }
 
     @Override
-    public void setCatalog(final String catalog) throws SQLException
-    { checkOpen(); try { _conn.setCatalog(catalog); } catch (final SQLException e) { handleException(e); } }
+    public void setCatalog(final String catalog) throws SQLException {
+        checkOpen();
+        try {
+            connection.setCatalog(catalog);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
     public void setReadOnly(final boolean readOnly) throws SQLException {
         checkOpen();
         try {
-            _conn.setReadOnly(readOnly);
-            if (_cacheState) {
-                _readOnlyCached = Boolean.valueOf(readOnly);
+            connection.setReadOnly(readOnly);
+            if (cacheState) {
+                readOnlyCached = Boolean.valueOf(readOnly);
             }
         } catch (final SQLException e) {
-            _readOnlyCached = null;
+            readOnlyCached = null;
             handleException(e);
         }
     }
 
-
     @Override
     public void setTransactionIsolation(final int level) throws SQLException {
         checkOpen();
         try {
-            _conn.setTransactionIsolation(level);
+            connection.setTransactionIsolation(level);
         } catch (final SQLException e) {
             handleException(e);
         }
     }
 
-
     @Override
-    public void setTypeMap(final Map<String,Class<?>> map) throws SQLException {
+    public void setTypeMap(final Map<String, Class<?>> map) throws SQLException {
         checkOpen();
         try {
-            _conn.setTypeMap(map);
+            connection.setTypeMap(map);
         } catch (final SQLException e) {
             handleException(e);
         }
@@ -592,31 +567,29 @@
 
     @Override
     public boolean isClosed() throws SQLException {
-        return _closed || _conn == null || _conn.isClosed();
+        return closed || connection == null || connection.isClosed();
     }
 
     protected void checkOpen() throws SQLException {
-        if(_closed) {
-            if (null != _conn) {
+        if (closed) {
+            if (null != connection) {
                 String label = "";
                 try {
-                    label = _conn.toString();
+                    label = connection.toString();
                 } catch (final Exception ex) {
                     // ignore, leave label empty
                 }
-                throw new SQLException
-                    ("Connection " + label + " is closed.");
+                throw new SQLException("Connection " + label + " is closed.");
             }
-            throw new SQLException
-                ("Connection is null.");
+            throw new SQLException("Connection is null.");
         }
     }
 
     protected void activate() {
-        _closed = false;
+        closed = false;
         setLastUsed();
-        if(_conn instanceof DelegatingConnection) {
-            ((DelegatingConnection<?>)_conn).activate();
+        if (connection instanceof DelegatingConnection) {
+            ((DelegatingConnection<?>) connection).activate();
         }
     }
 
@@ -625,7 +598,7 @@
         // Statement's when it is closed.
         // DBCP-288. Not all the traced objects will be statements
         final List<AbandonedTrace> traces = getTrace();
-        if(traces != null && traces.size() > 0) {
+        if (traces != null && traces.size() > 0) {
             final Iterator<AbandonedTrace> traceIter = traces.iterator();
             while (traceIter.hasNext()) {
                 final Object trace = traceIter.next();
@@ -642,126 +615,109 @@
         setLastUsed(0);
     }
 
-
     @Override
     public int getHoldability() throws SQLException {
         checkOpen();
         try {
-            return _conn.getHoldability();
+            return connection.getHoldability();
         } catch (final SQLException e) {
             handleException(e);
             return 0;
         }
     }
 
-
     @Override
     public void setHoldability(final int holdability) throws SQLException {
         checkOpen();
         try {
-            _conn.setHoldability(holdability);
+            connection.setHoldability(holdability);
         } catch (final SQLException e) {
             handleException(e);
         }
     }
 
-
     @Override
     public Savepoint setSavepoint() throws SQLException {
         checkOpen();
         try {
-            return _conn.setSavepoint();
+            return connection.setSavepoint();
         } catch (final SQLException e) {
             handleException(e);
             return null;
         }
     }
 
-
     @Override
     public Savepoint setSavepoint(final String name) throws SQLException {
         checkOpen();
         try {
-            return _conn.setSavepoint(name);
+            return connection.setSavepoint(name);
         } catch (final SQLException e) {
             handleException(e);
             return null;
         }
     }
 
-
     @Override
     public void rollback(final Savepoint savepoint) throws SQLException {
         checkOpen();
         try {
-            _conn.rollback(savepoint);
+            connection.rollback(savepoint);
         } catch (final SQLException e) {
             handleException(e);
         }
     }
 
-
     @Override
-    public void releaseSavepoint(final Savepoint savepoint)
-            throws SQLException {
+    public void releaseSavepoint(final Savepoint savepoint) throws SQLException {
         checkOpen();
         try {
-            _conn.releaseSavepoint(savepoint);
+            connection.releaseSavepoint(savepoint);
         } catch (final SQLException e) {
             handleException(e);
         }
     }
 
-
     @Override
-    public Statement createStatement(final int resultSetType,
-                                     final int resultSetConcurrency,
-                                     final int resultSetHoldability) throws SQLException {
+    public Statement createStatement(final int resultSetType, final int resultSetConcurrency,
+            final int resultSetHoldability) throws SQLException {
         checkOpen();
         try {
             final DelegatingStatement ds = new DelegatingStatement(this,
-                    _conn.createStatement(resultSetType, resultSetConcurrency,
-                            resultSetHoldability));
+                    connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability));
             initializeStatement(ds);
             return ds;
-        }
-        catch (final SQLException e) {
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
     }
 
     @Override
-    public PreparedStatement prepareStatement(final String sql, final int resultSetType,
-                                              final int resultSetConcurrency,
-                                              final int resultSetHoldability) throws SQLException {
+    public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency,
+            final int resultSetHoldability) throws SQLException {
         checkOpen();
         try {
-            final DelegatingPreparedStatement dps = new DelegatingPreparedStatement(
-                    this, _conn.prepareStatement(sql, resultSetType,
-                            resultSetConcurrency, resultSetHoldability));
+            final DelegatingPreparedStatement dps = new DelegatingPreparedStatement(this,
+                    connection.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability));
             initializeStatement(dps);
             return dps;
-        }
-        catch (final SQLException e) {
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
     }
 
     @Override
-    public CallableStatement prepareCall(final String sql, final int resultSetType,
-                                         final int resultSetConcurrency,
-                                         final int resultSetHoldability) throws SQLException {
+    public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency,
+            final int resultSetHoldability) throws SQLException {
         checkOpen();
         try {
-            final DelegatingCallableStatement dcs = new DelegatingCallableStatement(
-                    this, _conn.prepareCall(sql, resultSetType,
-                            resultSetConcurrency, resultSetHoldability));
+            final DelegatingCallableStatement dcs = new DelegatingCallableStatement(this,
+                    connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability));
             initializeStatement(dcs);
             return dcs;
-        }
-        catch (final SQLException e) {
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
@@ -771,12 +727,11 @@
     public PreparedStatement prepareStatement(final String sql, final int autoGeneratedKeys) throws SQLException {
         checkOpen();
         try {
-            final DelegatingPreparedStatement dps = new DelegatingPreparedStatement(
-                    this, _conn.prepareStatement(sql, autoGeneratedKeys));
+            final DelegatingPreparedStatement dps = new DelegatingPreparedStatement(this,
+                    connection.prepareStatement(sql, autoGeneratedKeys));
             initializeStatement(dps);
             return dps;
-        }
-        catch (final SQLException e) {
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
@@ -786,12 +741,11 @@
     public PreparedStatement prepareStatement(final String sql, final int columnIndexes[]) throws SQLException {
         checkOpen();
         try {
-            final DelegatingPreparedStatement dps = new DelegatingPreparedStatement(
-                    this, _conn.prepareStatement(sql, columnIndexes));
+            final DelegatingPreparedStatement dps = new DelegatingPreparedStatement(this,
+                    connection.prepareStatement(sql, columnIndexes));
             initializeStatement(dps);
             return dps;
-        }
-        catch (final SQLException e) {
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
@@ -801,26 +755,24 @@
     public PreparedStatement prepareStatement(final String sql, final String columnNames[]) throws SQLException {
         checkOpen();
         try {
-            final DelegatingPreparedStatement dps =  new DelegatingPreparedStatement(
-                    this, _conn.prepareStatement(sql, columnNames));
+            final DelegatingPreparedStatement dps = new DelegatingPreparedStatement(this,
+                    connection.prepareStatement(sql, columnNames));
             initializeStatement(dps);
             return dps;
-        }
-        catch (final SQLException e) {
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
     }
 
-
     @Override
     public boolean isWrapperFor(final Class<?> iface) throws SQLException {
         if (iface.isAssignableFrom(getClass())) {
             return true;
-        } else if (iface.isAssignableFrom(_conn.getClass())) {
+        } else if (iface.isAssignableFrom(connection.getClass())) {
             return true;
         } else {
-            return _conn.isWrapperFor(iface);
+            return connection.isWrapperFor(iface);
         }
     }
 
@@ -828,10 +780,10 @@
     public <T> T unwrap(final Class<T> iface) throws SQLException {
         if (iface.isAssignableFrom(getClass())) {
             return iface.cast(this);
-        } else if (iface.isAssignableFrom(_conn.getClass())) {
-            return iface.cast(_conn);
+        } else if (iface.isAssignableFrom(connection.getClass())) {
+            return iface.cast(connection);
         } else {
-            return _conn.unwrap(iface);
+            return connection.unwrap(iface);
         }
     }
 
@@ -839,9 +791,8 @@
     public Array createArrayOf(final String typeName, final Object[] elements) throws SQLException {
         checkOpen();
         try {
-            return _conn.createArrayOf(typeName, elements);
-        }
-        catch (final SQLException e) {
+            return connection.createArrayOf(typeName, elements);
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
@@ -851,9 +802,8 @@
     public Blob createBlob() throws SQLException {
         checkOpen();
         try {
-            return _conn.createBlob();
-        }
-        catch (final SQLException e) {
+            return connection.createBlob();
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
@@ -863,9 +813,8 @@
     public Clob createClob() throws SQLException {
         checkOpen();
         try {
-            return _conn.createClob();
-        }
-        catch (final SQLException e) {
+            return connection.createClob();
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
@@ -875,9 +824,8 @@
     public NClob createNClob() throws SQLException {
         checkOpen();
         try {
-            return _conn.createNClob();
-        }
-        catch (final SQLException e) {
+            return connection.createNClob();
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
@@ -887,9 +835,8 @@
     public SQLXML createSQLXML() throws SQLException {
         checkOpen();
         try {
-            return _conn.createSQLXML();
-        }
-        catch (final SQLException e) {
+            return connection.createSQLXML();
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
@@ -899,23 +846,21 @@
     public Struct createStruct(final String typeName, final Object[] attributes) throws SQLException {
         checkOpen();
         try {
-            return _conn.createStruct(typeName, attributes);
-        }
-        catch (final SQLException e) {
+            return connection.createStruct(typeName, attributes);
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
     }
 
     @Override
-    public boolean isValid(final int timeout) throws SQLException {
+    public boolean isValid(final int timeoutSeconds) throws SQLException {
         if (isClosed()) {
             return false;
         }
         try {
-            return _conn.isValid(timeout);
-        }
-        catch (final SQLException e) {
+            return connection.isValid(timeoutSeconds);
+        } catch (final SQLException e) {
             handleException(e);
             return false;
         }
@@ -925,12 +870,10 @@
     public void setClientInfo(final String name, final String value) throws SQLClientInfoException {
         try {
             checkOpen();
-            _conn.setClientInfo(name, value);
-        }
-        catch (final SQLClientInfoException e) {
+            connection.setClientInfo(name, value);
+        } catch (final SQLClientInfoException e) {
             throw e;
-        }
-        catch (final SQLException e) {
+        } catch (final SQLException e) {
             throw new SQLClientInfoException("Connection is closed.", EMPTY_FAILED_PROPERTIES, e);
         }
     }
@@ -939,12 +882,10 @@
     public void setClientInfo(final Properties properties) throws SQLClientInfoException {
         try {
             checkOpen();
-            _conn.setClientInfo(properties);
-        }
-        catch (final SQLClientInfoException e) {
+            connection.setClientInfo(properties);
+        } catch (final SQLClientInfoException e) {
             throw e;
-        }
-        catch (final SQLException e) {
+        } catch (final SQLException e) {
             throw new SQLClientInfoException("Connection is closed.", EMPTY_FAILED_PROPERTIES, e);
         }
     }
@@ -953,9 +894,8 @@
     public Properties getClientInfo() throws SQLException {
         checkOpen();
         try {
-            return _conn.getClientInfo();
-        }
-        catch (final SQLException e) {
+            return connection.getClientInfo();
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
@@ -965,9 +905,8 @@
     public String getClientInfo(final String name) throws SQLException {
         checkOpen();
         try {
-            return _conn.getClientInfo(name);
-        }
-        catch (final SQLException e) {
+            return connection.getClientInfo(name);
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
@@ -977,9 +916,8 @@
     public void setSchema(final String schema) throws SQLException {
         checkOpen();
         try {
-            _conn.setSchema(schema);
-        }
-        catch (final SQLException e) {
+            connection.setSchema(schema);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -988,9 +926,8 @@
     public String getSchema() throws SQLException {
         checkOpen();
         try {
-            return _conn.getSchema();
-        }
-        catch (final SQLException e) {
+            return connection.getSchema();
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
@@ -1000,21 +937,18 @@
     public void abort(final Executor executor) throws SQLException {
         checkOpen();
         try {
-            _conn.abort(executor);
-        }
-        catch (final SQLException e) {
+            connection.abort(executor);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
 
     @Override
-    public void setNetworkTimeout(final Executor executor, final int milliseconds)
-            throws SQLException {
+    public void setNetworkTimeout(final Executor executor, final int milliseconds) throws SQLException {
         checkOpen();
         try {
-            _conn.setNetworkTimeout(executor, milliseconds);
-        }
-        catch (final SQLException e) {
+            connection.setNetworkTimeout(executor, milliseconds);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -1023,9 +957,8 @@
     public int getNetworkTimeout() throws SQLException {
         checkOpen();
         try {
-            return _conn.getNetworkTimeout();
-        }
-        catch (final SQLException e) {
+            return connection.getNetworkTimeout();
+        } catch (final SQLException e) {
             handleException(e);
             return 0;
         }
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingDatabaseMetaData.java b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingDatabaseMetaData.java
index 6ff5c83..d58711d 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingDatabaseMetaData.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingDatabaseMetaData.java
@@ -23,53 +23,67 @@
 import java.sql.SQLException;
 
 /**
- * <p>A base delegating implementation of {@link DatabaseMetaData}.</p>
+ * <p>
+ * A base delegating implementation of {@link DatabaseMetaData}.
+ * </p>
+ * <p>
+ * Methods that create {@link ResultSet} objects are wrapped to create {@link DelegatingResultSet} objects and the
+ * remaining methods simply call the corresponding method on the "delegate" provided in the constructor.
+ * </p>
  *
- * <p>Methods that create {@link ResultSet} objects are wrapped to
- * create {@link DelegatingResultSet} objects and the remaining methods
- * simply call the corresponding method on the "delegate"
- * provided in the constructor.</p>
  * @since 2.0
  */
 public class DelegatingDatabaseMetaData implements DatabaseMetaData {
 
     /** My delegate {@link DatabaseMetaData} */
-    private final DatabaseMetaData _meta;
+    private final DatabaseMetaData databaseMetaData;
 
     /** The connection that created me. **/
-    private final DelegatingConnection<?> _conn;
+    private final DelegatingConnection<?> connection;
 
-    public DelegatingDatabaseMetaData(final DelegatingConnection<?> c,
-            final DatabaseMetaData m) {
+    /**
+     * Constructs a new instance for the given delegating connection and database meta data.
+     *
+     * @param connection
+     *            the delegating connection
+     * @param databaseMetaData
+     *            the database meta data
+     */
+    public DelegatingDatabaseMetaData(final DelegatingConnection<?> connection,
+            final DatabaseMetaData databaseMetaData) {
         super();
-        _conn = c;
-        _meta = m;
-    }
-
-    public DatabaseMetaData getDelegate() {
-        return _meta;
+        this.connection = connection;
+        this.databaseMetaData = databaseMetaData;
     }
 
     /**
-     * If my underlying {@link ResultSet} is not a
-     * {@code DelegatingResultSet}, returns it,
-     * otherwise recursively invokes this method on
-     * my delegate.
+     * Gets the underlying database meta data.
+     *
+     * @return The underlying database meta data.
+     */
+    public DatabaseMetaData getDelegate() {
+        return databaseMetaData;
+    }
+
+    /**
+     * If my underlying {@link ResultSet} is not a {@code DelegatingResultSet}, returns it, otherwise recursively
+     * invokes this method on my delegate.
      * <p>
-     * Hence this method will return the first
-     * delegate that is not a {@code DelegatingResultSet},
-     * or {@code null} when no non-{@code DelegatingResultSet}
-     * delegate can be found by traversing this chain.
+     * Hence this method will return the first delegate that is not a {@code DelegatingResultSet}, or {@code null} when
+     * no non-{@code DelegatingResultSet} delegate can be found by traversing this chain.
+     * </p>
      * <p>
-     * This method is useful when you may have nested
-     * {@code DelegatingResultSet}s, and you want to make
-     * sure to obtain a "genuine" {@link ResultSet}.
+     * This method is useful when you may have nested {@code DelegatingResultSet}s, and you want to make sure to obtain
+     * a "genuine" {@link ResultSet}.
+     * </p>
+     *
+     * @return the innermost database meta data.
      */
     public DatabaseMetaData getInnermostDelegate() {
-        DatabaseMetaData m = _meta;
-        while(m != null && m instanceof DelegatingDatabaseMetaData) {
-            m = ((DelegatingDatabaseMetaData)m).getDelegate();
-            if(this == m) {
+        DatabaseMetaData m = databaseMetaData;
+        while (m != null && m instanceof DelegatingDatabaseMetaData) {
+            m = ((DelegatingDatabaseMetaData) m).getDelegate();
+            if (this == m) {
                 return null;
             }
         }
@@ -77,76 +91,94 @@
     }
 
     protected void handleException(final SQLException e) throws SQLException {
-        if (_conn != null) {
-            _conn.handleException(e);
-        }
-        else {
+        if (connection != null) {
+            connection.handleException(e);
+        } else {
             throw e;
         }
     }
 
     @Override
     public boolean allProceduresAreCallable() throws SQLException {
-        try { return _meta.allProceduresAreCallable(); }
-          catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.allProceduresAreCallable();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean allTablesAreSelectable() throws SQLException {
-        try { return _meta.allTablesAreSelectable(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.allTablesAreSelectable();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean dataDefinitionCausesTransactionCommit() throws SQLException {
-        try { return _meta.dataDefinitionCausesTransactionCommit(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.dataDefinitionCausesTransactionCommit();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean dataDefinitionIgnoredInTransactions() throws SQLException {
-        try { return _meta.dataDefinitionIgnoredInTransactions(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.dataDefinitionIgnoredInTransactions();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean deletesAreDetected(final int type) throws SQLException {
-        try { return _meta.deletesAreDetected(type); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.deletesAreDetected(type);
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean doesMaxRowSizeIncludeBlobs() throws SQLException {
-        try { return _meta.doesMaxRowSizeIncludeBlobs(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.doesMaxRowSizeIncludeBlobs();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
-    public ResultSet getAttributes(final String catalog, final String schemaPattern,
-            final String typeNamePattern, final String attributeNamePattern)
-            throws SQLException {
-        _conn.checkOpen();
+    public ResultSet getAttributes(final String catalog, final String schemaPattern, final String typeNamePattern,
+            final String attributeNamePattern) throws SQLException {
+        connection.checkOpen();
         try {
-            return DelegatingResultSet.wrapResultSet(_conn,_meta.getAttributes(
-                    catalog, schemaPattern, typeNamePattern,
-                    attributeNamePattern));
-        }
-        catch (final SQLException e) {
+            return DelegatingResultSet.wrapResultSet(connection,
+                    databaseMetaData.getAttributes(catalog, schemaPattern, typeNamePattern, attributeNamePattern));
+        } catch (final SQLException e) {
             handleException(e);
             throw new AssertionError();
         }
     }
 
     @Override
-    public ResultSet getBestRowIdentifier(final String catalog, final String schema,
-            final String table, final int scope, final boolean nullable) throws SQLException {
-        _conn.checkOpen();
+    public ResultSet getBestRowIdentifier(final String catalog, final String schema, final String table,
+            final int scope, final boolean nullable) throws SQLException {
+        connection.checkOpen();
         try {
-            return DelegatingResultSet.wrapResultSet(_conn,
-                    _meta.getBestRowIdentifier(catalog, schema, table, scope,
-                            nullable));
-        }
-        catch (final SQLException e) {
+            return DelegatingResultSet.wrapResultSet(connection,
+                    databaseMetaData.getBestRowIdentifier(catalog, schema, table, scope, nullable));
+        } catch (final SQLException e) {
             handleException(e);
             throw new AssertionError();
         }
@@ -154,55 +186,56 @@
 
     @Override
     public String getCatalogSeparator() throws SQLException {
-        try { return _meta.getCatalogSeparator(); }
-        catch (final SQLException e) { handleException(e); throw new AssertionError(); }
+        try {
+            return databaseMetaData.getCatalogSeparator();
+        } catch (final SQLException e) {
+            handleException(e);
+            throw new AssertionError();
+        }
     }
 
     @Override
     public String getCatalogTerm() throws SQLException {
-        try { return _meta.getCatalogTerm(); }
-        catch (final SQLException e) { handleException(e); throw new AssertionError(); }
+        try {
+            return databaseMetaData.getCatalogTerm();
+        } catch (final SQLException e) {
+            handleException(e);
+            throw new AssertionError();
+        }
     }
 
     @Override
     public ResultSet getCatalogs() throws SQLException {
-        _conn.checkOpen();
+        connection.checkOpen();
         try {
-            return DelegatingResultSet.wrapResultSet(_conn,
-                    _meta.getCatalogs());
-        }
-        catch (final SQLException e) {
+            return DelegatingResultSet.wrapResultSet(connection, databaseMetaData.getCatalogs());
+        } catch (final SQLException e) {
             handleException(e);
             throw new AssertionError();
         }
     }
 
     @Override
-    public ResultSet getColumnPrivileges(final String catalog, final String schema,
-            final String table, final String columnNamePattern) throws SQLException {
-        _conn.checkOpen();
+    public ResultSet getColumnPrivileges(final String catalog, final String schema, final String table,
+            final String columnNamePattern) throws SQLException {
+        connection.checkOpen();
         try {
-            return DelegatingResultSet.wrapResultSet(_conn,
-                    _meta.getColumnPrivileges(catalog, schema, table,
-                            columnNamePattern));
-        }
-        catch (final SQLException e) {
+            return DelegatingResultSet.wrapResultSet(connection,
+                    databaseMetaData.getColumnPrivileges(catalog, schema, table, columnNamePattern));
+        } catch (final SQLException e) {
             handleException(e);
             throw new AssertionError();
         }
     }
 
     @Override
-    public ResultSet getColumns(final String catalog, final String schemaPattern,
-            final String tableNamePattern, final String columnNamePattern)
-            throws SQLException {
-        _conn.checkOpen();
+    public ResultSet getColumns(final String catalog, final String schemaPattern, final String tableNamePattern,
+            final String columnNamePattern) throws SQLException {
+        connection.checkOpen();
         try {
-            return DelegatingResultSet.wrapResultSet(_conn,
-                    _meta.getColumns(catalog, schemaPattern, tableNamePattern,
-                            columnNamePattern));
-        }
-        catch (final SQLException e) {
+            return DelegatingResultSet.wrapResultSet(connection,
+                    databaseMetaData.getColumns(catalog, schemaPattern, tableNamePattern, columnNamePattern));
+        } catch (final SQLException e) {
             handleException(e);
             throw new AssertionError();
         }
@@ -210,21 +243,17 @@
 
     @Override
     public Connection getConnection() throws SQLException {
-        return _conn;
+        return connection;
     }
 
     @Override
-    public ResultSet getCrossReference(final String parentCatalog,
-            final String parentSchema, final String parentTable, final String foreignCatalog,
-            final String foreignSchema, final String foreignTable) throws SQLException {
-        _conn.checkOpen();
+    public ResultSet getCrossReference(final String parentCatalog, final String parentSchema, final String parentTable,
+            final String foreignCatalog, final String foreignSchema, final String foreignTable) throws SQLException {
+        connection.checkOpen();
         try {
-            return DelegatingResultSet.wrapResultSet(_conn,
-                    _meta.getCrossReference(parentCatalog, parentSchema,
-                            parentTable, foreignCatalog, foreignSchema,
-                            foreignTable));
-        }
-        catch (final SQLException e) {
+            return DelegatingResultSet.wrapResultSet(connection, databaseMetaData.getCrossReference(parentCatalog,
+                    parentSchema, parentTable, foreignCatalog, foreignSchema, foreignTable));
+        } catch (final SQLException e) {
             handleException(e);
             throw new AssertionError();
         }
@@ -232,61 +261,92 @@
 
     @Override
     public int getDatabaseMajorVersion() throws SQLException {
-        try { return _meta.getDatabaseMajorVersion(); }
-        catch (final SQLException e) { handleException(e); return 0; }
+        try {
+            return databaseMetaData.getDatabaseMajorVersion();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
     }
 
     @Override
     public int getDatabaseMinorVersion() throws SQLException {
-        try { return _meta.getDatabaseMinorVersion(); }
-        catch (final SQLException e) { handleException(e); return 0; }
+        try {
+            return databaseMetaData.getDatabaseMinorVersion();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
     }
 
     @Override
     public String getDatabaseProductName() throws SQLException {
-        try { return _meta.getDatabaseProductName(); }
-        catch (final SQLException e) { handleException(e); throw new AssertionError(); }
+        try {
+            return databaseMetaData.getDatabaseProductName();
+        } catch (final SQLException e) {
+            handleException(e);
+            throw new AssertionError();
+        }
     }
 
     @Override
     public String getDatabaseProductVersion() throws SQLException {
-        try { return _meta.getDatabaseProductVersion(); }
-        catch (final SQLException e) { handleException(e); throw new AssertionError(); }
+        try {
+            return databaseMetaData.getDatabaseProductVersion();
+        } catch (final SQLException e) {
+            handleException(e);
+            throw new AssertionError();
+        }
     }
 
     @Override
     public int getDefaultTransactionIsolation() throws SQLException {
-        try { return _meta.getDefaultTransactionIsolation(); }
-        catch (final SQLException e) { handleException(e); return 0; }
+        try {
+            return databaseMetaData.getDefaultTransactionIsolation();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
     }
 
     @Override
-    public int getDriverMajorVersion() {return _meta.getDriverMajorVersion();}
+    public int getDriverMajorVersion() {
+        return databaseMetaData.getDriverMajorVersion();
+    }
 
     @Override
-    public int getDriverMinorVersion() {return _meta.getDriverMinorVersion();}
+    public int getDriverMinorVersion() {
+        return databaseMetaData.getDriverMinorVersion();
+    }
 
     @Override
     public String getDriverName() throws SQLException {
-        try { return _meta.getDriverName(); }
-        catch (final SQLException e) { handleException(e); throw new AssertionError(); }
+        try {
+            return databaseMetaData.getDriverName();
+        } catch (final SQLException e) {
+            handleException(e);
+            throw new AssertionError();
+        }
     }
 
     @Override
     public String getDriverVersion() throws SQLException {
-        try { return _meta.getDriverVersion(); }
-        catch (final SQLException e) { handleException(e); throw new AssertionError(); }
+        try {
+            return databaseMetaData.getDriverVersion();
+        } catch (final SQLException e) {
+            handleException(e);
+            throw new AssertionError();
+        }
     }
 
     @Override
     public ResultSet getExportedKeys(final String catalog, final String schema, final String table)
             throws SQLException {
-        _conn.checkOpen();
+        connection.checkOpen();
         try {
-            return DelegatingResultSet.wrapResultSet(_conn,
-                    _meta.getExportedKeys(catalog, schema, table));
-        }
-        catch (final SQLException e) {
+            return DelegatingResultSet.wrapResultSet(connection,
+                    databaseMetaData.getExportedKeys(catalog, schema, table));
+        } catch (final SQLException e) {
             handleException(e);
             throw new AssertionError();
         }
@@ -294,40 +354,45 @@
 
     @Override
     public String getExtraNameCharacters() throws SQLException {
-        try { return _meta.getExtraNameCharacters(); }
-        catch (final SQLException e) { handleException(e); throw new AssertionError(); }
-    }
-
-    @Override
-    public String getIdentifierQuoteString() throws SQLException {
-        try { return _meta.getIdentifierQuoteString(); }
-        catch (final SQLException e) { handleException(e); throw new AssertionError(); }
-    }
-
-    @Override
-    public ResultSet getImportedKeys(final String catalog, final String schema, final String table)
-            throws SQLException {
-        _conn.checkOpen();
         try {
-            return DelegatingResultSet.wrapResultSet(_conn,
-                    _meta.getImportedKeys(catalog, schema, table));
-        }
-        catch (final SQLException e) {
+            return databaseMetaData.getExtraNameCharacters();
+        } catch (final SQLException e) {
             handleException(e);
             throw new AssertionError();
         }
     }
 
     @Override
-    public ResultSet getIndexInfo(final String catalog, final String schema, final String table,
-            final boolean unique, final boolean approximate) throws SQLException {
-        _conn.checkOpen();
+    public String getIdentifierQuoteString() throws SQLException {
         try {
-            return DelegatingResultSet.wrapResultSet(_conn,
-                    _meta.getIndexInfo(catalog, schema, table, unique,
-                            approximate));
+            return databaseMetaData.getIdentifierQuoteString();
+        } catch (final SQLException e) {
+            handleException(e);
+            throw new AssertionError();
         }
-        catch (final SQLException e) {
+    }
+
+    @Override
+    public ResultSet getImportedKeys(final String catalog, final String schema, final String table)
+            throws SQLException {
+        connection.checkOpen();
+        try {
+            return DelegatingResultSet.wrapResultSet(connection,
+                    databaseMetaData.getImportedKeys(catalog, schema, table));
+        } catch (final SQLException e) {
+            handleException(e);
+            throw new AssertionError();
+        }
+    }
+
+    @Override
+    public ResultSet getIndexInfo(final String catalog, final String schema, final String table, final boolean unique,
+            final boolean approximate) throws SQLException {
+        connection.checkOpen();
+        try {
+            return DelegatingResultSet.wrapResultSet(connection,
+                    databaseMetaData.getIndexInfo(catalog, schema, table, unique, approximate));
+        } catch (final SQLException e) {
             handleException(e);
             throw new AssertionError();
         }
@@ -335,151 +400,241 @@
 
     @Override
     public int getJDBCMajorVersion() throws SQLException {
-        try { return _meta.getJDBCMajorVersion(); }
-        catch (final SQLException e) { handleException(e); return 0; }
+        try {
+            return databaseMetaData.getJDBCMajorVersion();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
     }
 
     @Override
     public int getJDBCMinorVersion() throws SQLException {
-        try { return _meta.getJDBCMinorVersion(); }
-        catch (final SQLException e) { handleException(e); return 0; }
+        try {
+            return databaseMetaData.getJDBCMinorVersion();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
     }
 
     @Override
     public int getMaxBinaryLiteralLength() throws SQLException {
-        try { return _meta.getMaxBinaryLiteralLength(); }
-        catch (final SQLException e) { handleException(e); return 0; }
+        try {
+            return databaseMetaData.getMaxBinaryLiteralLength();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
     }
 
     @Override
     public int getMaxCatalogNameLength() throws SQLException {
-        try { return _meta.getMaxCatalogNameLength(); }
-        catch (final SQLException e) { handleException(e); return 0; }
+        try {
+            return databaseMetaData.getMaxCatalogNameLength();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
     }
 
     @Override
     public int getMaxCharLiteralLength() throws SQLException {
-        try { return _meta.getMaxCharLiteralLength(); }
-        catch (final SQLException e) { handleException(e); return 0; }
+        try {
+            return databaseMetaData.getMaxCharLiteralLength();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
     }
 
     @Override
     public int getMaxColumnNameLength() throws SQLException {
-        try { return _meta.getMaxColumnNameLength(); }
-        catch (final SQLException e) { handleException(e); return 0; }
+        try {
+            return databaseMetaData.getMaxColumnNameLength();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
     }
 
     @Override
     public int getMaxColumnsInGroupBy() throws SQLException {
-        try { return _meta.getMaxColumnsInGroupBy(); }
-        catch (final SQLException e) { handleException(e); return 0; }
+        try {
+            return databaseMetaData.getMaxColumnsInGroupBy();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
     }
 
     @Override
     public int getMaxColumnsInIndex() throws SQLException {
-        try { return _meta.getMaxColumnsInIndex(); }
-        catch (final SQLException e) { handleException(e); return 0; }
+        try {
+            return databaseMetaData.getMaxColumnsInIndex();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
     }
 
     @Override
     public int getMaxColumnsInOrderBy() throws SQLException {
-        try { return _meta.getMaxColumnsInOrderBy(); }
-        catch (final SQLException e) { handleException(e); return 0; }
+        try {
+            return databaseMetaData.getMaxColumnsInOrderBy();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
     }
 
     @Override
     public int getMaxColumnsInSelect() throws SQLException {
-        try { return _meta.getMaxColumnsInSelect(); }
-        catch (final SQLException e) { handleException(e); return 0; }
+        try {
+            return databaseMetaData.getMaxColumnsInSelect();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
     }
 
     @Override
     public int getMaxColumnsInTable() throws SQLException {
-        try { return _meta.getMaxColumnsInTable(); }
-        catch (final SQLException e) { handleException(e); return 0; }
+        try {
+            return databaseMetaData.getMaxColumnsInTable();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
     }
 
     @Override
     public int getMaxConnections() throws SQLException {
-        try { return _meta.getMaxConnections(); }
-        catch (final SQLException e) { handleException(e); return 0; }
+        try {
+            return databaseMetaData.getMaxConnections();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
     }
 
     @Override
     public int getMaxCursorNameLength() throws SQLException {
-        try { return _meta.getMaxCursorNameLength(); }
-        catch (final SQLException e) { handleException(e); return 0; }
+        try {
+            return databaseMetaData.getMaxCursorNameLength();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
     }
 
     @Override
     public int getMaxIndexLength() throws SQLException {
-        try { return _meta.getMaxIndexLength(); }
-        catch (final SQLException e) { handleException(e); return 0; }
+        try {
+            return databaseMetaData.getMaxIndexLength();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
     }
 
     @Override
     public int getMaxProcedureNameLength() throws SQLException {
-        try { return _meta.getMaxProcedureNameLength(); }
-        catch (final SQLException e) { handleException(e); return 0; }
+        try {
+            return databaseMetaData.getMaxProcedureNameLength();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
     }
 
     @Override
     public int getMaxRowSize() throws SQLException {
-        try { return _meta.getMaxRowSize(); }
-        catch (final SQLException e) { handleException(e); return 0; }
+        try {
+            return databaseMetaData.getMaxRowSize();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
     }
 
     @Override
     public int getMaxSchemaNameLength() throws SQLException {
-        try { return _meta.getMaxSchemaNameLength(); }
-        catch (final SQLException e) { handleException(e); return 0; }
+        try {
+            return databaseMetaData.getMaxSchemaNameLength();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
     }
 
     @Override
     public int getMaxStatementLength() throws SQLException {
-        try { return _meta.getMaxStatementLength(); }
-        catch (final SQLException e) { handleException(e); return 0; }
+        try {
+            return databaseMetaData.getMaxStatementLength();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
     }
 
     @Override
     public int getMaxStatements() throws SQLException {
-        try { return _meta.getMaxStatements(); }
-        catch (final SQLException e) { handleException(e); return 0; }
+        try {
+            return databaseMetaData.getMaxStatements();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
     }
 
     @Override
     public int getMaxTableNameLength() throws SQLException {
-        try { return _meta.getMaxTableNameLength(); }
-        catch (final SQLException e) { handleException(e); return 0; }
+        try {
+            return databaseMetaData.getMaxTableNameLength();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
     }
 
     @Override
     public int getMaxTablesInSelect() throws SQLException {
-        try { return _meta.getMaxTablesInSelect(); }
-        catch (final SQLException e) { handleException(e); return 0; }
+        try {
+            return databaseMetaData.getMaxTablesInSelect();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
     }
 
     @Override
     public int getMaxUserNameLength() throws SQLException {
-        try { return _meta.getMaxUserNameLength(); }
-        catch (final SQLException e) { handleException(e); return 0; }
+        try {
+            return databaseMetaData.getMaxUserNameLength();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
     }
 
     @Override
     public String getNumericFunctions() throws SQLException {
-        try { return _meta.getNumericFunctions(); }
-        catch (final SQLException e) { handleException(e); throw new AssertionError(); }
+        try {
+            return databaseMetaData.getNumericFunctions();
+        } catch (final SQLException e) {
+            handleException(e);
+            throw new AssertionError();
+        }
     }
 
     @Override
-    public ResultSet getPrimaryKeys(final String catalog, final String schema, final String table)
-            throws SQLException {
-        _conn.checkOpen();
+    public ResultSet getPrimaryKeys(final String catalog, final String schema, final String table) throws SQLException {
+        connection.checkOpen();
         try {
-            return DelegatingResultSet.wrapResultSet(_conn,
-                    _meta.getPrimaryKeys(catalog, schema, table));
-        }
-        catch (final SQLException e) {
+            return DelegatingResultSet.wrapResultSet(connection,
+                    databaseMetaData.getPrimaryKeys(catalog, schema, table));
+        } catch (final SQLException e) {
             handleException(e);
             throw new AssertionError();
         }
@@ -487,15 +642,12 @@
 
     @Override
     public ResultSet getProcedureColumns(final String catalog, final String schemaPattern,
-            final String procedureNamePattern, final String columnNamePattern)
-            throws SQLException {
-        _conn.checkOpen();
+            final String procedureNamePattern, final String columnNamePattern) throws SQLException {
+        connection.checkOpen();
         try {
-            return DelegatingResultSet.wrapResultSet(_conn,
-                    _meta.getProcedureColumns(catalog, schemaPattern,
-                            procedureNamePattern, columnNamePattern));
-        }
-        catch (final SQLException e) {
+            return DelegatingResultSet.wrapResultSet(connection, databaseMetaData.getProcedureColumns(catalog,
+                    schemaPattern, procedureNamePattern, columnNamePattern));
+        } catch (final SQLException e) {
             handleException(e);
             throw new AssertionError();
         }
@@ -503,20 +655,22 @@
 
     @Override
     public String getProcedureTerm() throws SQLException {
-        try { return _meta.getProcedureTerm(); }
-        catch (final SQLException e) { handleException(e); throw new AssertionError(); }
+        try {
+            return databaseMetaData.getProcedureTerm();
+        } catch (final SQLException e) {
+            handleException(e);
+            throw new AssertionError();
+        }
     }
 
     @Override
-    public ResultSet getProcedures(final String catalog, final String schemaPattern,
-            final String procedureNamePattern) throws SQLException {
-        _conn.checkOpen();
+    public ResultSet getProcedures(final String catalog, final String schemaPattern, final String procedureNamePattern)
+            throws SQLException {
+        connection.checkOpen();
         try {
-            return DelegatingResultSet.wrapResultSet(_conn,
-                    _meta.getProcedures(catalog, schemaPattern,
-                            procedureNamePattern));
-        }
-        catch (final SQLException e) {
+            return DelegatingResultSet.wrapResultSet(connection,
+                    databaseMetaData.getProcedures(catalog, schemaPattern, procedureNamePattern));
+        } catch (final SQLException e) {
             handleException(e);
             throw new AssertionError();
         }
@@ -524,36 +678,50 @@
 
     @Override
     public int getResultSetHoldability() throws SQLException {
-        try { return _meta.getResultSetHoldability(); }
-        catch (final SQLException e) { handleException(e); return 0; }
+        try {
+            return databaseMetaData.getResultSetHoldability();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
     }
 
     @Override
     public String getSQLKeywords() throws SQLException {
-        try { return _meta.getSQLKeywords(); }
-        catch (final SQLException e) { handleException(e); throw new AssertionError(); }
+        try {
+            return databaseMetaData.getSQLKeywords();
+        } catch (final SQLException e) {
+            handleException(e);
+            throw new AssertionError();
+        }
     }
 
     @Override
     public int getSQLStateType() throws SQLException {
-        try { return _meta.getSQLStateType(); }
-        catch (final SQLException e) { handleException(e); return 0; }
+        try {
+            return databaseMetaData.getSQLStateType();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
     }
 
     @Override
     public String getSchemaTerm() throws SQLException {
-        try { return _meta.getSchemaTerm(); }
-        catch (final SQLException e) { handleException(e); throw new AssertionError(); }
+        try {
+            return databaseMetaData.getSchemaTerm();
+        } catch (final SQLException e) {
+            handleException(e);
+            throw new AssertionError();
+        }
     }
 
     @Override
     public ResultSet getSchemas() throws SQLException {
-        _conn.checkOpen();
+        connection.checkOpen();
         try {
-            return DelegatingResultSet.wrapResultSet(_conn,
-                    _meta.getSchemas());
-        }
-        catch (final SQLException e) {
+            return DelegatingResultSet.wrapResultSet(connection, databaseMetaData.getSchemas());
+        } catch (final SQLException e) {
             handleException(e);
             throw new AssertionError();
         }
@@ -561,41 +729,45 @@
 
     @Override
     public String getSearchStringEscape() throws SQLException {
-        try { return _meta.getSearchStringEscape(); }
-        catch (final SQLException e) { handleException(e); throw new AssertionError(); }
-    }
-
-    @Override
-    public String getStringFunctions() throws SQLException {
-        try { return _meta.getStringFunctions(); }
-        catch (final SQLException e) { handleException(e); throw new AssertionError(); }
-    }
-
-    @Override
-    public ResultSet getSuperTables(final String catalog, final String schemaPattern,
-            final String tableNamePattern) throws SQLException {
-        _conn.checkOpen();
         try {
-            return DelegatingResultSet.wrapResultSet(_conn,
-                    _meta.getSuperTables(catalog, schemaPattern,
-                            tableNamePattern));
-        }
-        catch (final SQLException e) {
+            return databaseMetaData.getSearchStringEscape();
+        } catch (final SQLException e) {
             handleException(e);
             throw new AssertionError();
         }
     }
 
     @Override
-    public ResultSet getSuperTypes(final String catalog, final String schemaPattern,
-            final String typeNamePattern) throws SQLException {
-        _conn.checkOpen();
+    public String getStringFunctions() throws SQLException {
         try {
-            return DelegatingResultSet.wrapResultSet(_conn,
-                    _meta.getSuperTypes(catalog, schemaPattern,
-                            typeNamePattern));
+            return databaseMetaData.getStringFunctions();
+        } catch (final SQLException e) {
+            handleException(e);
+            throw new AssertionError();
         }
-        catch (final SQLException e) {
+    }
+
+    @Override
+    public ResultSet getSuperTables(final String catalog, final String schemaPattern, final String tableNamePattern)
+            throws SQLException {
+        connection.checkOpen();
+        try {
+            return DelegatingResultSet.wrapResultSet(connection,
+                    databaseMetaData.getSuperTables(catalog, schemaPattern, tableNamePattern));
+        } catch (final SQLException e) {
+            handleException(e);
+            throw new AssertionError();
+        }
+    }
+
+    @Override
+    public ResultSet getSuperTypes(final String catalog, final String schemaPattern, final String typeNamePattern)
+            throws SQLException {
+        connection.checkOpen();
+        try {
+            return DelegatingResultSet.wrapResultSet(connection,
+                    databaseMetaData.getSuperTypes(catalog, schemaPattern, typeNamePattern));
+        } catch (final SQLException e) {
             handleException(e);
             throw new AssertionError();
         }
@@ -603,20 +775,22 @@
 
     @Override
     public String getSystemFunctions() throws SQLException {
-        try { return _meta.getSystemFunctions(); }
-        catch (final SQLException e) { handleException(e); throw new AssertionError(); }
+        try {
+            return databaseMetaData.getSystemFunctions();
+        } catch (final SQLException e) {
+            handleException(e);
+            throw new AssertionError();
+        }
     }
 
     @Override
-    public ResultSet getTablePrivileges(final String catalog, final String schemaPattern,
-            final String tableNamePattern) throws SQLException {
-        _conn.checkOpen();
+    public ResultSet getTablePrivileges(final String catalog, final String schemaPattern, final String tableNamePattern)
+            throws SQLException {
+        connection.checkOpen();
         try {
-            return DelegatingResultSet.wrapResultSet(_conn,
-                    _meta.getTablePrivileges(catalog, schemaPattern,
-                            tableNamePattern));
-        }
-        catch (final SQLException e) {
+            return DelegatingResultSet.wrapResultSet(connection,
+                    databaseMetaData.getTablePrivileges(catalog, schemaPattern, tableNamePattern));
+        } catch (final SQLException e) {
             handleException(e);
             throw new AssertionError();
         }
@@ -624,27 +798,23 @@
 
     @Override
     public ResultSet getTableTypes() throws SQLException {
-        _conn.checkOpen();
+        connection.checkOpen();
         try {
-            return DelegatingResultSet.wrapResultSet(_conn,
-                    _meta.getTableTypes());
-        }
-        catch (final SQLException e) {
+            return DelegatingResultSet.wrapResultSet(connection, databaseMetaData.getTableTypes());
+        } catch (final SQLException e) {
             handleException(e);
             throw new AssertionError();
         }
     }
 
     @Override
-    public ResultSet getTables(final String catalog, final String schemaPattern,
-            final String tableNamePattern, final String[] types) throws SQLException {
-        _conn.checkOpen();
+    public ResultSet getTables(final String catalog, final String schemaPattern, final String tableNamePattern,
+            final String[] types) throws SQLException {
+        connection.checkOpen();
         try {
-            return DelegatingResultSet.wrapResultSet(_conn,
-                    _meta.getTables(catalog, schemaPattern, tableNamePattern,
-                            types));
-        }
-        catch (final SQLException e) {
+            return DelegatingResultSet.wrapResultSet(connection,
+                    databaseMetaData.getTables(catalog, schemaPattern, tableNamePattern, types));
+        } catch (final SQLException e) {
             handleException(e);
             throw new AssertionError();
         }
@@ -652,33 +822,33 @@
 
     @Override
     public String getTimeDateFunctions() throws SQLException {
-        try { return _meta.getTimeDateFunctions(); }
-        catch (final SQLException e) { handleException(e); throw new AssertionError(); }
-    }
-
-    @Override
-    public ResultSet getTypeInfo() throws SQLException {
-        _conn.checkOpen();
         try {
-            return DelegatingResultSet.wrapResultSet(_conn,
-                    _meta.getTypeInfo());
-        }
-        catch (final SQLException e) {
+            return databaseMetaData.getTimeDateFunctions();
+        } catch (final SQLException e) {
             handleException(e);
             throw new AssertionError();
         }
     }
 
     @Override
-    public ResultSet getUDTs(final String catalog, final String schemaPattern,
-            final String typeNamePattern, final int[] types) throws SQLException {
-        _conn.checkOpen();
+    public ResultSet getTypeInfo() throws SQLException {
+        connection.checkOpen();
         try {
-            return DelegatingResultSet.wrapResultSet(_conn,
-                    _meta.getUDTs(catalog, schemaPattern, typeNamePattern,
-                            types));
+            return DelegatingResultSet.wrapResultSet(connection, databaseMetaData.getTypeInfo());
+        } catch (final SQLException e) {
+            handleException(e);
+            throw new AssertionError();
         }
-        catch (final SQLException e) {
+    }
+
+    @Override
+    public ResultSet getUDTs(final String catalog, final String schemaPattern, final String typeNamePattern,
+            final int[] types) throws SQLException {
+        connection.checkOpen();
+        try {
+            return DelegatingResultSet.wrapResultSet(connection,
+                    databaseMetaData.getUDTs(catalog, schemaPattern, typeNamePattern, types));
+        } catch (final SQLException e) {
             handleException(e);
             throw new AssertionError();
         }
@@ -686,25 +856,32 @@
 
     @Override
     public String getURL() throws SQLException {
-        try { return _meta.getURL(); }
-        catch (final SQLException e) { handleException(e); throw new AssertionError(); }
+        try {
+            return databaseMetaData.getURL();
+        } catch (final SQLException e) {
+            handleException(e);
+            throw new AssertionError();
+        }
     }
 
     @Override
     public String getUserName() throws SQLException {
-        try { return _meta.getUserName(); }
-        catch (final SQLException e) { handleException(e); throw new AssertionError(); }
+        try {
+            return databaseMetaData.getUserName();
+        } catch (final SQLException e) {
+            handleException(e);
+            throw new AssertionError();
+        }
     }
 
     @Override
-    public ResultSet getVersionColumns(final String catalog, final String schema,
-            final String table) throws SQLException {
-        _conn.checkOpen();
+    public ResultSet getVersionColumns(final String catalog, final String schema, final String table)
+            throws SQLException {
+        connection.checkOpen();
         try {
-            return DelegatingResultSet.wrapResultSet(_conn,
-                    _meta.getVersionColumns(catalog, schema, table));
-        }
-        catch (final SQLException e) {
+            return DelegatingResultSet.wrapResultSet(connection,
+                    databaseMetaData.getVersionColumns(catalog, schema, table));
+        } catch (final SQLException e) {
             handleException(e);
             throw new AssertionError();
         }
@@ -712,548 +889,902 @@
 
     @Override
     public boolean insertsAreDetected(final int type) throws SQLException {
-        try { return _meta.insertsAreDetected(type); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.insertsAreDetected(type);
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean isCatalogAtStart() throws SQLException {
-        try { return _meta.isCatalogAtStart(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.isCatalogAtStart();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean isReadOnly() throws SQLException {
-        try { return _meta.isReadOnly(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.isReadOnly();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean locatorsUpdateCopy() throws SQLException {
-        try { return _meta.locatorsUpdateCopy(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.locatorsUpdateCopy();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean nullPlusNonNullIsNull() throws SQLException {
-        try { return _meta.nullPlusNonNullIsNull(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.nullPlusNonNullIsNull();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean nullsAreSortedAtEnd() throws SQLException {
-        try { return _meta.nullsAreSortedAtEnd(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.nullsAreSortedAtEnd();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean nullsAreSortedAtStart() throws SQLException {
-        try { return _meta.nullsAreSortedAtStart(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.nullsAreSortedAtStart();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean nullsAreSortedHigh() throws SQLException {
-        try { return _meta.nullsAreSortedHigh(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.nullsAreSortedHigh();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean nullsAreSortedLow() throws SQLException {
-        try { return _meta.nullsAreSortedLow(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.nullsAreSortedLow();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean othersDeletesAreVisible(final int type) throws SQLException {
-        try { return _meta.othersDeletesAreVisible(type); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.othersDeletesAreVisible(type);
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean othersInsertsAreVisible(final int type) throws SQLException {
-        try { return _meta.othersInsertsAreVisible(type); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.othersInsertsAreVisible(type);
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean othersUpdatesAreVisible(final int type) throws SQLException {
-        try { return _meta.othersUpdatesAreVisible(type); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.othersUpdatesAreVisible(type);
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean ownDeletesAreVisible(final int type) throws SQLException {
-        try { return _meta.ownDeletesAreVisible(type); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.ownDeletesAreVisible(type);
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean ownInsertsAreVisible(final int type) throws SQLException {
-        try { return _meta.ownInsertsAreVisible(type); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.ownInsertsAreVisible(type);
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean ownUpdatesAreVisible(final int type) throws SQLException {
-        try { return _meta.ownUpdatesAreVisible(type); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.ownUpdatesAreVisible(type);
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean storesLowerCaseIdentifiers() throws SQLException {
-        try { return _meta.storesLowerCaseIdentifiers(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.storesLowerCaseIdentifiers();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean storesLowerCaseQuotedIdentifiers() throws SQLException {
-        try { return _meta.storesLowerCaseQuotedIdentifiers(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.storesLowerCaseQuotedIdentifiers();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean storesMixedCaseIdentifiers() throws SQLException {
-        try { return _meta.storesMixedCaseIdentifiers(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.storesMixedCaseIdentifiers();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean storesMixedCaseQuotedIdentifiers() throws SQLException {
-        try { return _meta.storesMixedCaseQuotedIdentifiers(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.storesMixedCaseQuotedIdentifiers();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean storesUpperCaseIdentifiers() throws SQLException {
-        try { return _meta.storesUpperCaseIdentifiers(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.storesUpperCaseIdentifiers();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean storesUpperCaseQuotedIdentifiers() throws SQLException {
-        try { return _meta.storesUpperCaseQuotedIdentifiers(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.storesUpperCaseQuotedIdentifiers();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsANSI92EntryLevelSQL() throws SQLException {
-        try { return _meta.supportsANSI92EntryLevelSQL(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsANSI92EntryLevelSQL();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsANSI92FullSQL() throws SQLException {
-        try { return _meta.supportsANSI92FullSQL(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsANSI92FullSQL();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsANSI92IntermediateSQL() throws SQLException {
-        try { return _meta.supportsANSI92IntermediateSQL(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsANSI92IntermediateSQL();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsAlterTableWithAddColumn() throws SQLException {
-        try { return _meta.supportsAlterTableWithAddColumn(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsAlterTableWithAddColumn();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsAlterTableWithDropColumn() throws SQLException {
-        try { return _meta.supportsAlterTableWithDropColumn(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsAlterTableWithDropColumn();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsBatchUpdates() throws SQLException {
-        try { return _meta.supportsBatchUpdates(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsBatchUpdates();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsCatalogsInDataManipulation() throws SQLException {
-        try { return _meta.supportsCatalogsInDataManipulation(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsCatalogsInDataManipulation();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsCatalogsInIndexDefinitions() throws SQLException {
-        try { return _meta.supportsCatalogsInIndexDefinitions(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsCatalogsInIndexDefinitions();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException {
-        try { return _meta.supportsCatalogsInPrivilegeDefinitions(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsCatalogsInPrivilegeDefinitions();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsCatalogsInProcedureCalls() throws SQLException {
-        try { return _meta.supportsCatalogsInProcedureCalls(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsCatalogsInProcedureCalls();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsCatalogsInTableDefinitions() throws SQLException {
-        try { return _meta.supportsCatalogsInTableDefinitions(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsCatalogsInTableDefinitions();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsColumnAliasing() throws SQLException {
-        try { return _meta.supportsColumnAliasing(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsColumnAliasing();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsConvert() throws SQLException {
-        try { return _meta.supportsConvert(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsConvert();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
-    public boolean supportsConvert(final int fromType, final int toType)
-            throws SQLException {
-        try { return _meta.supportsConvert(fromType, toType); }
-        catch (final SQLException e) { handleException(e); return false; }
+    public boolean supportsConvert(final int fromType, final int toType) throws SQLException {
+        try {
+            return databaseMetaData.supportsConvert(fromType, toType);
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsCoreSQLGrammar() throws SQLException {
-        try { return _meta.supportsCoreSQLGrammar(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsCoreSQLGrammar();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsCorrelatedSubqueries() throws SQLException {
-        try { return _meta.supportsCorrelatedSubqueries(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsCorrelatedSubqueries();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
-    public boolean supportsDataDefinitionAndDataManipulationTransactions()
-            throws SQLException {
-        try { return _meta.supportsDataDefinitionAndDataManipulationTransactions(); }
-        catch (final SQLException e) { handleException(e); return false; }
+    public boolean supportsDataDefinitionAndDataManipulationTransactions() throws SQLException {
+        try {
+            return databaseMetaData.supportsDataDefinitionAndDataManipulationTransactions();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
-    public boolean supportsDataManipulationTransactionsOnly()
-            throws SQLException {
-        try { return _meta.supportsDataManipulationTransactionsOnly(); }
-        catch (final SQLException e) { handleException(e); return false; }
+    public boolean supportsDataManipulationTransactionsOnly() throws SQLException {
+        try {
+            return databaseMetaData.supportsDataManipulationTransactionsOnly();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsDifferentTableCorrelationNames() throws SQLException {
-        try { return _meta.supportsDifferentTableCorrelationNames(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsDifferentTableCorrelationNames();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsExpressionsInOrderBy() throws SQLException {
-        try { return _meta.supportsExpressionsInOrderBy(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsExpressionsInOrderBy();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsExtendedSQLGrammar() throws SQLException {
-        try { return _meta.supportsExtendedSQLGrammar(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsExtendedSQLGrammar();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsFullOuterJoins() throws SQLException {
-        try { return _meta.supportsFullOuterJoins(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsFullOuterJoins();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsGetGeneratedKeys() throws SQLException {
-        try { return _meta.supportsGetGeneratedKeys(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsGetGeneratedKeys();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsGroupBy() throws SQLException {
-        try { return _meta.supportsGroupBy(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsGroupBy();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsGroupByBeyondSelect() throws SQLException {
-        try { return _meta.supportsGroupByBeyondSelect(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsGroupByBeyondSelect();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsGroupByUnrelated() throws SQLException {
-        try { return _meta.supportsGroupByUnrelated(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsGroupByUnrelated();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsIntegrityEnhancementFacility() throws SQLException {
-        try { return _meta.supportsIntegrityEnhancementFacility(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsIntegrityEnhancementFacility();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsLikeEscapeClause() throws SQLException {
-        try { return _meta.supportsLikeEscapeClause(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsLikeEscapeClause();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsLimitedOuterJoins() throws SQLException {
-        try { return _meta.supportsLimitedOuterJoins(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsLimitedOuterJoins();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsMinimumSQLGrammar() throws SQLException {
-        try { return _meta.supportsMinimumSQLGrammar(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsMinimumSQLGrammar();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsMixedCaseIdentifiers() throws SQLException {
-        try { return _meta.supportsMixedCaseIdentifiers(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsMixedCaseIdentifiers();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException {
-        try { return _meta.supportsMixedCaseQuotedIdentifiers(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsMixedCaseQuotedIdentifiers();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsMultipleOpenResults() throws SQLException {
-        try { return _meta.supportsMultipleOpenResults(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsMultipleOpenResults();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsMultipleResultSets() throws SQLException {
-        try { return _meta.supportsMultipleResultSets(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsMultipleResultSets();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsMultipleTransactions() throws SQLException {
-        try { return _meta.supportsMultipleTransactions(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsMultipleTransactions();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsNamedParameters() throws SQLException {
-        try { return _meta.supportsNamedParameters(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsNamedParameters();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsNonNullableColumns() throws SQLException {
-        try { return _meta.supportsNonNullableColumns(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsNonNullableColumns();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsOpenCursorsAcrossCommit() throws SQLException {
-        try { return _meta.supportsOpenCursorsAcrossCommit(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsOpenCursorsAcrossCommit();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsOpenCursorsAcrossRollback() throws SQLException {
-        try { return _meta.supportsOpenCursorsAcrossRollback(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsOpenCursorsAcrossRollback();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsOpenStatementsAcrossCommit() throws SQLException {
-        try { return _meta.supportsOpenStatementsAcrossCommit(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsOpenStatementsAcrossCommit();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsOpenStatementsAcrossRollback() throws SQLException {
-        try { return _meta.supportsOpenStatementsAcrossRollback(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsOpenStatementsAcrossRollback();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsOrderByUnrelated() throws SQLException {
-        try { return _meta.supportsOrderByUnrelated(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsOrderByUnrelated();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsOuterJoins() throws SQLException {
-        try { return _meta.supportsOuterJoins(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsOuterJoins();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsPositionedDelete() throws SQLException {
-        try { return _meta.supportsPositionedDelete(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsPositionedDelete();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsPositionedUpdate() throws SQLException {
-        try { return _meta.supportsPositionedUpdate(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsPositionedUpdate();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
-    public boolean supportsResultSetConcurrency(final int type, final int concurrency)
-            throws SQLException {
-        try { return _meta.supportsResultSetConcurrency(type, concurrency); }
-        catch (final SQLException e) { handleException(e); return false; }
+    public boolean supportsResultSetConcurrency(final int type, final int concurrency) throws SQLException {
+        try {
+            return databaseMetaData.supportsResultSetConcurrency(type, concurrency);
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
-    public boolean supportsResultSetHoldability(final int holdability)
-            throws SQLException {
-        try { return _meta.supportsResultSetHoldability(holdability); }
-        catch (final SQLException e) { handleException(e); return false; }
+    public boolean supportsResultSetHoldability(final int holdability) throws SQLException {
+        try {
+            return databaseMetaData.supportsResultSetHoldability(holdability);
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsResultSetType(final int type) throws SQLException {
-        try { return _meta.supportsResultSetType(type); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsResultSetType(type);
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsSavepoints() throws SQLException {
-        try { return _meta.supportsSavepoints(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsSavepoints();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsSchemasInDataManipulation() throws SQLException {
-        try { return _meta.supportsSchemasInDataManipulation(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsSchemasInDataManipulation();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsSchemasInIndexDefinitions() throws SQLException {
-        try { return _meta.supportsSchemasInIndexDefinitions(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsSchemasInIndexDefinitions();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException {
-        try { return _meta.supportsSchemasInPrivilegeDefinitions(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsSchemasInPrivilegeDefinitions();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsSchemasInProcedureCalls() throws SQLException {
-        try { return _meta.supportsSchemasInProcedureCalls(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsSchemasInProcedureCalls();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsSchemasInTableDefinitions() throws SQLException {
-        try { return _meta.supportsSchemasInTableDefinitions(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsSchemasInTableDefinitions();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsSelectForUpdate() throws SQLException {
-        try { return _meta.supportsSelectForUpdate(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsSelectForUpdate();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsStatementPooling() throws SQLException {
-        try { return _meta.supportsStatementPooling(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsStatementPooling();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsStoredProcedures() throws SQLException {
-        try { return _meta.supportsStoredProcedures(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsStoredProcedures();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsSubqueriesInComparisons() throws SQLException {
-        try { return _meta.supportsSubqueriesInComparisons(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsSubqueriesInComparisons();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsSubqueriesInExists() throws SQLException {
-        try { return _meta.supportsSubqueriesInExists(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsSubqueriesInExists();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsSubqueriesInIns() throws SQLException {
-        try { return _meta.supportsSubqueriesInIns(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsSubqueriesInIns();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsSubqueriesInQuantifieds() throws SQLException {
-        try { return _meta.supportsSubqueriesInQuantifieds(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsSubqueriesInQuantifieds();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsTableCorrelationNames() throws SQLException {
-        try { return _meta.supportsTableCorrelationNames(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsTableCorrelationNames();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
-    public boolean supportsTransactionIsolationLevel(final int level)
-            throws SQLException {
-        try { return _meta.supportsTransactionIsolationLevel(level); }
-        catch (final SQLException e) { handleException(e); return false; }
+    public boolean supportsTransactionIsolationLevel(final int level) throws SQLException {
+        try {
+            return databaseMetaData.supportsTransactionIsolationLevel(level);
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsTransactions() throws SQLException {
-        try { return _meta.supportsTransactions(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsTransactions();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsUnion() throws SQLException {
-        try { return _meta.supportsUnion(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsUnion();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsUnionAll() throws SQLException {
-        try { return _meta.supportsUnionAll(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsUnionAll();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean updatesAreDetected(final int type) throws SQLException {
-        try { return _meta.updatesAreDetected(type); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.updatesAreDetected(type);
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean usesLocalFilePerTable() throws SQLException {
-        try { return _meta.usesLocalFilePerTable(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.usesLocalFilePerTable();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean usesLocalFiles() throws SQLException {
-        try { return _meta.usesLocalFiles(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.usesLocalFiles();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     /* JDBC_4_ANT_KEY_BEGIN */
@@ -1262,10 +1793,10 @@
     public boolean isWrapperFor(final Class<?> iface) throws SQLException {
         if (iface.isAssignableFrom(getClass())) {
             return true;
-        } else if (iface.isAssignableFrom(_meta.getClass())) {
+        } else if (iface.isAssignableFrom(databaseMetaData.getClass())) {
             return true;
         } else {
-            return _meta.isWrapperFor(iface);
+            return databaseMetaData.isWrapperFor(iface);
         }
     }
 
@@ -1273,28 +1804,29 @@
     public <T> T unwrap(final Class<T> iface) throws SQLException {
         if (iface.isAssignableFrom(getClass())) {
             return iface.cast(this);
-        } else if (iface.isAssignableFrom(_meta.getClass())) {
-            return iface.cast(_meta);
+        } else if (iface.isAssignableFrom(databaseMetaData.getClass())) {
+            return iface.cast(databaseMetaData);
         } else {
-            return _meta.unwrap(iface);
+            return databaseMetaData.unwrap(iface);
         }
     }
 
     @Override
     public RowIdLifetime getRowIdLifetime() throws SQLException {
-        try { return _meta.getRowIdLifetime(); }
-        catch (final SQLException e) { handleException(e); throw new AssertionError(); }
+        try {
+            return databaseMetaData.getRowIdLifetime();
+        } catch (final SQLException e) {
+            handleException(e);
+            throw new AssertionError();
+        }
     }
 
     @Override
-    public ResultSet getSchemas(final String catalog, final String schemaPattern)
-    throws SQLException {
-        _conn.checkOpen();
+    public ResultSet getSchemas(final String catalog, final String schemaPattern) throws SQLException {
+        connection.checkOpen();
         try {
-            return DelegatingResultSet.wrapResultSet(_conn,
-                    _meta.getSchemas(catalog, schemaPattern));
-        }
-        catch (final SQLException e) {
+            return DelegatingResultSet.wrapResultSet(connection, databaseMetaData.getSchemas(catalog, schemaPattern));
+        } catch (final SQLException e) {
             handleException(e);
             throw new AssertionError();
         }
@@ -1302,39 +1834,43 @@
 
     @Override
     public boolean autoCommitFailureClosesAllResultSets() throws SQLException {
-        try { return _meta.autoCommitFailureClosesAllResultSets(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.autoCommitFailureClosesAllResultSets();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public boolean supportsStoredFunctionsUsingCallSyntax() throws SQLException {
-        try { return _meta.supportsStoredFunctionsUsingCallSyntax(); }
-        catch (final SQLException e) { handleException(e); return false; }
+        try {
+            return databaseMetaData.supportsStoredFunctionsUsingCallSyntax();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
     }
 
     @Override
     public ResultSet getClientInfoProperties() throws SQLException {
-        _conn.checkOpen();
+        connection.checkOpen();
         try {
-            return DelegatingResultSet.wrapResultSet(_conn,
-                    _meta.getClientInfoProperties());
-        }
-        catch (final SQLException e) {
+            return DelegatingResultSet.wrapResultSet(connection, databaseMetaData.getClientInfoProperties());
+        } catch (final SQLException e) {
             handleException(e);
             throw new AssertionError();
         }
     }
 
     @Override
-    public ResultSet getFunctions(final String catalog, final String schemaPattern,
-            final String functionNamePattern) throws SQLException {
-        _conn.checkOpen();
+    public ResultSet getFunctions(final String catalog, final String schemaPattern, final String functionNamePattern)
+            throws SQLException {
+        connection.checkOpen();
         try {
-            return DelegatingResultSet.wrapResultSet(_conn,
-                    _meta.getFunctions(catalog, schemaPattern,
-                            functionNamePattern));
-        }
-        catch (final SQLException e) {
+            return DelegatingResultSet.wrapResultSet(connection,
+                    databaseMetaData.getFunctions(catalog, schemaPattern, functionNamePattern));
+        } catch (final SQLException e) {
             handleException(e);
             throw new AssertionError();
         }
@@ -1342,15 +1878,12 @@
 
     @Override
     public ResultSet getFunctionColumns(final String catalog, final String schemaPattern,
-            final String functionNamePattern, final String columnNamePattern)
-            throws SQLException {
-        _conn.checkOpen();
+            final String functionNamePattern, final String columnNamePattern) throws SQLException {
+        connection.checkOpen();
         try {
-            return DelegatingResultSet.wrapResultSet(_conn,
-                    _meta.getFunctionColumns(catalog, schemaPattern,
-                            functionNamePattern, columnNamePattern));
-        }
-        catch (final SQLException e) {
+            return DelegatingResultSet.wrapResultSet(connection, databaseMetaData.getFunctionColumns(catalog,
+                    schemaPattern, functionNamePattern, columnNamePattern));
+        } catch (final SQLException e) {
             handleException(e);
             throw new AssertionError();
         }
@@ -1359,16 +1892,13 @@
     /* JDBC_4_ANT_KEY_END */
 
     @Override
-    public ResultSet getPseudoColumns(final String catalog, final String schemaPattern,
-            final String tableNamePattern, final String columnNamePattern)
-            throws SQLException {
-        _conn.checkOpen();
+    public ResultSet getPseudoColumns(final String catalog, final String schemaPattern, final String tableNamePattern,
+            final String columnNamePattern) throws SQLException {
+        connection.checkOpen();
         try {
-            return DelegatingResultSet.wrapResultSet(_conn,
-                    _meta.getPseudoColumns(catalog, schemaPattern,
-                            tableNamePattern, columnNamePattern));
-}
-        catch (final SQLException e) {
+            return DelegatingResultSet.wrapResultSet(connection,
+                    databaseMetaData.getPseudoColumns(catalog, schemaPattern, tableNamePattern, columnNamePattern));
+        } catch (final SQLException e) {
             handleException(e);
             throw new AssertionError();
         }
@@ -1376,11 +1906,10 @@
 
     @Override
     public boolean generatedKeyAlwaysReturned() throws SQLException {
-        _conn.checkOpen();
+        connection.checkOpen();
         try {
-            return _meta.generatedKeyAlwaysReturned();
-        }
-        catch (final SQLException e) {
+            return databaseMetaData.generatedKeyAlwaysReturned();
+        } catch (final SQLException e) {
             handleException(e);
             return false;
         }
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingPreparedStatement.java b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingPreparedStatement.java
index ec3ad6a..26de0cf 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingPreparedStatement.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingPreparedStatement.java
@@ -40,36 +40,27 @@
 /**
  * A base delegating implementation of {@link PreparedStatement}.
  * <p>
- * All of the methods from the {@link PreparedStatement} interface
- * simply check to see that the {@link PreparedStatement} is active,
- * and call the corresponding method on the "delegate"
- * provided in my constructor.
+ * All of the methods from the {@link PreparedStatement} interface simply check to see that the
+ * {@link PreparedStatement} is active, and call the corresponding method on the "delegate" provided in my constructor.
  * <p>
- * Extends AbandonedTrace to implement Statement tracking and
- * logging of code which created the Statement. Tracking the
- * Statement ensures that the Connection which created it can
- * close any open Statement's on Connection close.
+ * Extends AbandonedTrace to implement Statement tracking and logging of code which created the Statement. Tracking the
+ * Statement ensures that the Connection which created it can close any open Statement's on Connection close.
  *
- * @author Rodney Waldhoff
- * @author Glenn L. Nielsen
- * @author James House
- * @author Dirk Verbeeck
  * @since 2.0
  */
-public class DelegatingPreparedStatement extends DelegatingStatement
-        implements PreparedStatement {
+public class DelegatingPreparedStatement extends DelegatingStatement implements PreparedStatement {
 
     /**
-     * Create a wrapper for the Statement which traces this
-     * Statement to the Connection which created it and the
-     * code which created it.
+     * Create a wrapper for the Statement which traces this Statement to the Connection which created it and the code
+     * which created it.
      *
-     * @param s the {@link PreparedStatement} to delegate all calls to.
-     * @param c the {@link DelegatingConnection} that created this statement.
+     * @param statement
+     *            the {@link PreparedStatement} to delegate all calls to.
+     * @param connection
+     *            the {@link DelegatingConnection} that created this statement.
      */
-    public DelegatingPreparedStatement(final DelegatingConnection<?> c,
-                                       final PreparedStatement s) {
-        super(c, s);
+    public DelegatingPreparedStatement(final DelegatingConnection<?> connection, final PreparedStatement statement) {
+        super(connection, statement);
     }
 
     @Override
@@ -79,9 +70,8 @@
             getConnectionInternal().setLastUsed();
         }
         try {
-            return DelegatingResultSet.wrapResultSet(this,((PreparedStatement)getDelegate()).executeQuery());
-        }
-        catch (final SQLException e) {
+            return DelegatingResultSet.wrapResultSet(this, getDelegatePreparedStatement().executeQuery());
+        } catch (final SQLException e) {
             handleException(e);
             throw new AssertionError();
         }
@@ -94,98 +84,229 @@
             getConnectionInternal().setLastUsed();
         }
         try {
-            return ((PreparedStatement) getDelegate()).executeUpdate();
+            return getDelegatePreparedStatement().executeUpdate();
         } catch (final SQLException e) {
             handleException(e);
             return 0;
         }
     }
 
-    @Override
-    public void setNull(final int parameterIndex, final int sqlType) throws SQLException
-    { checkOpen(); try { ((PreparedStatement)getDelegate()).setNull(parameterIndex,sqlType); } catch (final SQLException e) { handleException(e); } }
+    private PreparedStatement getDelegatePreparedStatement() {
+        return (PreparedStatement) getDelegate();
+    }
 
     @Override
-    public void setBoolean(final int parameterIndex, final boolean x) throws SQLException
-    { checkOpen(); try { ((PreparedStatement)getDelegate()).setBoolean(parameterIndex,x); } catch (final SQLException e) { handleException(e); } }
+    public void setNull(final int parameterIndex, final int sqlType) throws SQLException {
+        checkOpen();
+        try {
+            getDelegatePreparedStatement().setNull(parameterIndex, sqlType);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setByte(final int parameterIndex, final byte x) throws SQLException
-    { checkOpen(); try { ((PreparedStatement)getDelegate()).setByte(parameterIndex,x); } catch (final SQLException e) { handleException(e); } }
+    public void setBoolean(final int parameterIndex, final boolean x) throws SQLException {
+        checkOpen();
+        try {
+            getDelegatePreparedStatement().setBoolean(parameterIndex, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setShort(final int parameterIndex, final short x) throws SQLException
-    { checkOpen(); try { ((PreparedStatement)getDelegate()).setShort(parameterIndex,x); } catch (final SQLException e) { handleException(e); } }
+    public void setByte(final int parameterIndex, final byte x) throws SQLException {
+        checkOpen();
+        try {
+            getDelegatePreparedStatement().setByte(parameterIndex, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setInt(final int parameterIndex, final int x) throws SQLException
-    { checkOpen(); try { ((PreparedStatement)getDelegate()).setInt(parameterIndex,x); } catch (final SQLException e) { handleException(e); } }
+    public void setShort(final int parameterIndex, final short x) throws SQLException {
+        checkOpen();
+        try {
+            getDelegatePreparedStatement().setShort(parameterIndex, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setLong(final int parameterIndex, final long x) throws SQLException
-    { checkOpen(); try { ((PreparedStatement)getDelegate()).setLong(parameterIndex,x); } catch (final SQLException e) { handleException(e); } }
+    public void setInt(final int parameterIndex, final int x) throws SQLException {
+        checkOpen();
+        try {
+            getDelegatePreparedStatement().setInt(parameterIndex, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setFloat(final int parameterIndex, final float x) throws SQLException
-    { checkOpen(); try { ((PreparedStatement)getDelegate()).setFloat(parameterIndex,x); } catch (final SQLException e) { handleException(e); } }
+    public void setLong(final int parameterIndex, final long x) throws SQLException {
+        checkOpen();
+        try {
+            getDelegatePreparedStatement().setLong(parameterIndex, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setDouble(final int parameterIndex, final double x) throws SQLException
-    { checkOpen(); try { ((PreparedStatement)getDelegate()).setDouble(parameterIndex,x); } catch (final SQLException e) { handleException(e); } }
+    public void setFloat(final int parameterIndex, final float x) throws SQLException {
+        checkOpen();
+        try {
+            getDelegatePreparedStatement().setFloat(parameterIndex, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setBigDecimal(final int parameterIndex, final BigDecimal x) throws SQLException
-    { checkOpen(); try { ((PreparedStatement)getDelegate()).setBigDecimal(parameterIndex,x); } catch (final SQLException e) { handleException(e); } }
+    public void setDouble(final int parameterIndex, final double x) throws SQLException {
+        checkOpen();
+        try {
+            getDelegatePreparedStatement().setDouble(parameterIndex, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setString(final int parameterIndex, final String x) throws SQLException
-    { checkOpen(); try { ((PreparedStatement)getDelegate()).setString(parameterIndex,x); } catch (final SQLException e) { handleException(e); } }
+    public void setBigDecimal(final int parameterIndex, final BigDecimal x) throws SQLException {
+        checkOpen();
+        try {
+            getDelegatePreparedStatement().setBigDecimal(parameterIndex, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setBytes(final int parameterIndex, final byte[] x) throws SQLException
-    { checkOpen(); try { ((PreparedStatement)getDelegate()).setBytes(parameterIndex,x); } catch (final SQLException e) { handleException(e); } }
+    public void setString(final int parameterIndex, final String x) throws SQLException {
+        checkOpen();
+        try {
+            getDelegatePreparedStatement().setString(parameterIndex, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setDate(final int parameterIndex, final Date x) throws SQLException
-    { checkOpen(); try { ((PreparedStatement)getDelegate()).setDate(parameterIndex,x); } catch (final SQLException e) { handleException(e); } }
+    public void setBytes(final int parameterIndex, final byte[] x) throws SQLException {
+        checkOpen();
+        try {
+            getDelegatePreparedStatement().setBytes(parameterIndex, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setTime(final int parameterIndex, final Time x) throws SQLException
-    { checkOpen(); try { ((PreparedStatement)getDelegate()).setTime(parameterIndex,x); } catch (final SQLException e) { handleException(e); } }
+    public void setDate(final int parameterIndex, final Date x) throws SQLException {
+        checkOpen();
+        try {
+            getDelegatePreparedStatement().setDate(parameterIndex, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setTimestamp(final int parameterIndex, final Timestamp x) throws SQLException
-    { checkOpen(); try { ((PreparedStatement)getDelegate()).setTimestamp(parameterIndex,x); } catch (final SQLException e) { handleException(e); } }
+    public void setTime(final int parameterIndex, final Time x) throws SQLException {
+        checkOpen();
+        try {
+            getDelegatePreparedStatement().setTime(parameterIndex, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setAsciiStream(final int parameterIndex, final InputStream x, final int length) throws SQLException
-    { checkOpen(); try { ((PreparedStatement)getDelegate()).setAsciiStream(parameterIndex,x,length); } catch (final SQLException e) { handleException(e); } }
+    public void setTimestamp(final int parameterIndex, final Timestamp x) throws SQLException {
+        checkOpen();
+        try {
+            getDelegatePreparedStatement().setTimestamp(parameterIndex, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
+
+    @Override
+    public void setAsciiStream(final int parameterIndex, final InputStream x, final int length) throws SQLException {
+        checkOpen();
+        try {
+            getDelegatePreparedStatement().setAsciiStream(parameterIndex, x, length);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     /** @deprecated */
     @Deprecated
     @Override
-    public void setUnicodeStream(final int parameterIndex, final InputStream x, final int length) throws SQLException
-    { checkOpen(); try { ((PreparedStatement)getDelegate()).setUnicodeStream(parameterIndex,x,length); } catch (final SQLException e) { handleException(e); } }
+    public void setUnicodeStream(final int parameterIndex, final InputStream x, final int length) throws SQLException {
+        checkOpen();
+        try {
+            getDelegatePreparedStatement().setUnicodeStream(parameterIndex, x, length);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setBinaryStream(final int parameterIndex, final InputStream x, final int length) throws SQLException
-    { checkOpen(); try { ((PreparedStatement)getDelegate()).setBinaryStream(parameterIndex,x,length); } catch (final SQLException e) { handleException(e); } }
+    public void setBinaryStream(final int parameterIndex, final InputStream x, final int length) throws SQLException {
+        checkOpen();
+        try {
+            getDelegatePreparedStatement().setBinaryStream(parameterIndex, x, length);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void clearParameters() throws SQLException
-    { checkOpen(); try { ((PreparedStatement)getDelegate()).clearParameters(); } catch (final SQLException e) { handleException(e); } }
+    public void clearParameters() throws SQLException {
+        checkOpen();
+        try {
+            getDelegatePreparedStatement().clearParameters();
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setObject(final int parameterIndex, final Object x, final int targetSqlType, final int scale) throws SQLException
-    { checkOpen(); try { ((PreparedStatement)getDelegate()).setObject(parameterIndex, x, targetSqlType, scale); } catch (final SQLException e) { handleException(e); } }
+    public void setObject(final int parameterIndex, final Object x, final int targetSqlType, final int scale)
+            throws SQLException {
+        checkOpen();
+        try {
+            getDelegatePreparedStatement().setObject(parameterIndex, x, targetSqlType, scale);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setObject(final int parameterIndex, final Object x, final int targetSqlType) throws SQLException
-    { checkOpen(); try { ((PreparedStatement)getDelegate()).setObject(parameterIndex, x, targetSqlType); } catch (final SQLException e) { handleException(e); } }
+    public void setObject(final int parameterIndex, final Object x, final int targetSqlType) throws SQLException {
+        checkOpen();
+        try {
+            getDelegatePreparedStatement().setObject(parameterIndex, x, targetSqlType);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setObject(final int parameterIndex, final Object x) throws SQLException
-    { checkOpen(); try { ((PreparedStatement)getDelegate()).setObject(parameterIndex, x); } catch (final SQLException e) { handleException(e); } }
+    public void setObject(final int parameterIndex, final Object x) throws SQLException {
+        checkOpen();
+        try {
+            getDelegatePreparedStatement().setObject(parameterIndex, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
     public boolean execute() throws SQLException {
@@ -194,7 +315,7 @@
             getConnectionInternal().setLastUsed();
         }
         try {
-            return ((PreparedStatement) getDelegate()).execute();
+            return getDelegatePreparedStatement().execute();
         } catch (final SQLException e) {
             handleException(e);
             return false;
@@ -202,54 +323,123 @@
     }
 
     @Override
-    public void addBatch() throws SQLException
-    { checkOpen(); try { ((PreparedStatement)getDelegate()).addBatch(); } catch (final SQLException e) { handleException(e); } }
+    public void addBatch() throws SQLException {
+        checkOpen();
+        try {
+            getDelegatePreparedStatement().addBatch();
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setCharacterStream(final int parameterIndex, final Reader reader, final int length) throws SQLException
-    { checkOpen(); try { ((PreparedStatement)getDelegate()).setCharacterStream(parameterIndex,reader,length); } catch (final SQLException e) { handleException(e); } }
+    public void setCharacterStream(final int parameterIndex, final Reader reader, final int length)
+            throws SQLException {
+        checkOpen();
+        try {
+            getDelegatePreparedStatement().setCharacterStream(parameterIndex, reader, length);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setRef(final int i, final Ref x) throws SQLException
-    { checkOpen(); try { ((PreparedStatement)getDelegate()).setRef(i,x); } catch (final SQLException e) { handleException(e); } }
+    public void setRef(final int i, final Ref x) throws SQLException {
+        checkOpen();
+        try {
+            getDelegatePreparedStatement().setRef(i, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setBlob(final int i, final Blob x) throws SQLException
-    { checkOpen(); try { ((PreparedStatement)getDelegate()).setBlob(i,x); } catch (final SQLException e) { handleException(e); } }
+    public void setBlob(final int i, final Blob x) throws SQLException {
+        checkOpen();
+        try {
+            getDelegatePreparedStatement().setBlob(i, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setClob(final int i, final Clob x) throws SQLException
-    { checkOpen(); try { ((PreparedStatement)getDelegate()).setClob(i,x); } catch (final SQLException e) { handleException(e); } }
+    public void setClob(final int i, final Clob x) throws SQLException {
+        checkOpen();
+        try {
+            getDelegatePreparedStatement().setClob(i, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setArray(final int i, final Array x) throws SQLException
-    { checkOpen(); try { ((PreparedStatement)getDelegate()).setArray(i,x); } catch (final SQLException e) { handleException(e); } }
+    public void setArray(final int i, final Array x) throws SQLException {
+        checkOpen();
+        try {
+            getDelegatePreparedStatement().setArray(i, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public ResultSetMetaData getMetaData() throws SQLException
-    { checkOpen(); try { return ((PreparedStatement)getDelegate()).getMetaData(); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } }
+    public ResultSetMetaData getMetaData() throws SQLException {
+        checkOpen();
+        try {
+            return getDelegatePreparedStatement().getMetaData();
+        } catch (final SQLException e) {
+            handleException(e);
+            throw new AssertionError();
+        }
+    }
 
     @Override
-    public void setDate(final int parameterIndex, final Date x, final Calendar cal) throws SQLException
-    { checkOpen(); try { ((PreparedStatement)getDelegate()).setDate(parameterIndex,x,cal); } catch (final SQLException e) { handleException(e); } }
+    public void setDate(final int parameterIndex, final Date x, final Calendar cal) throws SQLException {
+        checkOpen();
+        try {
+            getDelegatePreparedStatement().setDate(parameterIndex, x, cal);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setTime(final int parameterIndex, final Time x, final Calendar cal) throws SQLException
-    { checkOpen(); try { ((PreparedStatement)getDelegate()).setTime(parameterIndex,x,cal); } catch (final SQLException e) { handleException(e); } }
+    public void setTime(final int parameterIndex, final Time x, final Calendar cal) throws SQLException {
+        checkOpen();
+        try {
+            getDelegatePreparedStatement().setTime(parameterIndex, x, cal);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setTimestamp(final int parameterIndex, final Timestamp x, final Calendar cal) throws SQLException
-    { checkOpen(); try { ((PreparedStatement)getDelegate()).setTimestamp(parameterIndex,x,cal); } catch (final SQLException e) { handleException(e); } }
+    public void setTimestamp(final int parameterIndex, final Timestamp x, final Calendar cal) throws SQLException {
+        checkOpen();
+        try {
+            getDelegatePreparedStatement().setTimestamp(parameterIndex, x, cal);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setNull(final int paramIndex, final int sqlType, final String typeName) throws SQLException
-    { checkOpen(); try { ((PreparedStatement)getDelegate()).setNull(paramIndex,sqlType,typeName); } catch (final SQLException e) { handleException(e); } }
+    public void setNull(final int paramIndex, final int sqlType, final String typeName) throws SQLException {
+        checkOpen();
+        try {
+            getDelegatePreparedStatement().setNull(paramIndex, sqlType, typeName);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     /**
      * Returns a String representation of this object.
      *
      * @return String
      */
+    @SuppressWarnings("resource")
     @Override
     public String toString() {
         final Statement statement = getDelegate();
@@ -257,21 +447,32 @@
     }
 
     @Override
-    public void setURL(final int parameterIndex, final java.net.URL x) throws SQLException
-    { checkOpen(); try { ((PreparedStatement)getDelegate()).setURL(parameterIndex, x); } catch (final SQLException e) { handleException(e); } }
+    public void setURL(final int parameterIndex, final java.net.URL x) throws SQLException {
+        checkOpen();
+        try {
+            getDelegatePreparedStatement().setURL(parameterIndex, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public java.sql.ParameterMetaData getParameterMetaData() throws SQLException
-    { checkOpen(); try { return ((PreparedStatement)getDelegate()).getParameterMetaData(); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } }
-
+    public java.sql.ParameterMetaData getParameterMetaData() throws SQLException {
+        checkOpen();
+        try {
+            return getDelegatePreparedStatement().getParameterMetaData();
+        } catch (final SQLException e) {
+            handleException(e);
+            throw new AssertionError();
+        }
+    }
 
     @Override
     public void setRowId(final int parameterIndex, final RowId value) throws SQLException {
         checkOpen();
         try {
-            ((PreparedStatement)getDelegate()).setRowId(parameterIndex, value);
-        }
-        catch (final SQLException e) {
+            getDelegatePreparedStatement().setRowId(parameterIndex, value);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -280,20 +481,19 @@
     public void setNString(final int parameterIndex, final String value) throws SQLException {
         checkOpen();
         try {
-            ((PreparedStatement)getDelegate()).setNString(parameterIndex, value);
-        }
-        catch (final SQLException e) {
+            getDelegatePreparedStatement().setNString(parameterIndex, value);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
 
     @Override
-    public void setNCharacterStream(final int parameterIndex, final Reader value, final long length) throws SQLException {
+    public void setNCharacterStream(final int parameterIndex, final Reader value, final long length)
+            throws SQLException {
         checkOpen();
         try {
-            ((PreparedStatement)getDelegate()).setNCharacterStream(parameterIndex, value, length);
-        }
-        catch (final SQLException e) {
+            getDelegatePreparedStatement().setNCharacterStream(parameterIndex, value, length);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -302,9 +502,8 @@
     public void setNClob(final int parameterIndex, final NClob value) throws SQLException {
         checkOpen();
         try {
-            ((PreparedStatement)getDelegate()).setNClob(parameterIndex, value);
-        }
-        catch (final SQLException e) {
+            getDelegatePreparedStatement().setNClob(parameterIndex, value);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -313,20 +512,19 @@
     public void setClob(final int parameterIndex, final Reader reader, final long length) throws SQLException {
         checkOpen();
         try {
-            ((PreparedStatement)getDelegate()).setClob(parameterIndex, reader, length);
-        }
-        catch (final SQLException e) {
+            getDelegatePreparedStatement().setClob(parameterIndex, reader, length);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
 
     @Override
-    public void setBlob(final int parameterIndex, final InputStream inputStream, final long length) throws SQLException {
+    public void setBlob(final int parameterIndex, final InputStream inputStream, final long length)
+            throws SQLException {
         checkOpen();
         try {
-            ((PreparedStatement)getDelegate()).setBlob(parameterIndex, inputStream, length);
-        }
-        catch (final SQLException e) {
+            getDelegatePreparedStatement().setBlob(parameterIndex, inputStream, length);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -335,9 +533,8 @@
     public void setNClob(final int parameterIndex, final Reader reader, final long length) throws SQLException {
         checkOpen();
         try {
-            ((PreparedStatement)getDelegate()).setNClob(parameterIndex, reader, length);
-        }
-        catch (final SQLException e) {
+            getDelegatePreparedStatement().setNClob(parameterIndex, reader, length);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -346,42 +543,41 @@
     public void setSQLXML(final int parameterIndex, final SQLXML value) throws SQLException {
         checkOpen();
         try {
-            ((PreparedStatement)getDelegate()).setSQLXML(parameterIndex, value);
-        }
-        catch (final SQLException e) {
+            getDelegatePreparedStatement().setSQLXML(parameterIndex, value);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
 
     @Override
-    public void setAsciiStream(final int parameterIndex, final InputStream inputStream, final long length) throws SQLException {
+    public void setAsciiStream(final int parameterIndex, final InputStream inputStream, final long length)
+            throws SQLException {
         checkOpen();
         try {
-            ((PreparedStatement)getDelegate()).setAsciiStream(parameterIndex, inputStream, length);
-        }
-        catch (final SQLException e) {
+            getDelegatePreparedStatement().setAsciiStream(parameterIndex, inputStream, length);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
 
     @Override
-    public void setBinaryStream(final int parameterIndex, final InputStream inputStream, final long length) throws SQLException {
+    public void setBinaryStream(final int parameterIndex, final InputStream inputStream, final long length)
+            throws SQLException {
         checkOpen();
         try {
-            ((PreparedStatement)getDelegate()).setBinaryStream(parameterIndex, inputStream, length);
-        }
-        catch (final SQLException e) {
+            getDelegatePreparedStatement().setBinaryStream(parameterIndex, inputStream, length);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
 
     @Override
-    public void setCharacterStream(final int parameterIndex, final Reader reader, final long length) throws SQLException {
+    public void setCharacterStream(final int parameterIndex, final Reader reader, final long length)
+            throws SQLException {
         checkOpen();
         try {
-            ((PreparedStatement)getDelegate()).setCharacterStream(parameterIndex, reader, length);
-        }
-        catch (final SQLException e) {
+            getDelegatePreparedStatement().setCharacterStream(parameterIndex, reader, length);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -390,9 +586,8 @@
     public void setAsciiStream(final int parameterIndex, final InputStream inputStream) throws SQLException {
         checkOpen();
         try {
-            ((PreparedStatement)getDelegate()).setAsciiStream(parameterIndex, inputStream);
-        }
-        catch (final SQLException e) {
+            getDelegatePreparedStatement().setAsciiStream(parameterIndex, inputStream);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -401,9 +596,8 @@
     public void setBinaryStream(final int parameterIndex, final InputStream inputStream) throws SQLException {
         checkOpen();
         try {
-            ((PreparedStatement)getDelegate()).setBinaryStream(parameterIndex, inputStream);
-        }
-        catch (final SQLException e) {
+            getDelegatePreparedStatement().setBinaryStream(parameterIndex, inputStream);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -412,9 +606,8 @@
     public void setCharacterStream(final int parameterIndex, final Reader reader) throws SQLException {
         checkOpen();
         try {
-            ((PreparedStatement)getDelegate()).setCharacterStream(parameterIndex, reader);
-        }
-        catch (final SQLException e) {
+            getDelegatePreparedStatement().setCharacterStream(parameterIndex, reader);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -423,9 +616,8 @@
     public void setNCharacterStream(final int parameterIndex, final Reader reader) throws SQLException {
         checkOpen();
         try {
-            ((PreparedStatement)getDelegate()).setNCharacterStream(parameterIndex, reader);
-        }
-        catch (final SQLException e) {
+            getDelegatePreparedStatement().setNCharacterStream(parameterIndex, reader);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -434,9 +626,8 @@
     public void setClob(final int parameterIndex, final Reader reader) throws SQLException {
         checkOpen();
         try {
-            ((PreparedStatement)getDelegate()).setClob(parameterIndex, reader);
-        }
-        catch (final SQLException e) {
+            getDelegatePreparedStatement().setClob(parameterIndex, reader);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -445,9 +636,8 @@
     public void setBlob(final int parameterIndex, final InputStream inputStream) throws SQLException {
         checkOpen();
         try {
-            ((PreparedStatement)getDelegate()).setBlob(parameterIndex, inputStream);
-        }
-        catch (final SQLException e) {
+            getDelegatePreparedStatement().setBlob(parameterIndex, inputStream);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -456,9 +646,8 @@
     public void setNClob(final int parameterIndex, final Reader reader) throws SQLException {
         checkOpen();
         try {
-            ((PreparedStatement)getDelegate()).setNClob(parameterIndex, reader);
-        }
-        catch (final SQLException e) {
+            getDelegatePreparedStatement().setNClob(parameterIndex, reader);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingResultSet.java b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingResultSet.java
index 20250cd..3cff4e4 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingResultSet.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingResultSet.java
@@ -42,103 +42,123 @@
 /**
  * A base delegating implementation of {@link ResultSet}.
  * <p>
- * All of the methods from the {@link ResultSet} interface
- * simply call the corresponding method on the "delegate"
+ * All of the methods from the {@link ResultSet} interface simply call the corresponding method on the "delegate"
  * provided in my constructor.
+ * </p>
  * <p>
- * Extends AbandonedTrace to implement result set tracking and
- * logging of code which created the ResultSet. Tracking the
- * ResultSet ensures that the Statement which created it can
- * close any open ResultSet's on Statement close.
+ * Extends AbandonedTrace to implement result set tracking and logging of code which created the ResultSet. Tracking the
+ * ResultSet ensures that the Statement which created it can close any open ResultSet's on Statement close.
+ * </p>
  *
- * @author Glenn L. Nielsen
- * @author James House
- * @author Dirk Verbeeck
  * @since 2.0
  */
 public final class DelegatingResultSet extends AbandonedTrace implements ResultSet {
 
     /** My delegate. **/
-    private final ResultSet _res;
+    private final ResultSet resultSet;
 
     /** The Statement that created me, if any. **/
-    private Statement _stmt;
+    private Statement statement;
 
     /** The Connection that created me, if any. **/
-    private Connection _conn;
+    private Connection connection;
 
     /**
-     * Create a wrapper for the ResultSet which traces this
-     * ResultSet to the Statement which created it and the
-     * code which created it.
+     * Creates a wrapper for the ResultSet which traces this ResultSet to the Statement which created it and the code
+     * which created it.
      * <p>
-     * Private to ensure all construction is
-     * {@link #wrapResultSet(Statement, ResultSet)}
+     * Private to ensure all construction is {@link #wrapResultSet(Statement, ResultSet)}
+     * </p>
      *
-     * @param stmt Statement which created this ResultSet
-     * @param res ResultSet to wrap
+     * @param statement
+     *            The Statement which created the ResultSet.
+     * @param resultSet
+     *            The ResultSet to wrap.
      */
-    private DelegatingResultSet(final Statement stmt, final ResultSet res) {
-        super((AbandonedTrace)stmt);
-        this._stmt = stmt;
-        this._res = res;
+    private DelegatingResultSet(final Statement statement, final ResultSet resultSet) {
+        super((AbandonedTrace) statement);
+        this.statement = statement;
+        this.resultSet = resultSet;
     }
 
     /**
-     * Create a wrapper for the ResultSet which traces this
-     * ResultSet to the Connection which created it (via, for
+     * Creates a wrapper for the ResultSet which traces this ResultSet to the Connection which created it (via, for
      * example DatabaseMetadata, and the code which created it.
      * <p>
-     * Private to ensure all construction is
-     * {@link #wrapResultSet(Connection, ResultSet)}
+     * Private to ensure all construction is {@link #wrapResultSet(Connection, ResultSet)}
+     * </p>
      *
-     * @param conn Connection which created this ResultSet
-     * @param res ResultSet to wrap
+     * @param conn
+     *            Connection which created this ResultSet
+     * @param res
+     *            ResultSet to wrap
      */
     private DelegatingResultSet(final Connection conn, final ResultSet res) {
-        super((AbandonedTrace)conn);
-        this._conn = conn;
-        this._res = res;
-    }
-
-    public static ResultSet wrapResultSet(final Statement stmt, final ResultSet rset) {
-        if(null == rset) {
-            return null;
-        }
-        return new DelegatingResultSet(stmt,rset);
-    }
-
-    public static ResultSet wrapResultSet(final Connection conn, final ResultSet rset) {
-        if(null == rset) {
-            return null;
-        }
-        return new DelegatingResultSet(conn,rset);
-    }
-
-    public ResultSet getDelegate() {
-        return _res;
+        super((AbandonedTrace) conn);
+        this.connection = conn;
+        this.resultSet = res;
     }
 
     /**
-     * If my underlying {@link ResultSet} is not a
-     * {@code DelegatingResultSet}, returns it,
-     * otherwise recursively invokes this method on
-     * my delegate.
+     * Wraps the given result set in a delegate.
+     *
+     * @param statement
+     *            The Statement which created the ResultSet.
+     * @param resultSet
+     *            The ResultSet to wrap.
+     * @return a new delegate.
+     */
+    public static ResultSet wrapResultSet(final Statement statement, final ResultSet resultSet) {
+        if (null == resultSet) {
+            return null;
+        }
+        return new DelegatingResultSet(statement, resultSet);
+    }
+
+    /**
+     * Wraps the given result set in a delegate.
+     *
+     * @param connection
+     *            The Connection which created the ResultSet.
+     * @param resultSet
+     *            The ResultSet to wrap.
+     * @return a new delegate.
+     */
+    public static ResultSet wrapResultSet(final Connection connection, final ResultSet resultSet) {
+        if (null == resultSet) {
+            return null;
+        }
+        return new DelegatingResultSet(connection, resultSet);
+    }
+
+    /**
+     * Gets my delegate.
+     *
+     * @return my delegate.
+     */
+    public ResultSet getDelegate() {
+        return resultSet;
+    }
+
+    /**
+     * If my underlying {@link ResultSet} is not a {@code DelegatingResultSet}, returns it, otherwise recursively
+     * invokes this method on my delegate.
      * <p>
-     * Hence this method will return the first
-     * delegate that is not a {@code DelegatingResultSet},
-     * or {@code null} when no non-{@code DelegatingResultSet}
-     * delegate can be found by traversing this chain.
+     * Hence this method will return the first delegate that is not a {@code DelegatingResultSet}, or {@code null} when
+     * no non-{@code DelegatingResultSet} delegate can be found by traversing this chain.
+     * </p>
      * <p>
-     * This method is useful when you may have nested
-     * {@code DelegatingResultSet}s, and you want to make
-     * sure to obtain a "genuine" {@link ResultSet}.
+     * This method is useful when you may have nested {@code DelegatingResultSet}s, and you want to make sure to obtain
+     * a "genuine" {@link ResultSet}.
+     * </p>
+     *
+     * @return the innermost delegate.
      */
     public ResultSet getInnermostDelegate() {
-        ResultSet r = _res;
-        while(r != null && r instanceof DelegatingResultSet) {
-            r = ((DelegatingResultSet)r).getDelegate();
-            if(this == r) {
+        ResultSet r = resultSet;
+        while (r != null && r instanceof DelegatingResultSet) {
+            r = ((DelegatingResultSet) r).getDelegate();
+            if (this == r) {
                 return null;
             }
         }
@@ -147,610 +167,1369 @@
 
     @Override
     public Statement getStatement() throws SQLException {
-        return _stmt;
+        return statement;
     }
 
     /**
-     * Wrapper for close of ResultSet which removes this
-     * result set from being traced then calls close on
-     * the original ResultSet.
+     * Wrapper for close of ResultSet which removes this result set from being traced then calls close on the original
+     * ResultSet.
      */
     @Override
     public void close() throws SQLException {
         try {
-            if(_stmt != null) {
-                ((AbandonedTrace)_stmt).removeTrace(this);
-                _stmt = null;
+            if (statement != null) {
+                ((AbandonedTrace) statement).removeTrace(this);
+                statement = null;
             }
-            if(_conn != null) {
-                ((AbandonedTrace)_conn).removeTrace(this);
-                _conn = null;
+            if (connection != null) {
+                ((AbandonedTrace) connection).removeTrace(this);
+                connection = null;
             }
-            _res.close();
-        }
-        catch (final SQLException e) {
+            resultSet.close();
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
 
     protected void handleException(final SQLException e) throws SQLException {
-        if (_stmt != null && _stmt instanceof DelegatingStatement) {
-            ((DelegatingStatement)_stmt).handleException(e);
-        }
-        else if (_conn != null && _conn instanceof DelegatingConnection) {
-            ((DelegatingConnection<?>)_conn).handleException(e);
-        }
-        else {
+        if (statement != null && statement instanceof DelegatingStatement) {
+            ((DelegatingStatement) statement).handleException(e);
+        } else if (connection != null && connection instanceof DelegatingConnection) {
+            ((DelegatingConnection<?>) connection).handleException(e);
+        } else {
             throw e;
         }
     }
 
     @Override
-    public boolean next() throws SQLException
-    { try { return _res.next(); } catch (final SQLException e) { handleException(e); return false; } }
+    public boolean next() throws SQLException {
+        try {
+            return resultSet.next();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
+    }
 
     @Override
-    public boolean wasNull() throws SQLException
-    { try { return _res.wasNull(); } catch (final SQLException e) { handleException(e); return false; } }
+    public boolean wasNull() throws SQLException {
+        try {
+            return resultSet.wasNull();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
+    }
 
     @Override
-    public String getString(final int columnIndex) throws SQLException
-    { try { return _res.getString(columnIndex); } catch (final SQLException e) { handleException(e); return null; } }
+    public String getString(final int columnIndex) throws SQLException {
+        try {
+            return resultSet.getString(columnIndex);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public boolean getBoolean(final int columnIndex) throws SQLException
-    { try { return _res.getBoolean(columnIndex); } catch (final SQLException e) { handleException(e); return false; } }
+    public boolean getBoolean(final int columnIndex) throws SQLException {
+        try {
+            return resultSet.getBoolean(columnIndex);
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
+    }
 
     @Override
-    public byte getByte(final int columnIndex) throws SQLException
-    { try { return _res.getByte(columnIndex); } catch (final SQLException e) { handleException(e); return 0; } }
+    public byte getByte(final int columnIndex) throws SQLException {
+        try {
+            return resultSet.getByte(columnIndex);
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
     @Override
-    public short getShort(final int columnIndex) throws SQLException
-    { try { return _res.getShort(columnIndex); } catch (final SQLException e) { handleException(e); return 0; } }
+    public short getShort(final int columnIndex) throws SQLException {
+        try {
+            return resultSet.getShort(columnIndex);
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
     @Override
-    public int getInt(final int columnIndex) throws SQLException
-    { try { return _res.getInt(columnIndex); } catch (final SQLException e) { handleException(e); return 0; } }
+    public int getInt(final int columnIndex) throws SQLException {
+        try {
+            return resultSet.getInt(columnIndex);
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
     @Override
-    public long getLong(final int columnIndex) throws SQLException
-    { try { return _res.getLong(columnIndex); } catch (final SQLException e) { handleException(e); return 0; } }
+    public long getLong(final int columnIndex) throws SQLException {
+        try {
+            return resultSet.getLong(columnIndex);
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
     @Override
-    public float getFloat(final int columnIndex) throws SQLException
-    { try { return _res.getFloat(columnIndex); } catch (final SQLException e) { handleException(e); return 0; } }
+    public float getFloat(final int columnIndex) throws SQLException {
+        try {
+            return resultSet.getFloat(columnIndex);
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
     @Override
-    public double getDouble(final int columnIndex) throws SQLException
-    { try { return _res.getDouble(columnIndex); } catch (final SQLException e) { handleException(e); return 0; } }
+    public double getDouble(final int columnIndex) throws SQLException {
+        try {
+            return resultSet.getDouble(columnIndex);
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
     /** @deprecated */
     @Deprecated
     @Override
-    public BigDecimal getBigDecimal(final int columnIndex, final int scale) throws SQLException
-    { try { return _res.getBigDecimal(columnIndex); } catch (final SQLException e) { handleException(e); return null; } }
+    public BigDecimal getBigDecimal(final int columnIndex, final int scale) throws SQLException {
+        try {
+            return resultSet.getBigDecimal(columnIndex);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public byte[] getBytes(final int columnIndex) throws SQLException
-    { try { return _res.getBytes(columnIndex); } catch (final SQLException e) { handleException(e); return null; } }
+    public byte[] getBytes(final int columnIndex) throws SQLException {
+        try {
+            return resultSet.getBytes(columnIndex);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Date getDate(final int columnIndex) throws SQLException
-    { try { return _res.getDate(columnIndex); } catch (final SQLException e) { handleException(e); return null; } }
+    public Date getDate(final int columnIndex) throws SQLException {
+        try {
+            return resultSet.getDate(columnIndex);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Time getTime(final int columnIndex) throws SQLException
-    { try { return _res.getTime(columnIndex); } catch (final SQLException e) { handleException(e); return null; } }
+    public Time getTime(final int columnIndex) throws SQLException {
+        try {
+            return resultSet.getTime(columnIndex);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Timestamp getTimestamp(final int columnIndex) throws SQLException
-    { try { return _res.getTimestamp(columnIndex); } catch (final SQLException e) { handleException(e); return null; } }
+    public Timestamp getTimestamp(final int columnIndex) throws SQLException {
+        try {
+            return resultSet.getTimestamp(columnIndex);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public InputStream getAsciiStream(final int columnIndex) throws SQLException
-    { try { return _res.getAsciiStream(columnIndex); } catch (final SQLException e) { handleException(e); return null; } }
+    public InputStream getAsciiStream(final int columnIndex) throws SQLException {
+        try {
+            return resultSet.getAsciiStream(columnIndex);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     /** @deprecated */
     @Deprecated
     @Override
-    public InputStream getUnicodeStream(final int columnIndex) throws SQLException
-    { try { return _res.getUnicodeStream(columnIndex); } catch (final SQLException e) { handleException(e); return null; } }
+    public InputStream getUnicodeStream(final int columnIndex) throws SQLException {
+        try {
+            return resultSet.getUnicodeStream(columnIndex);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public InputStream getBinaryStream(final int columnIndex) throws SQLException
-    { try { return _res.getBinaryStream(columnIndex); } catch (final SQLException e) { handleException(e); return null; } }
+    public InputStream getBinaryStream(final int columnIndex) throws SQLException {
+        try {
+            return resultSet.getBinaryStream(columnIndex);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public String getString(final String columnName) throws SQLException
-    { try { return _res.getString(columnName); } catch (final SQLException e) { handleException(e); return null; } }
+    public String getString(final String columnName) throws SQLException {
+        try {
+            return resultSet.getString(columnName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public boolean getBoolean(final String columnName) throws SQLException
-    { try { return _res.getBoolean(columnName); } catch (final SQLException e) { handleException(e); return false; } }
+    public boolean getBoolean(final String columnName) throws SQLException {
+        try {
+            return resultSet.getBoolean(columnName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
+    }
 
     @Override
-    public byte getByte(final String columnName) throws SQLException
-    { try { return _res.getByte(columnName); } catch (final SQLException e) { handleException(e); return 0; } }
+    public byte getByte(final String columnName) throws SQLException {
+        try {
+            return resultSet.getByte(columnName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
     @Override
-    public short getShort(final String columnName) throws SQLException
-    { try { return _res.getShort(columnName); } catch (final SQLException e) { handleException(e); return 0; } }
+    public short getShort(final String columnName) throws SQLException {
+        try {
+            return resultSet.getShort(columnName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
     @Override
-    public int getInt(final String columnName) throws SQLException
-    { try { return _res.getInt(columnName); } catch (final SQLException e) { handleException(e); return 0; } }
+    public int getInt(final String columnName) throws SQLException {
+        try {
+            return resultSet.getInt(columnName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
     @Override
-    public long getLong(final String columnName) throws SQLException
-    { try { return _res.getLong(columnName); } catch (final SQLException e) { handleException(e); return 0; } }
+    public long getLong(final String columnName) throws SQLException {
+        try {
+            return resultSet.getLong(columnName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
     @Override
-    public float getFloat(final String columnName) throws SQLException
-    { try { return _res.getFloat(columnName); } catch (final SQLException e) { handleException(e); return 0; } }
+    public float getFloat(final String columnName) throws SQLException {
+        try {
+            return resultSet.getFloat(columnName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
     @Override
-    public double getDouble(final String columnName) throws SQLException
-    { try { return _res.getDouble(columnName); } catch (final SQLException e) { handleException(e); return 0; } }
+    public double getDouble(final String columnName) throws SQLException {
+        try {
+            return resultSet.getDouble(columnName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
     /** @deprecated */
     @Deprecated
     @Override
-    public BigDecimal getBigDecimal(final String columnName, final int scale) throws SQLException
-    { try { return _res.getBigDecimal(columnName); } catch (final SQLException e) { handleException(e); return null; } }
+    public BigDecimal getBigDecimal(final String columnName, final int scale) throws SQLException {
+        try {
+            return resultSet.getBigDecimal(columnName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public byte[] getBytes(final String columnName) throws SQLException
-    { try { return _res.getBytes(columnName); } catch (final SQLException e) { handleException(e); return null; } }
+    public byte[] getBytes(final String columnName) throws SQLException {
+        try {
+            return resultSet.getBytes(columnName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Date getDate(final String columnName) throws SQLException
-    { try { return _res.getDate(columnName); } catch (final SQLException e) { handleException(e); return null; } }
+    public Date getDate(final String columnName) throws SQLException {
+        try {
+            return resultSet.getDate(columnName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Time getTime(final String columnName) throws SQLException
-    { try { return _res.getTime(columnName); } catch (final SQLException e) { handleException(e); return null; } }
+    public Time getTime(final String columnName) throws SQLException {
+        try {
+            return resultSet.getTime(columnName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Timestamp getTimestamp(final String columnName) throws SQLException
-    { try { return _res.getTimestamp(columnName); } catch (final SQLException e) { handleException(e); return null; } }
+    public Timestamp getTimestamp(final String columnName) throws SQLException {
+        try {
+            return resultSet.getTimestamp(columnName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public InputStream getAsciiStream(final String columnName) throws SQLException
-    { try { return _res.getAsciiStream(columnName); } catch (final SQLException e) { handleException(e); return null; } }
+    public InputStream getAsciiStream(final String columnName) throws SQLException {
+        try {
+            return resultSet.getAsciiStream(columnName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     /** @deprecated */
     @Deprecated
     @Override
-    public InputStream getUnicodeStream(final String columnName) throws SQLException
-    { try { return _res.getUnicodeStream(columnName); } catch (final SQLException e) { handleException(e); return null; } }
+    public InputStream getUnicodeStream(final String columnName) throws SQLException {
+        try {
+            return resultSet.getUnicodeStream(columnName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public InputStream getBinaryStream(final String columnName) throws SQLException
-    { try { return _res.getBinaryStream(columnName); } catch (final SQLException e) { handleException(e); return null; } }
+    public InputStream getBinaryStream(final String columnName) throws SQLException {
+        try {
+            return resultSet.getBinaryStream(columnName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public SQLWarning getWarnings() throws SQLException
-    { try { return _res.getWarnings(); } catch (final SQLException e) { handleException(e); return null; } }
+    public SQLWarning getWarnings() throws SQLException {
+        try {
+            return resultSet.getWarnings();
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public void clearWarnings() throws SQLException
-    { try { _res.clearWarnings(); } catch (final SQLException e) { handleException(e); } }
+    public void clearWarnings() throws SQLException {
+        try {
+            resultSet.clearWarnings();
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public String getCursorName() throws SQLException
-    { try { return _res.getCursorName(); } catch (final SQLException e) { handleException(e); return null; } }
+    public String getCursorName() throws SQLException {
+        try {
+            return resultSet.getCursorName();
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public ResultSetMetaData getMetaData() throws SQLException
-    { try { return _res.getMetaData(); } catch (final SQLException e) { handleException(e); return null; } }
+    public ResultSetMetaData getMetaData() throws SQLException {
+        try {
+            return resultSet.getMetaData();
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Object getObject(final int columnIndex) throws SQLException
-    { try { return _res.getObject(columnIndex); } catch (final SQLException e) { handleException(e); return null; } }
+    public Object getObject(final int columnIndex) throws SQLException {
+        try {
+            return resultSet.getObject(columnIndex);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Object getObject(final String columnName) throws SQLException
-    { try { return _res.getObject(columnName); } catch (final SQLException e) { handleException(e); return null; } }
+    public Object getObject(final String columnName) throws SQLException {
+        try {
+            return resultSet.getObject(columnName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public int findColumn(final String columnName) throws SQLException
-    { try { return _res.findColumn(columnName); } catch (final SQLException e) { handleException(e); return 0; } }
+    public int findColumn(final String columnName) throws SQLException {
+        try {
+            return resultSet.findColumn(columnName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
     @Override
-    public Reader getCharacterStream(final int columnIndex) throws SQLException
-    { try { return _res.getCharacterStream(columnIndex); } catch (final SQLException e) { handleException(e); return null; } }
+    public Reader getCharacterStream(final int columnIndex) throws SQLException {
+        try {
+            return resultSet.getCharacterStream(columnIndex);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Reader getCharacterStream(final String columnName) throws SQLException
-    { try { return _res.getCharacterStream(columnName); } catch (final SQLException e) { handleException(e); return null; } }
+    public Reader getCharacterStream(final String columnName) throws SQLException {
+        try {
+            return resultSet.getCharacterStream(columnName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public BigDecimal getBigDecimal(final int columnIndex) throws SQLException
-    { try { return _res.getBigDecimal(columnIndex); } catch (final SQLException e) { handleException(e); return null; } }
+    public BigDecimal getBigDecimal(final int columnIndex) throws SQLException {
+        try {
+            return resultSet.getBigDecimal(columnIndex);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public BigDecimal getBigDecimal(final String columnName) throws SQLException
-    { try { return _res.getBigDecimal(columnName); } catch (final SQLException e) { handleException(e); return null; } }
+    public BigDecimal getBigDecimal(final String columnName) throws SQLException {
+        try {
+            return resultSet.getBigDecimal(columnName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public boolean isBeforeFirst() throws SQLException
-    { try { return _res.isBeforeFirst(); } catch (final SQLException e) { handleException(e); return false; } }
+    public boolean isBeforeFirst() throws SQLException {
+        try {
+            return resultSet.isBeforeFirst();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
+    }
 
     @Override
-    public boolean isAfterLast() throws SQLException
-    { try { return _res.isAfterLast(); } catch (final SQLException e) { handleException(e); return false; } }
+    public boolean isAfterLast() throws SQLException {
+        try {
+            return resultSet.isAfterLast();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
+    }
 
     @Override
-    public boolean isFirst() throws SQLException
-    { try { return _res.isFirst(); } catch (final SQLException e) { handleException(e); return false; } }
+    public boolean isFirst() throws SQLException {
+        try {
+            return resultSet.isFirst();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
+    }
 
     @Override
-    public boolean isLast() throws SQLException
-    { try { return _res.isLast(); } catch (final SQLException e) { handleException(e); return false; } }
+    public boolean isLast() throws SQLException {
+        try {
+            return resultSet.isLast();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
+    }
 
     @Override
-    public void beforeFirst() throws SQLException
-    { try { _res.beforeFirst(); } catch (final SQLException e) { handleException(e); } }
+    public void beforeFirst() throws SQLException {
+        try {
+            resultSet.beforeFirst();
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void afterLast() throws SQLException
-    { try { _res.afterLast(); } catch (final SQLException e) { handleException(e); } }
+    public void afterLast() throws SQLException {
+        try {
+            resultSet.afterLast();
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public boolean first() throws SQLException
-    { try { return _res.first(); } catch (final SQLException e) { handleException(e); return false; } }
+    public boolean first() throws SQLException {
+        try {
+            return resultSet.first();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
+    }
 
     @Override
-    public boolean last() throws SQLException
-    { try { return _res.last(); } catch (final SQLException e) { handleException(e); return false; } }
+    public boolean last() throws SQLException {
+        try {
+            return resultSet.last();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
+    }
 
     @Override
-    public int getRow() throws SQLException
-    { try { return _res.getRow(); } catch (final SQLException e) { handleException(e); return 0; } }
+    public int getRow() throws SQLException {
+        try {
+            return resultSet.getRow();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
     @Override
-    public boolean absolute(final int row) throws SQLException
-    { try { return _res.absolute(row); } catch (final SQLException e) { handleException(e); return false; } }
+    public boolean absolute(final int row) throws SQLException {
+        try {
+            return resultSet.absolute(row);
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
+    }
 
     @Override
-    public boolean relative(final int rows) throws SQLException
-    { try { return _res.relative(rows); } catch (final SQLException e) { handleException(e); return false; } }
+    public boolean relative(final int rows) throws SQLException {
+        try {
+            return resultSet.relative(rows);
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
+    }
 
     @Override
-    public boolean previous() throws SQLException
-    { try { return _res.previous(); } catch (final SQLException e) { handleException(e); return false; } }
+    public boolean previous() throws SQLException {
+        try {
+            return resultSet.previous();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
+    }
 
     @Override
-    public void setFetchDirection(final int direction) throws SQLException
-    { try { _res.setFetchDirection(direction); } catch (final SQLException e) { handleException(e); } }
+    public void setFetchDirection(final int direction) throws SQLException {
+        try {
+            resultSet.setFetchDirection(direction);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public int getFetchDirection() throws SQLException
-    { try { return _res.getFetchDirection(); } catch (final SQLException e) { handleException(e); return 0; } }
+    public int getFetchDirection() throws SQLException {
+        try {
+            return resultSet.getFetchDirection();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
     @Override
-    public void setFetchSize(final int rows) throws SQLException
-    { try { _res.setFetchSize(rows); } catch (final SQLException e) { handleException(e); } }
+    public void setFetchSize(final int rows) throws SQLException {
+        try {
+            resultSet.setFetchSize(rows);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public int getFetchSize() throws SQLException
-    { try { return _res.getFetchSize(); } catch (final SQLException e) { handleException(e); return 0; } }
+    public int getFetchSize() throws SQLException {
+        try {
+            return resultSet.getFetchSize();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
     @Override
-    public int getType() throws SQLException
-    { try { return _res.getType(); } catch (final SQLException e) { handleException(e); return 0; } }
+    public int getType() throws SQLException {
+        try {
+            return resultSet.getType();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
     @Override
-    public int getConcurrency() throws SQLException
-    { try { return _res.getConcurrency(); } catch (final SQLException e) { handleException(e); return 0; } }
+    public int getConcurrency() throws SQLException {
+        try {
+            return resultSet.getConcurrency();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
     @Override
-    public boolean rowUpdated() throws SQLException
-    { try { return _res.rowUpdated(); } catch (final SQLException e) { handleException(e); return false; } }
+    public boolean rowUpdated() throws SQLException {
+        try {
+            return resultSet.rowUpdated();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
+    }
 
     @Override
-    public boolean rowInserted() throws SQLException
-    { try { return _res.rowInserted(); } catch (final SQLException e) { handleException(e); return false; } }
+    public boolean rowInserted() throws SQLException {
+        try {
+            return resultSet.rowInserted();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
+    }
 
     @Override
-    public boolean rowDeleted() throws SQLException
-    { try { return _res.rowDeleted(); } catch (final SQLException e) { handleException(e); return false; } }
+    public boolean rowDeleted() throws SQLException {
+        try {
+            return resultSet.rowDeleted();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
+    }
 
     @Override
-    public void updateNull(final int columnIndex) throws SQLException
-    { try { _res.updateNull(columnIndex); } catch (final SQLException e) { handleException(e); } }
+    public void updateNull(final int columnIndex) throws SQLException {
+        try {
+            resultSet.updateNull(columnIndex);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateBoolean(final int columnIndex, final boolean x) throws SQLException
-    { try { _res.updateBoolean(columnIndex, x); } catch (final SQLException e) { handleException(e); } }
+    public void updateBoolean(final int columnIndex, final boolean x) throws SQLException {
+        try {
+            resultSet.updateBoolean(columnIndex, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateByte(final int columnIndex, final byte x) throws SQLException
-    { try { _res.updateByte(columnIndex, x); } catch (final SQLException e) { handleException(e); } }
+    public void updateByte(final int columnIndex, final byte x) throws SQLException {
+        try {
+            resultSet.updateByte(columnIndex, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateShort(final int columnIndex, final short x) throws SQLException
-    { try { _res.updateShort(columnIndex, x); } catch (final SQLException e) { handleException(e); } }
+    public void updateShort(final int columnIndex, final short x) throws SQLException {
+        try {
+            resultSet.updateShort(columnIndex, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateInt(final int columnIndex, final int x) throws SQLException
-    { try { _res.updateInt(columnIndex, x); } catch (final SQLException e) { handleException(e); } }
+    public void updateInt(final int columnIndex, final int x) throws SQLException {
+        try {
+            resultSet.updateInt(columnIndex, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateLong(final int columnIndex, final long x) throws SQLException
-    { try { _res.updateLong(columnIndex, x); } catch (final SQLException e) { handleException(e); } }
+    public void updateLong(final int columnIndex, final long x) throws SQLException {
+        try {
+            resultSet.updateLong(columnIndex, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateFloat(final int columnIndex, final float x) throws SQLException
-    { try { _res.updateFloat(columnIndex, x); } catch (final SQLException e) { handleException(e); } }
+    public void updateFloat(final int columnIndex, final float x) throws SQLException {
+        try {
+            resultSet.updateFloat(columnIndex, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateDouble(final int columnIndex, final double x) throws SQLException
-    { try { _res.updateDouble(columnIndex, x); } catch (final SQLException e) { handleException(e); } }
+    public void updateDouble(final int columnIndex, final double x) throws SQLException {
+        try {
+            resultSet.updateDouble(columnIndex, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateBigDecimal(final int columnIndex, final BigDecimal x) throws SQLException
-    { try { _res.updateBigDecimal(columnIndex, x); } catch (final SQLException e) { handleException(e); } }
+    public void updateBigDecimal(final int columnIndex, final BigDecimal x) throws SQLException {
+        try {
+            resultSet.updateBigDecimal(columnIndex, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateString(final int columnIndex, final String x) throws SQLException
-    { try { _res.updateString(columnIndex, x); } catch (final SQLException e) { handleException(e); } }
+    public void updateString(final int columnIndex, final String x) throws SQLException {
+        try {
+            resultSet.updateString(columnIndex, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateBytes(final int columnIndex, final byte[] x) throws SQLException
-    { try { _res.updateBytes(columnIndex, x); } catch (final SQLException e) { handleException(e); } }
+    public void updateBytes(final int columnIndex, final byte[] x) throws SQLException {
+        try {
+            resultSet.updateBytes(columnIndex, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateDate(final int columnIndex, final Date x) throws SQLException
-    { try { _res.updateDate(columnIndex, x); } catch (final SQLException e) { handleException(e); } }
+    public void updateDate(final int columnIndex, final Date x) throws SQLException {
+        try {
+            resultSet.updateDate(columnIndex, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateTime(final int columnIndex, final Time x) throws SQLException
-    { try { _res.updateTime(columnIndex, x); } catch (final SQLException e) { handleException(e); } }
+    public void updateTime(final int columnIndex, final Time x) throws SQLException {
+        try {
+            resultSet.updateTime(columnIndex, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateTimestamp(final int columnIndex, final Timestamp x) throws SQLException
-    { try { _res.updateTimestamp(columnIndex, x); } catch (final SQLException e) { handleException(e); } }
+    public void updateTimestamp(final int columnIndex, final Timestamp x) throws SQLException {
+        try {
+            resultSet.updateTimestamp(columnIndex, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateAsciiStream(final int columnIndex, final InputStream x, final int length) throws SQLException
-    { try { _res.updateAsciiStream(columnIndex, x, length); } catch (final SQLException e) { handleException(e); } }
+    public void updateAsciiStream(final int columnIndex, final InputStream x, final int length) throws SQLException {
+        try {
+            resultSet.updateAsciiStream(columnIndex, x, length);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateBinaryStream(final int columnIndex, final InputStream x, final int length) throws SQLException
-    { try { _res.updateBinaryStream(columnIndex, x, length); } catch (final SQLException e) { handleException(e); } }
+    public void updateBinaryStream(final int columnIndex, final InputStream x, final int length) throws SQLException {
+        try {
+            resultSet.updateBinaryStream(columnIndex, x, length);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateCharacterStream(final int columnIndex, final Reader x, final int length) throws SQLException
-    { try { _res.updateCharacterStream(columnIndex, x, length); } catch (final SQLException e) { handleException(e); } }
+    public void updateCharacterStream(final int columnIndex, final Reader x, final int length) throws SQLException {
+        try {
+            resultSet.updateCharacterStream(columnIndex, x, length);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateObject(final int columnIndex, final Object x, final int scale) throws SQLException
-    { try { _res.updateObject(columnIndex, x); } catch (final SQLException e) { handleException(e); } }
+    public void updateObject(final int columnIndex, final Object x, final int scale) throws SQLException {
+        try {
+            resultSet.updateObject(columnIndex, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateObject(final int columnIndex, final Object x) throws SQLException
-    { try { _res.updateObject(columnIndex, x); } catch (final SQLException e) { handleException(e); } }
+    public void updateObject(final int columnIndex, final Object x) throws SQLException {
+        try {
+            resultSet.updateObject(columnIndex, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateNull(final String columnName) throws SQLException
-    { try { _res.updateNull(columnName); } catch (final SQLException e) { handleException(e); } }
+    public void updateNull(final String columnName) throws SQLException {
+        try {
+            resultSet.updateNull(columnName);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateBoolean(final String columnName, final boolean x) throws SQLException
-    { try { _res.updateBoolean(columnName, x); } catch (final SQLException e) { handleException(e); } }
+    public void updateBoolean(final String columnName, final boolean x) throws SQLException {
+        try {
+            resultSet.updateBoolean(columnName, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateByte(final String columnName, final byte x) throws SQLException
-    { try { _res.updateByte(columnName, x); } catch (final SQLException e) { handleException(e); } }
+    public void updateByte(final String columnName, final byte x) throws SQLException {
+        try {
+            resultSet.updateByte(columnName, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateShort(final String columnName, final short x) throws SQLException
-    { try { _res.updateShort(columnName, x); } catch (final SQLException e) { handleException(e); } }
+    public void updateShort(final String columnName, final short x) throws SQLException {
+        try {
+            resultSet.updateShort(columnName, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateInt(final String columnName, final int x) throws SQLException
-    { try { _res.updateInt(columnName, x); } catch (final SQLException e) { handleException(e); } }
+    public void updateInt(final String columnName, final int x) throws SQLException {
+        try {
+            resultSet.updateInt(columnName, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateLong(final String columnName, final long x) throws SQLException
-    { try { _res.updateLong(columnName, x); } catch (final SQLException e) { handleException(e); } }
+    public void updateLong(final String columnName, final long x) throws SQLException {
+        try {
+            resultSet.updateLong(columnName, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateFloat(final String columnName, final float x) throws SQLException
-    { try { _res.updateFloat(columnName, x); } catch (final SQLException e) { handleException(e); } }
+    public void updateFloat(final String columnName, final float x) throws SQLException {
+        try {
+            resultSet.updateFloat(columnName, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateDouble(final String columnName, final double x) throws SQLException
-    { try { _res.updateDouble(columnName, x); } catch (final SQLException e) { handleException(e); } }
+    public void updateDouble(final String columnName, final double x) throws SQLException {
+        try {
+            resultSet.updateDouble(columnName, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateBigDecimal(final String columnName, final BigDecimal x) throws SQLException
-    { try { _res.updateBigDecimal(columnName, x); } catch (final SQLException e) { handleException(e); } }
+    public void updateBigDecimal(final String columnName, final BigDecimal x) throws SQLException {
+        try {
+            resultSet.updateBigDecimal(columnName, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateString(final String columnName, final String x) throws SQLException
-    { try { _res.updateString(columnName, x); } catch (final SQLException e) { handleException(e); } }
+    public void updateString(final String columnName, final String x) throws SQLException {
+        try {
+            resultSet.updateString(columnName, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateBytes(final String columnName, final byte[] x) throws SQLException
-    { try { _res.updateBytes(columnName, x); } catch (final SQLException e) { handleException(e); } }
+    public void updateBytes(final String columnName, final byte[] x) throws SQLException {
+        try {
+            resultSet.updateBytes(columnName, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateDate(final String columnName, final Date x) throws SQLException
-    { try { _res.updateDate(columnName, x); } catch (final SQLException e) { handleException(e); } }
+    public void updateDate(final String columnName, final Date x) throws SQLException {
+        try {
+            resultSet.updateDate(columnName, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateTime(final String columnName, final Time x) throws SQLException
-    { try { _res.updateTime(columnName, x); } catch (final SQLException e) { handleException(e); } }
+    public void updateTime(final String columnName, final Time x) throws SQLException {
+        try {
+            resultSet.updateTime(columnName, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateTimestamp(final String columnName, final Timestamp x) throws SQLException
-    { try { _res.updateTimestamp(columnName, x); } catch (final SQLException e) { handleException(e); } }
+    public void updateTimestamp(final String columnName, final Timestamp x) throws SQLException {
+        try {
+            resultSet.updateTimestamp(columnName, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateAsciiStream(final String columnName, final InputStream x, final int length) throws SQLException
-    { try { _res.updateAsciiStream(columnName, x, length); } catch (final SQLException e) { handleException(e); } }
+    public void updateAsciiStream(final String columnName, final InputStream x, final int length) throws SQLException {
+        try {
+            resultSet.updateAsciiStream(columnName, x, length);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateBinaryStream(final String columnName, final InputStream x, final int length) throws SQLException
-    { try { _res.updateBinaryStream(columnName, x, length); } catch (final SQLException e) { handleException(e); } }
+    public void updateBinaryStream(final String columnName, final InputStream x, final int length) throws SQLException {
+        try {
+            resultSet.updateBinaryStream(columnName, x, length);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateCharacterStream(final String columnName, final Reader reader, final int length) throws SQLException
-    { try { _res.updateCharacterStream(columnName, reader, length); } catch (final SQLException e) { handleException(e); } }
+    public void updateCharacterStream(final String columnName, final Reader reader, final int length)
+            throws SQLException {
+        try {
+            resultSet.updateCharacterStream(columnName, reader, length);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateObject(final String columnName, final Object x, final int scale) throws SQLException
-    { try { _res.updateObject(columnName, x); } catch (final SQLException e) { handleException(e); } }
+    public void updateObject(final String columnName, final Object x, final int scale) throws SQLException {
+        try {
+            resultSet.updateObject(columnName, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateObject(final String columnName, final Object x) throws SQLException
-    { try { _res.updateObject(columnName, x); } catch (final SQLException e) { handleException(e); } }
+    public void updateObject(final String columnName, final Object x) throws SQLException {
+        try {
+            resultSet.updateObject(columnName, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void insertRow() throws SQLException
-    { try { _res.insertRow(); } catch (final SQLException e) { handleException(e); } }
+    public void insertRow() throws SQLException {
+        try {
+            resultSet.insertRow();
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateRow() throws SQLException
-    { try { _res.updateRow(); } catch (final SQLException e) { handleException(e); } }
+    public void updateRow() throws SQLException {
+        try {
+            resultSet.updateRow();
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void deleteRow() throws SQLException
-    { try { _res.deleteRow(); } catch (final SQLException e) { handleException(e); } }
+    public void deleteRow() throws SQLException {
+        try {
+            resultSet.deleteRow();
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void refreshRow() throws SQLException
-    { try { _res.refreshRow(); } catch (final SQLException e) { handleException(e); } }
+    public void refreshRow() throws SQLException {
+        try {
+            resultSet.refreshRow();
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void cancelRowUpdates() throws SQLException
-    { try { _res.cancelRowUpdates(); } catch (final SQLException e) { handleException(e); } }
+    public void cancelRowUpdates() throws SQLException {
+        try {
+            resultSet.cancelRowUpdates();
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void moveToInsertRow() throws SQLException
-    { try { _res.moveToInsertRow(); } catch (final SQLException e) { handleException(e); } }
+    public void moveToInsertRow() throws SQLException {
+        try {
+            resultSet.moveToInsertRow();
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void moveToCurrentRow() throws SQLException
-    { try { _res.moveToCurrentRow(); } catch (final SQLException e) { handleException(e); } }
+    public void moveToCurrentRow() throws SQLException {
+        try {
+            resultSet.moveToCurrentRow();
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public Object getObject(final int i, final Map<String,Class<?>> map) throws SQLException
-    { try { return _res.getObject(i, map); } catch (final SQLException e) { handleException(e); return null; } }
+    public Object getObject(final int i, final Map<String, Class<?>> map) throws SQLException {
+        try {
+            return resultSet.getObject(i, map);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Ref getRef(final int i) throws SQLException
-    { try { return _res.getRef(i); } catch (final SQLException e) { handleException(e); return null; } }
+    public Ref getRef(final int i) throws SQLException {
+        try {
+            return resultSet.getRef(i);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Blob getBlob(final int i) throws SQLException
-    { try { return _res.getBlob(i); } catch (final SQLException e) { handleException(e); return null; } }
+    public Blob getBlob(final int i) throws SQLException {
+        try {
+            return resultSet.getBlob(i);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Clob getClob(final int i) throws SQLException
-    { try { return _res.getClob(i); } catch (final SQLException e) { handleException(e); return null; } }
+    public Clob getClob(final int i) throws SQLException {
+        try {
+            return resultSet.getClob(i);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Array getArray(final int i) throws SQLException
-    { try { return _res.getArray(i); } catch (final SQLException e) { handleException(e); return null; } }
+    public Array getArray(final int i) throws SQLException {
+        try {
+            return resultSet.getArray(i);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Object getObject(final String colName, final Map<String,Class<?>> map) throws SQLException
-    { try { return _res.getObject(colName, map); } catch (final SQLException e) { handleException(e); return null; } }
+    public Object getObject(final String colName, final Map<String, Class<?>> map) throws SQLException {
+        try {
+            return resultSet.getObject(colName, map);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Ref getRef(final String colName) throws SQLException
-    { try { return _res.getRef(colName); } catch (final SQLException e) { handleException(e); return null; } }
+    public Ref getRef(final String colName) throws SQLException {
+        try {
+            return resultSet.getRef(colName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Blob getBlob(final String colName) throws SQLException
-    { try { return _res.getBlob(colName); } catch (final SQLException e) { handleException(e); return null; } }
+    public Blob getBlob(final String colName) throws SQLException {
+        try {
+            return resultSet.getBlob(colName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Clob getClob(final String colName) throws SQLException
-    { try { return _res.getClob(colName); } catch (final SQLException e) { handleException(e); return null; } }
+    public Clob getClob(final String colName) throws SQLException {
+        try {
+            return resultSet.getClob(colName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Array getArray(final String colName) throws SQLException
-    { try { return _res.getArray(colName); } catch (final SQLException e) { handleException(e); return null; } }
+    public Array getArray(final String colName) throws SQLException {
+        try {
+            return resultSet.getArray(colName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Date getDate(final int columnIndex, final Calendar cal) throws SQLException
-    { try { return _res.getDate(columnIndex, cal); } catch (final SQLException e) { handleException(e); return null; } }
+    public Date getDate(final int columnIndex, final Calendar cal) throws SQLException {
+        try {
+            return resultSet.getDate(columnIndex, cal);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Date getDate(final String columnName, final Calendar cal) throws SQLException
-    { try { return _res.getDate(columnName, cal); } catch (final SQLException e) { handleException(e); return null; } }
+    public Date getDate(final String columnName, final Calendar cal) throws SQLException {
+        try {
+            return resultSet.getDate(columnName, cal);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Time getTime(final int columnIndex, final Calendar cal) throws SQLException
-    { try { return _res.getTime(columnIndex, cal); } catch (final SQLException e) { handleException(e); return null; } }
+    public Time getTime(final int columnIndex, final Calendar cal) throws SQLException {
+        try {
+            return resultSet.getTime(columnIndex, cal);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Time getTime(final String columnName, final Calendar cal) throws SQLException
-    { try { return _res.getTime(columnName, cal); } catch (final SQLException e) { handleException(e); return null; } }
+    public Time getTime(final String columnName, final Calendar cal) throws SQLException {
+        try {
+            return resultSet.getTime(columnName, cal);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Timestamp getTimestamp(final int columnIndex, final Calendar cal) throws SQLException
-    { try { return _res.getTimestamp(columnIndex, cal); } catch (final SQLException e) { handleException(e); return null; } }
+    public Timestamp getTimestamp(final int columnIndex, final Calendar cal) throws SQLException {
+        try {
+            return resultSet.getTimestamp(columnIndex, cal);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public Timestamp getTimestamp(final String columnName, final Calendar cal) throws SQLException
-    { try { return _res.getTimestamp(columnName, cal); } catch (final SQLException e) { handleException(e); return null; } }
-
+    public Timestamp getTimestamp(final String columnName, final Calendar cal) throws SQLException {
+        try {
+            return resultSet.getTimestamp(columnName, cal);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public java.net.URL getURL(final int columnIndex) throws SQLException
-    { try { return _res.getURL(columnIndex); } catch (final SQLException e) { handleException(e); return null; } }
+    public java.net.URL getURL(final int columnIndex) throws SQLException {
+        try {
+            return resultSet.getURL(columnIndex);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public java.net.URL getURL(final String columnName) throws SQLException
-    { try { return _res.getURL(columnName); } catch (final SQLException e) { handleException(e); return null; } }
+    public java.net.URL getURL(final String columnName) throws SQLException {
+        try {
+            return resultSet.getURL(columnName);
+        } catch (final SQLException e) {
+            handleException(e);
+            return null;
+        }
+    }
 
     @Override
-    public void updateRef(final int columnIndex, final Ref x) throws SQLException
-    { try { _res.updateRef(columnIndex, x); } catch (final SQLException e) { handleException(e); } }
+    public void updateRef(final int columnIndex, final Ref x) throws SQLException {
+        try {
+            resultSet.updateRef(columnIndex, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateRef(final String columnName, final Ref x) throws SQLException
-    { try { _res.updateRef(columnName, x); } catch (final SQLException e) { handleException(e); } }
+    public void updateRef(final String columnName, final Ref x) throws SQLException {
+        try {
+            resultSet.updateRef(columnName, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateBlob(final int columnIndex, final Blob x) throws SQLException
-    { try { _res.updateBlob(columnIndex, x); } catch (final SQLException e) { handleException(e); } }
+    public void updateBlob(final int columnIndex, final Blob x) throws SQLException {
+        try {
+            resultSet.updateBlob(columnIndex, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateBlob(final String columnName, final Blob x) throws SQLException
-    { try { _res.updateBlob(columnName, x); } catch (final SQLException e) { handleException(e); } }
+    public void updateBlob(final String columnName, final Blob x) throws SQLException {
+        try {
+            resultSet.updateBlob(columnName, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateClob(final int columnIndex, final Clob x) throws SQLException
-    { try { _res.updateClob(columnIndex, x); } catch (final SQLException e) { handleException(e); } }
+    public void updateClob(final int columnIndex, final Clob x) throws SQLException {
+        try {
+            resultSet.updateClob(columnIndex, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateClob(final String columnName, final Clob x) throws SQLException
-    { try { _res.updateClob(columnName, x); } catch (final SQLException e) { handleException(e); } }
+    public void updateClob(final String columnName, final Clob x) throws SQLException {
+        try {
+            resultSet.updateClob(columnName, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateArray(final int columnIndex, final Array x) throws SQLException
-    { try { _res.updateArray(columnIndex, x); } catch (final SQLException e) { handleException(e); } }
+    public void updateArray(final int columnIndex, final Array x) throws SQLException {
+        try {
+            resultSet.updateArray(columnIndex, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void updateArray(final String columnName, final Array x) throws SQLException
-    { try { _res.updateArray(columnName, x); } catch (final SQLException e) { handleException(e); } }
-
+    public void updateArray(final String columnName, final Array x) throws SQLException {
+        try {
+            resultSet.updateArray(columnName, x);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
     public boolean isWrapperFor(final Class<?> iface) throws SQLException {
         if (iface.isAssignableFrom(getClass())) {
             return true;
-        } else if (iface.isAssignableFrom(_res.getClass())) {
+        } else if (iface.isAssignableFrom(resultSet.getClass())) {
             return true;
         } else {
-            return _res.isWrapperFor(iface);
+            return resultSet.isWrapperFor(iface);
         }
     }
 
@@ -758,19 +1537,18 @@
     public <T> T unwrap(final Class<T> iface) throws SQLException {
         if (iface.isAssignableFrom(getClass())) {
             return iface.cast(this);
-        } else if (iface.isAssignableFrom(_res.getClass())) {
-            return iface.cast(_res);
+        } else if (iface.isAssignableFrom(resultSet.getClass())) {
+            return iface.cast(resultSet);
         } else {
-            return _res.unwrap(iface);
+            return resultSet.unwrap(iface);
         }
     }
 
     @Override
     public RowId getRowId(final int columnIndex) throws SQLException {
         try {
-            return _res.getRowId(columnIndex);
-        }
-        catch (final SQLException e) {
+            return resultSet.getRowId(columnIndex);
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
@@ -779,9 +1557,8 @@
     @Override
     public RowId getRowId(final String columnLabel) throws SQLException {
         try {
-            return _res.getRowId(columnLabel);
-        }
-        catch (final SQLException e) {
+            return resultSet.getRowId(columnLabel);
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
@@ -790,9 +1567,8 @@
     @Override
     public void updateRowId(final int columnIndex, final RowId value) throws SQLException {
         try {
-            _res.updateRowId(columnIndex, value);
-        }
-        catch (final SQLException e) {
+            resultSet.updateRowId(columnIndex, value);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -800,9 +1576,8 @@
     @Override
     public void updateRowId(final String columnLabel, final RowId value) throws SQLException {
         try {
-            _res.updateRowId(columnLabel, value);
-        }
-        catch (final SQLException e) {
+            resultSet.updateRowId(columnLabel, value);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -810,9 +1585,8 @@
     @Override
     public int getHoldability() throws SQLException {
         try {
-            return _res.getHoldability();
-        }
-        catch (final SQLException e) {
+            return resultSet.getHoldability();
+        } catch (final SQLException e) {
             handleException(e);
             return 0;
         }
@@ -821,9 +1595,8 @@
     @Override
     public boolean isClosed() throws SQLException {
         try {
-            return _res.isClosed();
-        }
-        catch (final SQLException e) {
+            return resultSet.isClosed();
+        } catch (final SQLException e) {
             handleException(e);
             return false;
         }
@@ -832,9 +1605,8 @@
     @Override
     public void updateNString(final int columnIndex, final String value) throws SQLException {
         try {
-            _res.updateNString(columnIndex, value);
-        }
-        catch (final SQLException e) {
+            resultSet.updateNString(columnIndex, value);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -842,9 +1614,8 @@
     @Override
     public void updateNString(final String columnLabel, final String value) throws SQLException {
         try {
-            _res.updateNString(columnLabel, value);
-        }
-        catch (final SQLException e) {
+            resultSet.updateNString(columnLabel, value);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -852,9 +1623,8 @@
     @Override
     public void updateNClob(final int columnIndex, final NClob value) throws SQLException {
         try {
-            _res.updateNClob(columnIndex, value);
-        }
-        catch (final SQLException e) {
+            resultSet.updateNClob(columnIndex, value);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -862,9 +1632,8 @@
     @Override
     public void updateNClob(final String columnLabel, final NClob value) throws SQLException {
         try {
-            _res.updateNClob(columnLabel, value);
-        }
-        catch (final SQLException e) {
+            resultSet.updateNClob(columnLabel, value);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -872,9 +1641,8 @@
     @Override
     public NClob getNClob(final int columnIndex) throws SQLException {
         try {
-            return _res.getNClob(columnIndex);
-        }
-        catch (final SQLException e) {
+            return resultSet.getNClob(columnIndex);
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
@@ -883,9 +1651,8 @@
     @Override
     public NClob getNClob(final String columnLabel) throws SQLException {
         try {
-            return _res.getNClob(columnLabel);
-        }
-        catch (final SQLException e) {
+            return resultSet.getNClob(columnLabel);
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
@@ -894,9 +1661,8 @@
     @Override
     public SQLXML getSQLXML(final int columnIndex) throws SQLException {
         try {
-            return _res.getSQLXML(columnIndex);
-        }
-        catch (final SQLException e) {
+            return resultSet.getSQLXML(columnIndex);
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
@@ -905,9 +1671,8 @@
     @Override
     public SQLXML getSQLXML(final String columnLabel) throws SQLException {
         try {
-            return _res.getSQLXML(columnLabel);
-        }
-        catch (final SQLException e) {
+            return resultSet.getSQLXML(columnLabel);
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
@@ -916,9 +1681,8 @@
     @Override
     public void updateSQLXML(final int columnIndex, final SQLXML value) throws SQLException {
         try {
-            _res.updateSQLXML(columnIndex, value);
-        }
-        catch (final SQLException e) {
+            resultSet.updateSQLXML(columnIndex, value);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -926,9 +1690,8 @@
     @Override
     public void updateSQLXML(final String columnLabel, final SQLXML value) throws SQLException {
         try {
-            _res.updateSQLXML(columnLabel, value);
-        }
-        catch (final SQLException e) {
+            resultSet.updateSQLXML(columnLabel, value);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -936,9 +1699,8 @@
     @Override
     public String getNString(final int columnIndex) throws SQLException {
         try {
-            return _res.getNString(columnIndex);
-        }
-        catch (final SQLException e) {
+            return resultSet.getNString(columnIndex);
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
@@ -947,9 +1709,8 @@
     @Override
     public String getNString(final String columnLabel) throws SQLException {
         try {
-            return _res.getNString(columnLabel);
-        }
-        catch (final SQLException e) {
+            return resultSet.getNString(columnLabel);
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
@@ -958,9 +1719,8 @@
     @Override
     public Reader getNCharacterStream(final int columnIndex) throws SQLException {
         try {
-            return _res.getNCharacterStream(columnIndex);
-        }
-        catch (final SQLException e) {
+            return resultSet.getNCharacterStream(columnIndex);
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
@@ -969,110 +1729,109 @@
     @Override
     public Reader getNCharacterStream(final String columnLabel) throws SQLException {
         try {
-            return _res.getNCharacterStream(columnLabel);
-        }
-        catch (final SQLException e) {
+            return resultSet.getNCharacterStream(columnLabel);
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
     }
 
     @Override
-    public void updateNCharacterStream(final int columnIndex, final Reader reader, final long length) throws SQLException {
+    public void updateNCharacterStream(final int columnIndex, final Reader reader, final long length)
+            throws SQLException {
         try {
-            _res.updateNCharacterStream(columnIndex, reader, length);
-        }
-        catch (final SQLException e) {
+            resultSet.updateNCharacterStream(columnIndex, reader, length);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
 
     @Override
-    public void updateNCharacterStream(final String columnLabel, final Reader reader, final long length) throws SQLException {
+    public void updateNCharacterStream(final String columnLabel, final Reader reader, final long length)
+            throws SQLException {
         try {
-            _res.updateNCharacterStream(columnLabel, reader, length);
-        }
-        catch (final SQLException e) {
+            resultSet.updateNCharacterStream(columnLabel, reader, length);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
 
     @Override
-    public void updateAsciiStream(final int columnIndex, final InputStream inputStream, final long length) throws SQLException {
+    public void updateAsciiStream(final int columnIndex, final InputStream inputStream, final long length)
+            throws SQLException {
         try {
-            _res.updateAsciiStream(columnIndex, inputStream, length);
-        }
-        catch (final SQLException e) {
+            resultSet.updateAsciiStream(columnIndex, inputStream, length);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
 
     @Override
-    public void updateBinaryStream(final int columnIndex, final InputStream inputStream, final long length) throws SQLException {
+    public void updateBinaryStream(final int columnIndex, final InputStream inputStream, final long length)
+            throws SQLException {
         try {
-            _res.updateBinaryStream(columnIndex, inputStream, length);
-        }
-        catch (final SQLException e) {
+            resultSet.updateBinaryStream(columnIndex, inputStream, length);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
 
     @Override
-    public void updateCharacterStream(final int columnIndex, final Reader reader, final long length) throws SQLException {
+    public void updateCharacterStream(final int columnIndex, final Reader reader, final long length)
+            throws SQLException {
         try {
-            _res.updateCharacterStream(columnIndex, reader, length);
-        }
-        catch (final SQLException e) {
+            resultSet.updateCharacterStream(columnIndex, reader, length);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
 
     @Override
-    public void updateAsciiStream(final String columnLabel, final InputStream inputStream, final long length) throws SQLException {
+    public void updateAsciiStream(final String columnLabel, final InputStream inputStream, final long length)
+            throws SQLException {
         try {
-            _res.updateAsciiStream(columnLabel, inputStream, length);
-        }
-        catch (final SQLException e) {
+            resultSet.updateAsciiStream(columnLabel, inputStream, length);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
 
     @Override
-    public void updateBinaryStream(final String columnLabel, final InputStream inputStream, final long length) throws SQLException {
+    public void updateBinaryStream(final String columnLabel, final InputStream inputStream, final long length)
+            throws SQLException {
         try {
-            _res.updateBinaryStream(columnLabel, inputStream, length);
-        }
-        catch (final SQLException e) {
+            resultSet.updateBinaryStream(columnLabel, inputStream, length);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
 
     @Override
-    public void updateCharacterStream(final String columnLabel, final Reader reader, final long length) throws SQLException {
+    public void updateCharacterStream(final String columnLabel, final Reader reader, final long length)
+            throws SQLException {
         try {
-            _res.updateCharacterStream(columnLabel, reader, length);
-        }
-        catch (final SQLException e) {
+            resultSet.updateCharacterStream(columnLabel, reader, length);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
 
     @Override
-    public void updateBlob(final int columnIndex, final InputStream inputStream, final long length) throws SQLException {
+    public void updateBlob(final int columnIndex, final InputStream inputStream, final long length)
+            throws SQLException {
         try {
-            _res.updateBlob(columnIndex, inputStream, length);
-        }
-        catch (final SQLException e) {
+            resultSet.updateBlob(columnIndex, inputStream, length);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
 
     @Override
-    public void updateBlob(final String columnLabel, final InputStream inputStream, final long length) throws SQLException {
+    public void updateBlob(final String columnLabel, final InputStream inputStream, final long length)
+            throws SQLException {
         try {
-            _res.updateBlob(columnLabel, inputStream, length);
-        }
-        catch (final SQLException e) {
+            resultSet.updateBlob(columnLabel, inputStream, length);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -1080,9 +1839,8 @@
     @Override
     public void updateClob(final int columnIndex, final Reader reader, final long length) throws SQLException {
         try {
-            _res.updateClob(columnIndex, reader, length);
-        }
-        catch (final SQLException e) {
+            resultSet.updateClob(columnIndex, reader, length);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -1090,9 +1848,8 @@
     @Override
     public void updateClob(final String columnLabel, final Reader reader, final long length) throws SQLException {
         try {
-            _res.updateClob(columnLabel, reader, length);
-        }
-        catch (final SQLException e) {
+            resultSet.updateClob(columnLabel, reader, length);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -1100,9 +1857,8 @@
     @Override
     public void updateNClob(final int columnIndex, final Reader reader, final long length) throws SQLException {
         try {
-            _res.updateNClob(columnIndex, reader, length);
-        }
-        catch (final SQLException e) {
+            resultSet.updateNClob(columnIndex, reader, length);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -1110,9 +1866,8 @@
     @Override
     public void updateNClob(final String columnLabel, final Reader reader, final long length) throws SQLException {
         try {
-            _res.updateNClob(columnLabel, reader, length);
-        }
-        catch (final SQLException e) {
+            resultSet.updateNClob(columnLabel, reader, length);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -1120,9 +1875,8 @@
     @Override
     public void updateNCharacterStream(final int columnIndex, final Reader reader) throws SQLException {
         try {
-            _res.updateNCharacterStream(columnIndex, reader);
-        }
-        catch (final SQLException e) {
+            resultSet.updateNCharacterStream(columnIndex, reader);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -1130,9 +1884,8 @@
     @Override
     public void updateNCharacterStream(final String columnLabel, final Reader reader) throws SQLException {
         try {
-            _res.updateNCharacterStream(columnLabel, reader);
-        }
-        catch (final SQLException e) {
+            resultSet.updateNCharacterStream(columnLabel, reader);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -1140,9 +1893,8 @@
     @Override
     public void updateAsciiStream(final int columnIndex, final InputStream inputStream) throws SQLException {
         try {
-            _res.updateAsciiStream(columnIndex, inputStream);
-        }
-        catch (final SQLException e) {
+            resultSet.updateAsciiStream(columnIndex, inputStream);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -1150,9 +1902,8 @@
     @Override
     public void updateBinaryStream(final int columnIndex, final InputStream inputStream) throws SQLException {
         try {
-            _res.updateBinaryStream(columnIndex, inputStream);
-        }
-        catch (final SQLException e) {
+            resultSet.updateBinaryStream(columnIndex, inputStream);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -1160,9 +1911,8 @@
     @Override
     public void updateCharacterStream(final int columnIndex, final Reader reader) throws SQLException {
         try {
-            _res.updateCharacterStream(columnIndex, reader);
-        }
-        catch (final SQLException e) {
+            resultSet.updateCharacterStream(columnIndex, reader);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -1170,9 +1920,8 @@
     @Override
     public void updateAsciiStream(final String columnLabel, final InputStream inputStream) throws SQLException {
         try {
-            _res.updateAsciiStream(columnLabel, inputStream);
-        }
-        catch (final SQLException e) {
+            resultSet.updateAsciiStream(columnLabel, inputStream);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -1180,9 +1929,8 @@
     @Override
     public void updateBinaryStream(final String columnLabel, final InputStream inputStream) throws SQLException {
         try {
-            _res.updateBinaryStream(columnLabel, inputStream);
-        }
-        catch (final SQLException e) {
+            resultSet.updateBinaryStream(columnLabel, inputStream);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -1190,9 +1938,8 @@
     @Override
     public void updateCharacterStream(final String columnLabel, final Reader reader) throws SQLException {
         try {
-            _res.updateCharacterStream(columnLabel, reader);
-        }
-        catch (final SQLException e) {
+            resultSet.updateCharacterStream(columnLabel, reader);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -1200,9 +1947,8 @@
     @Override
     public void updateBlob(final int columnIndex, final InputStream inputStream) throws SQLException {
         try {
-            _res.updateBlob(columnIndex, inputStream);
-        }
-        catch (final SQLException e) {
+            resultSet.updateBlob(columnIndex, inputStream);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -1210,9 +1956,8 @@
     @Override
     public void updateBlob(final String columnLabel, final InputStream inputStream) throws SQLException {
         try {
-            _res.updateBlob(columnLabel, inputStream);
-        }
-        catch (final SQLException e) {
+            resultSet.updateBlob(columnLabel, inputStream);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -1220,9 +1965,8 @@
     @Override
     public void updateClob(final int columnIndex, final Reader reader) throws SQLException {
         try {
-            _res.updateClob(columnIndex, reader);
-        }
-        catch (final SQLException e) {
+            resultSet.updateClob(columnIndex, reader);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -1230,9 +1974,8 @@
     @Override
     public void updateClob(final String columnLabel, final Reader reader) throws SQLException {
         try {
-            _res.updateClob(columnLabel, reader);
-        }
-        catch (final SQLException e) {
+            resultSet.updateClob(columnLabel, reader);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -1240,9 +1983,8 @@
     @Override
     public void updateNClob(final int columnIndex, final Reader reader) throws SQLException {
         try {
-            _res.updateNClob(columnIndex, reader);
-        }
-        catch (final SQLException e) {
+            resultSet.updateNClob(columnIndex, reader);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -1250,9 +1992,8 @@
     @Override
     public void updateNClob(final String columnLabel, final Reader reader) throws SQLException {
         try {
-            _res.updateNClob(columnLabel, reader);
-        }
-        catch (final SQLException e) {
+            resultSet.updateNClob(columnLabel, reader);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -1260,23 +2001,25 @@
     @Override
     public <T> T getObject(final int columnIndex, final Class<T> type) throws SQLException {
         try {
-            return _res.getObject(columnIndex, type);
-        }
-        catch (final SQLException e) {
+            return resultSet.getObject(columnIndex, type);
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
     }
 
     @Override
-    public <T> T getObject(final String columnLabel, final Class<T> type)
-            throws SQLException {
+    public <T> T getObject(final String columnLabel, final Class<T> type) throws SQLException {
         try {
-            return _res.getObject(columnLabel, type);
-        }
-        catch (final SQLException e) {
+            return resultSet.getObject(columnLabel, type);
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
     }
+
+    @Override
+    public String toString() {
+        return super.toString() + "[_res=" + resultSet + ", _stmt=" + statement + ", _conn=" + connection + "]";
+    }
 }
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingStatement.java b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingStatement.java
index d0ebe1e..fffc70f 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingStatement.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingStatement.java
@@ -26,105 +26,102 @@
 /**
  * A base delegating implementation of {@link Statement}.
  * <p>
- * All of the methods from the {@link Statement} interface
- * simply check to see that the {@link Statement} is active,
- * and call the corresponding method on the "delegate"
- * provided in my constructor.
+ * All of the methods from the {@link Statement} interface simply check to see that the {@link Statement} is active, and
+ * call the corresponding method on the "delegate" provided in my constructor.
  * <p>
- * Extends AbandonedTrace to implement Statement tracking and
- * logging of code which created the Statement. Tracking the
- * Statement ensures that the Connection which created it can
- * close any open Statement's on Connection close.
+ * Extends AbandonedTrace to implement Statement tracking and logging of code which created the Statement. Tracking the
+ * Statement ensures that the Connection which created it can close any open Statement's on Connection close.
  *
- * @author Rodney Waldhoff
- * @author Glenn L. Nielsen
- * @author James House
- * @author Dirk Verbeeck
  * @since 2.0
  */
 public class DelegatingStatement extends AbandonedTrace implements Statement {
+
     /** My delegate. */
-    private Statement _stmt = null;
+    private Statement statement;
+
     /** The connection that created me. **/
-    private DelegatingConnection<?> _conn = null;
+    private DelegatingConnection<?> connection;
 
     /**
-     * Create a wrapper for the Statement which traces this
-     * Statement to the Connection which created it and the
-     * code which created it.
+     * Create a wrapper for the Statement which traces this Statement to the Connection which created it and the code
+     * which created it.
      *
-     * @param s the {@link Statement} to delegate all calls to.
-     * @param c the {@link DelegatingConnection} that created this statement.
+     * @param statement
+     *            the {@link Statement} to delegate all calls to.
+     * @param connection
+     *            the {@link DelegatingConnection} that created this statement.
      */
-    public DelegatingStatement(final DelegatingConnection<?> c, final Statement s) {
-        super(c);
-        _stmt = s;
-        _conn = c;
+    public DelegatingStatement(final DelegatingConnection<?> connection, final Statement statement) {
+        super(connection);
+        this.statement = statement;
+        this.connection = connection;
     }
 
     /**
      * Returns my underlying {@link Statement}.
+     *
      * @return my underlying {@link Statement}.
      * @see #getInnermostDelegate
      */
     public Statement getDelegate() {
-        return _stmt;
+        return statement;
     }
 
-
     /**
-     * If my underlying {@link Statement} is not a
-     * {@code DelegatingStatement}, returns it,
-     * otherwise recursively invokes this method on
-     * my delegate.
+     * If my underlying {@link Statement} is not a {@code DelegatingStatement}, returns it, otherwise recursively
+     * invokes this method on my delegate.
      * <p>
-     * Hence this method will return the first
-     * delegate that is not a {@code DelegatingStatement}
-     * or {@code null} when no non-{@code DelegatingStatement}
-     * delegate can be found by traversing this chain.
+     * Hence this method will return the first delegate that is not a {@code DelegatingStatement} or {@code null} when
+     * no non-{@code DelegatingStatement} delegate can be found by traversing this chain.
+     * </p>
      * <p>
-     * This method is useful when you may have nested
-     * {@code DelegatingStatement}s, and you want to make
-     * sure to obtain a "genuine" {@link Statement}.
+     * This method is useful when you may have nested {@code DelegatingStatement}s, and you want to make sure to obtain
+     * a "genuine" {@link Statement}.
+     * </p>
+     *
+     * @return The innermost delegate.
+     *
      * @see #getDelegate
      */
     public Statement getInnermostDelegate() {
-        Statement s = _stmt;
-        while(s != null && s instanceof DelegatingStatement) {
-            s = ((DelegatingStatement)s).getDelegate();
-            if(this == s) {
+        Statement s = statement;
+        while (s != null && s instanceof DelegatingStatement) {
+            s = ((DelegatingStatement) s).getDelegate();
+            if (this == s) {
                 return null;
             }
         }
         return s;
     }
 
-    /** Sets my delegate. */
-    public void setDelegate(final Statement s) {
-        _stmt = s;
+    /**
+     * Sets my delegate.
+     *
+     * @param statement
+     *            my delegate.
+     */
+    public void setDelegate(final Statement statement) {
+        this.statement = statement;
     }
 
-    private boolean _closed = false;
+    private boolean closed = false;
 
     protected boolean isClosedInternal() {
-        return _closed;
+        return closed;
     }
 
     protected void setClosedInternal(final boolean closed) {
-        this._closed = closed;
+        this.closed = closed;
     }
 
     protected void checkOpen() throws SQLException {
-        if(isClosed()) {
-            throw new SQLException
-                (this.getClass().getName() + " with address: \"" +
-                this.toString() + "\" is closed.");
+        if (isClosed()) {
+            throw new SQLException(this.getClass().getName() + " with address: \"" + this.toString() + "\" is closed.");
         }
     }
 
     /**
-     * Close this DelegatingStatement, and close
-     * any ResultSets that were not explicitly closed.
+     * Close this DelegatingStatement, and close any ResultSets that were not explicitly closed.
      */
     @Override
     public void close() throws SQLException {
@@ -133,9 +130,9 @@
         }
         try {
             try {
-                if (_conn != null) {
-                    _conn.removeTrace(this);
-                    _conn = null;
+                if (connection != null) {
+                    connection.removeTrace(this);
+                    connection = null;
                 }
 
                 // The JDBC spec requires that a statement close any open
@@ -143,7 +140,7 @@
                 // FIXME The PreparedStatement we're wrapping should handle this for us.
                 // See bug 17301 for what could happen when ResultSets are closed twice.
                 final List<AbandonedTrace> resultSets = getTrace();
-                if( resultSets != null) {
+                if (resultSets != null) {
                     final ResultSet[] set = resultSets.toArray(new ResultSet[resultSets.size()]);
                     for (final ResultSet element : set) {
                         element.close();
@@ -151,38 +148,47 @@
                     clearTrace();
                 }
 
-                if (_stmt != null) {
-                    _stmt.close();
+                if (statement != null) {
+                    statement.close();
                 }
-            }
-            catch (final SQLException e) {
+            } catch (final SQLException e) {
                 handleException(e);
             }
-        }
-        finally {
-            _closed = true;
-            _stmt = null;
+        } finally {
+            closed = true;
+            statement = null;
         }
     }
 
     protected void handleException(final SQLException e) throws SQLException {
-        if (_conn != null) {
-            _conn.handleException(e);
-        }
-        else {
+        if (connection != null) {
+            connection.handleException(e);
+        } else {
             throw e;
         }
     }
 
-    protected void activate() throws SQLException {
-        if(_stmt instanceof DelegatingStatement) {
-            ((DelegatingStatement)_stmt).activate();
+    /**
+     *
+     * @throws SQLException
+     *             thrown by the delegating statement.
+     * @since 2.4.0 made public, was protected in 2.3.0.
+     */
+    public void activate() throws SQLException {
+        if (statement instanceof DelegatingStatement) {
+            ((DelegatingStatement) statement).activate();
         }
     }
 
-    protected void passivate() throws SQLException {
-        if(_stmt instanceof DelegatingStatement) {
-            ((DelegatingStatement)_stmt).passivate();
+    /**
+     *
+     * @throws SQLException
+     *             thrown by the delegating statement.
+     * @since 2.4.0 made public, was protected in 2.3.0.
+     */
+    public void passivate() throws SQLException {
+        if (statement instanceof DelegatingStatement) {
+            ((DelegatingStatement) statement).passivate();
         }
     }
 
@@ -193,19 +199,18 @@
     }
 
     protected DelegatingConnection<?> getConnectionInternal() {
-        return _conn;
+        return connection;
     }
 
     @Override
     public ResultSet executeQuery(final String sql) throws SQLException {
         checkOpen();
-        if (_conn != null) {
-            _conn.setLastUsed();
+        if (connection != null) {
+            connection.setLastUsed();
         }
         try {
-            return DelegatingResultSet.wrapResultSet(this,_stmt.executeQuery(sql));
-        }
-        catch (final SQLException e) {
+            return DelegatingResultSet.wrapResultSet(this, statement.executeQuery(sql));
+        } catch (final SQLException e) {
             handleException(e);
             throw new AssertionError();
         }
@@ -215,9 +220,8 @@
     public ResultSet getResultSet() throws SQLException {
         checkOpen();
         try {
-            return DelegatingResultSet.wrapResultSet(this,_stmt.getResultSet());
-        }
-        catch (final SQLException e) {
+            return DelegatingResultSet.wrapResultSet(this, statement.getResultSet());
+        } catch (final SQLException e) {
             handleException(e);
             throw new AssertionError();
         }
@@ -226,68 +230,139 @@
     @Override
     public int executeUpdate(final String sql) throws SQLException {
         checkOpen();
-        if (_conn != null) {
-            _conn.setLastUsed();
+        if (connection != null) {
+            connection.setLastUsed();
         }
         try {
-            return _stmt.executeUpdate(sql);
+            return statement.executeUpdate(sql);
         } catch (final SQLException e) {
-            handleException(e); return 0;
+            handleException(e);
+            return 0;
         }
     }
 
     @Override
-    public int getMaxFieldSize() throws SQLException
-    { checkOpen(); try { return _stmt.getMaxFieldSize(); } catch (final SQLException e) { handleException(e); return 0; } }
+    public int getMaxFieldSize() throws SQLException {
+        checkOpen();
+        try {
+            return statement.getMaxFieldSize();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
     @Override
-    public void setMaxFieldSize(final int max) throws SQLException
-    { checkOpen(); try { _stmt.setMaxFieldSize(max); } catch (final SQLException e) { handleException(e); } }
+    public void setMaxFieldSize(final int max) throws SQLException {
+        checkOpen();
+        try {
+            statement.setMaxFieldSize(max);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public int getMaxRows() throws SQLException
-    { checkOpen(); try { return _stmt.getMaxRows(); } catch (final SQLException e) { handleException(e); return 0; } }
+    public int getMaxRows() throws SQLException {
+        checkOpen();
+        try {
+            return statement.getMaxRows();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
     @Override
-    public void setMaxRows(final int max) throws SQLException
-    { checkOpen(); try { _stmt.setMaxRows(max); } catch (final SQLException e) { handleException(e); } }
+    public void setMaxRows(final int max) throws SQLException {
+        checkOpen();
+        try {
+            statement.setMaxRows(max);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setEscapeProcessing(final boolean enable) throws SQLException
-    { checkOpen(); try { _stmt.setEscapeProcessing(enable); } catch (final SQLException e) { handleException(e); } }
+    public void setEscapeProcessing(final boolean enable) throws SQLException {
+        checkOpen();
+        try {
+            statement.setEscapeProcessing(enable);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public int getQueryTimeout() throws SQLException
-    { checkOpen(); try { return _stmt.getQueryTimeout(); } catch (final SQLException e) { handleException(e); return 0; } }
+    public int getQueryTimeout() throws SQLException {
+        checkOpen();
+        try {
+            return statement.getQueryTimeout();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
     @Override
-    public void setQueryTimeout(final int seconds) throws SQLException
-    { checkOpen(); try { _stmt.setQueryTimeout(seconds); } catch (final SQLException e) { handleException(e); } }
+    public void setQueryTimeout(final int seconds) throws SQLException {
+        checkOpen();
+        try {
+            statement.setQueryTimeout(seconds);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void cancel() throws SQLException
-    { checkOpen(); try { _stmt.cancel(); } catch (final SQLException e) { handleException(e); } }
+    public void cancel() throws SQLException {
+        checkOpen();
+        try {
+            statement.cancel();
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public SQLWarning getWarnings() throws SQLException
-    { checkOpen(); try { return _stmt.getWarnings(); } catch (final SQLException e) { handleException(e); throw new AssertionError(); } }
+    public SQLWarning getWarnings() throws SQLException {
+        checkOpen();
+        try {
+            return statement.getWarnings();
+        } catch (final SQLException e) {
+            handleException(e);
+            throw new AssertionError();
+        }
+    }
 
     @Override
-    public void clearWarnings() throws SQLException
-    { checkOpen(); try { _stmt.clearWarnings(); } catch (final SQLException e) { handleException(e); } }
+    public void clearWarnings() throws SQLException {
+        checkOpen();
+        try {
+            statement.clearWarnings();
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void setCursorName(final String name) throws SQLException
-    { checkOpen(); try { _stmt.setCursorName(name); } catch (final SQLException e) { handleException(e); } }
+    public void setCursorName(final String name) throws SQLException {
+        checkOpen();
+        try {
+            statement.setCursorName(name);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
     public boolean execute(final String sql) throws SQLException {
         checkOpen();
-        if (_conn != null) {
-            _conn.setLastUsed();
+        if (connection != null) {
+            connection.setLastUsed();
         }
         try {
-            return _stmt.execute(sql);
+            return statement.execute(sql);
         } catch (final SQLException e) {
             handleException(e);
             return false;
@@ -295,53 +370,119 @@
     }
 
     @Override
-    public int getUpdateCount() throws SQLException
-    { checkOpen(); try { return _stmt.getUpdateCount(); } catch (final SQLException e) { handleException(e); return 0; } }
+    public int getUpdateCount() throws SQLException {
+        checkOpen();
+        try {
+            return statement.getUpdateCount();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
     @Override
-    public boolean getMoreResults() throws SQLException
-    { checkOpen(); try { return _stmt.getMoreResults(); } catch (final SQLException e) { handleException(e); return false; } }
+    public boolean getMoreResults() throws SQLException {
+        checkOpen();
+        try {
+            return statement.getMoreResults();
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
+    }
 
     @Override
-    public void setFetchDirection(final int direction) throws SQLException
-    { checkOpen(); try { _stmt.setFetchDirection(direction); } catch (final SQLException e) { handleException(e); } }
+    public void setFetchDirection(final int direction) throws SQLException {
+        checkOpen();
+        try {
+            statement.setFetchDirection(direction);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public int getFetchDirection() throws SQLException
-    { checkOpen(); try { return _stmt.getFetchDirection(); } catch (final SQLException e) { handleException(e); return 0; } }
+    public int getFetchDirection() throws SQLException {
+        checkOpen();
+        try {
+            return statement.getFetchDirection();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
     @Override
-    public void setFetchSize(final int rows) throws SQLException
-    { checkOpen(); try { _stmt.setFetchSize(rows); } catch (final SQLException e) { handleException(e); } }
+    public void setFetchSize(final int rows) throws SQLException {
+        checkOpen();
+        try {
+            statement.setFetchSize(rows);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public int getFetchSize() throws SQLException
-    { checkOpen(); try { return _stmt.getFetchSize(); } catch (final SQLException e) { handleException(e); return 0; } }
+    public int getFetchSize() throws SQLException {
+        checkOpen();
+        try {
+            return statement.getFetchSize();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
     @Override
-    public int getResultSetConcurrency() throws SQLException
-    { checkOpen(); try { return _stmt.getResultSetConcurrency(); } catch (final SQLException e) { handleException(e); return 0; } }
+    public int getResultSetConcurrency() throws SQLException {
+        checkOpen();
+        try {
+            return statement.getResultSetConcurrency();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
     @Override
-    public int getResultSetType() throws SQLException
-    { checkOpen(); try { return _stmt.getResultSetType(); } catch (final SQLException e) { handleException(e); return 0; } }
+    public int getResultSetType() throws SQLException {
+        checkOpen();
+        try {
+            return statement.getResultSetType();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
     @Override
-    public void addBatch(final String sql) throws SQLException
-    { checkOpen(); try { _stmt.addBatch(sql); } catch (final SQLException e) { handleException(e); } }
+    public void addBatch(final String sql) throws SQLException {
+        checkOpen();
+        try {
+            statement.addBatch(sql);
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
-    public void clearBatch() throws SQLException
-    { checkOpen(); try { _stmt.clearBatch(); } catch (final SQLException e) { handleException(e); } }
+    public void clearBatch() throws SQLException {
+        checkOpen();
+        try {
+            statement.clearBatch();
+        } catch (final SQLException e) {
+            handleException(e);
+        }
+    }
 
     @Override
     public int[] executeBatch() throws SQLException {
         checkOpen();
-        if (_conn != null) {
-            _conn.setLastUsed();
+        if (connection != null) {
+            connection.setLastUsed();
         }
         try {
-            return _stmt.executeBatch();
+            return statement.executeBatch();
         } catch (final SQLException e) {
             handleException(e);
             throw new AssertionError();
@@ -355,18 +496,25 @@
      */
     @Override
     public String toString() {
-    return _stmt == null ? "NULL" : _stmt.toString();
+        return statement == null ? "NULL" : statement.toString();
     }
 
     @Override
-    public boolean getMoreResults(final int current) throws SQLException
-    { checkOpen(); try { return _stmt.getMoreResults(current); } catch (final SQLException e) { handleException(e); return false; } }
+    public boolean getMoreResults(final int current) throws SQLException {
+        checkOpen();
+        try {
+            return statement.getMoreResults(current);
+        } catch (final SQLException e) {
+            handleException(e);
+            return false;
+        }
+    }
 
     @Override
     public ResultSet getGeneratedKeys() throws SQLException {
         checkOpen();
         try {
-            return DelegatingResultSet.wrapResultSet(this, _stmt.getGeneratedKeys());
+            return DelegatingResultSet.wrapResultSet(this, statement.getGeneratedKeys());
         } catch (final SQLException e) {
             handleException(e);
             throw new AssertionError();
@@ -376,11 +524,11 @@
     @Override
     public int executeUpdate(final String sql, final int autoGeneratedKeys) throws SQLException {
         checkOpen();
-        if (_conn != null) {
-            _conn.setLastUsed();
+        if (connection != null) {
+            connection.setLastUsed();
         }
         try {
-            return _stmt.executeUpdate(sql, autoGeneratedKeys);
+            return statement.executeUpdate(sql, autoGeneratedKeys);
         } catch (final SQLException e) {
             handleException(e);
             return 0;
@@ -390,11 +538,11 @@
     @Override
     public int executeUpdate(final String sql, final int columnIndexes[]) throws SQLException {
         checkOpen();
-        if (_conn != null) {
-            _conn.setLastUsed();
+        if (connection != null) {
+            connection.setLastUsed();
         }
         try {
-            return _stmt.executeUpdate(sql, columnIndexes);
+            return statement.executeUpdate(sql, columnIndexes);
         } catch (final SQLException e) {
             handleException(e);
             return 0;
@@ -404,11 +552,11 @@
     @Override
     public int executeUpdate(final String sql, final String columnNames[]) throws SQLException {
         checkOpen();
-        if (_conn != null) {
-            _conn.setLastUsed();
+        if (connection != null) {
+            connection.setLastUsed();
         }
         try {
-            return _stmt.executeUpdate(sql, columnNames);
+            return statement.executeUpdate(sql, columnNames);
         } catch (final SQLException e) {
             handleException(e);
             return 0;
@@ -418,11 +566,11 @@
     @Override
     public boolean execute(final String sql, final int autoGeneratedKeys) throws SQLException {
         checkOpen();
-        if (_conn != null) {
-            _conn.setLastUsed();
+        if (connection != null) {
+            connection.setLastUsed();
         }
         try {
-            return _stmt.execute(sql, autoGeneratedKeys);
+            return statement.execute(sql, autoGeneratedKeys);
         } catch (final SQLException e) {
             handleException(e);
             return false;
@@ -432,11 +580,11 @@
     @Override
     public boolean execute(final String sql, final int columnIndexes[]) throws SQLException {
         checkOpen();
-        if (_conn != null) {
-            _conn.setLastUsed();
+        if (connection != null) {
+            connection.setLastUsed();
         }
         try {
-            return _stmt.execute(sql, columnIndexes);
+            return statement.execute(sql, columnIndexes);
         } catch (final SQLException e) {
             handleException(e);
             return false;
@@ -446,11 +594,11 @@
     @Override
     public boolean execute(final String sql, final String columnNames[]) throws SQLException {
         checkOpen();
-        if (_conn != null) {
-            _conn.setLastUsed();
+        if (connection != null) {
+            connection.setLastUsed();
         }
         try {
-            return _stmt.execute(sql, columnNames);
+            return statement.execute(sql, columnNames);
         } catch (final SQLException e) {
             handleException(e);
             return false;
@@ -458,26 +606,32 @@
     }
 
     @Override
-    public int getResultSetHoldability() throws SQLException
-    { checkOpen(); try { return _stmt.getResultSetHoldability(); } catch (final SQLException e) { handleException(e); return 0; } }
+    public int getResultSetHoldability() throws SQLException {
+        checkOpen();
+        try {
+            return statement.getResultSetHoldability();
+        } catch (final SQLException e) {
+            handleException(e);
+            return 0;
+        }
+    }
 
     /*
      * Note was protected prior to JDBC 4
      */
     @Override
     public boolean isClosed() throws SQLException {
-        return _closed;
+        return closed;
     }
 
-
     @Override
     public boolean isWrapperFor(final Class<?> iface) throws SQLException {
         if (iface.isAssignableFrom(getClass())) {
             return true;
-        } else if (iface.isAssignableFrom(_stmt.getClass())) {
+        } else if (iface.isAssignableFrom(statement.getClass())) {
             return true;
         } else {
-            return _stmt.isWrapperFor(iface);
+            return statement.isWrapperFor(iface);
         }
     }
 
@@ -485,10 +639,10 @@
     public <T> T unwrap(final Class<T> iface) throws SQLException {
         if (iface.isAssignableFrom(getClass())) {
             return iface.cast(this);
-        } else if (iface.isAssignableFrom(_stmt.getClass())) {
-            return iface.cast(_stmt);
+        } else if (iface.isAssignableFrom(statement.getClass())) {
+            return iface.cast(statement);
         } else {
-            return _stmt.unwrap(iface);
+            return statement.unwrap(iface);
         }
     }
 
@@ -496,9 +650,8 @@
     public void setPoolable(final boolean poolable) throws SQLException {
         checkOpen();
         try {
-            _stmt.setPoolable(poolable);
-        }
-        catch (final SQLException e) {
+            statement.setPoolable(poolable);
+        } catch (final SQLException e) {
             handleException(e);
         }
     }
@@ -507,9 +660,8 @@
     public boolean isPoolable() throws SQLException {
         checkOpen();
         try {
-            return _stmt.isPoolable();
-        }
-        catch (final SQLException e) {
+            return statement.isPoolable();
+        } catch (final SQLException e) {
             handleException(e);
             return false;
         }
@@ -519,7 +671,7 @@
     public void closeOnCompletion() throws SQLException {
         checkOpen();
         try {
-            _stmt.closeOnCompletion();
+            statement.closeOnCompletion();
         } catch (final SQLException e) {
             handleException(e);
         }
@@ -529,7 +681,7 @@
     public boolean isCloseOnCompletion() throws SQLException {
         checkOpen();
         try {
-            return _stmt.isCloseOnCompletion();
+            return statement.isCloseOnCompletion();
         } catch (final SQLException e) {
             handleException(e);
             return false;
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/DriverConnectionFactory.java b/java/org/apache/tomcat/dbcp/dbcp2/DriverConnectionFactory.java
index 6daf2bb..06f3bd9 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/DriverConnectionFactory.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/DriverConnectionFactory.java
@@ -23,28 +23,38 @@
 /**
  * A {@link Driver}-based implementation of {@link ConnectionFactory}.
  *
- * @author Rodney Waldhoff
  * @since 2.0
  */
 public class DriverConnectionFactory implements ConnectionFactory {
-    public DriverConnectionFactory(final Driver driver, final String connectUri, final Properties props) {
-        _driver = driver;
-        _connectUri = connectUri;
-        _props = props;
+
+    private final String connectionString;
+    private final Driver driver;
+    private final Properties properties;
+
+    /**
+     * Constructs a connection factory for a given Driver.
+     *
+     * @param driver
+     *            The Driver.
+     * @param connectString
+     *            The connection string.
+     * @param properties
+     *            The connection properties.
+     */
+    public DriverConnectionFactory(final Driver driver, final String connectString, final Properties properties) {
+        this.driver = driver;
+        this.connectionString = connectString;
+        this.properties = properties;
     }
 
     @Override
     public Connection createConnection() throws SQLException {
-        return _driver.connect(_connectUri,_props);
+        return driver.connect(connectionString, properties);
     }
 
-    private final Driver _driver;
-    private final String _connectUri;
-    private final Properties _props;
-
     @Override
     public String toString() {
-        return this.getClass().getName() + " [" + String.valueOf(_driver) + ";" +
-                String.valueOf(_connectUri) + ";"  + String.valueOf(_props) + "]";
+        return this.getClass().getName() + " [" + String.valueOf(driver) + ";" + String.valueOf(connectionString) + ";"
+                + String.valueOf(properties) + "]";
     }
 }
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/DriverManagerConnectionFactory.java b/java/org/apache/tomcat/dbcp/dbcp2/DriverManagerConnectionFactory.java
index cc40321..7b6b060 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/DriverManagerConnectionFactory.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/DriverManagerConnectionFactory.java
@@ -24,9 +24,6 @@
 /**
  * A {@link DriverManager}-based implementation of {@link ConnectionFactory}.
  *
- * @author Rodney Waldhoff
- * @author Ignacio J. Ortega
- * @author Dirk Verbeeck
  * @since 2.0
  */
 public class DriverManagerConnectionFactory implements ConnectionFactory {
@@ -40,57 +37,62 @@
         DriverManager.getDrivers();
     }
 
-
     /**
      * Constructor for DriverManagerConnectionFactory.
-     * @param connectUri a database url of the form
-     * <code> jdbc:<em>subprotocol</em>:<em>subname</em></code>
+     *
+     * @param connectionUri
+     *            a database url of the form <code> jdbc:<em>subprotocol</em>:<em>subname</em></code>
      * @since 2.2
      */
-    public DriverManagerConnectionFactory(final String connectUri) {
-        _connectUri = connectUri;
-        _props = new Properties();
+    public DriverManagerConnectionFactory(final String connectionUri) {
+        this.connectionUri = connectionUri;
+        this.propeties = new Properties();
     }
 
     /**
      * Constructor for DriverManagerConnectionFactory.
-     * @param connectUri a database url of the form
-     * <code> jdbc:<em>subprotocol</em>:<em>subname</em></code>
-     * @param props a list of arbitrary string tag/value pairs as
-     * connection arguments; normally at least a "user" and "password"
-     * property should be included.
+     *
+     * @param connectionUri
+     *            a database url of the form <code> jdbc:<em>subprotocol</em>:<em>subname</em></code>
+     * @param properties
+     *            a list of arbitrary string tag/value pairs as connection arguments; normally at least a "user" and
+     *            "password" property should be included.
      */
-    public DriverManagerConnectionFactory(final String connectUri, final Properties props) {
-        _connectUri = connectUri;
-        _props = props;
+    public DriverManagerConnectionFactory(final String connectionUri, final Properties properties) {
+        this.connectionUri = connectionUri;
+        this.propeties = properties;
     }
 
     /**
      * Constructor for DriverManagerConnectionFactory.
-     * @param connectUri a database url of the form
-     * <code>jdbc:<em>subprotocol</em>:<em>subname</em></code>
-     * @param uname the database user
-     * @param passwd the user's password
+     *
+     * @param connectionUri
+     *            a database url of the form <code>jdbc:<em>subprotocol</em>:<em>subname</em></code>
+     * @param userName
+     *            the database user
+     * @param userPassword
+     *            the user's password
      */
-    public DriverManagerConnectionFactory(final String connectUri, final String uname, final String passwd) {
-        _connectUri = connectUri;
-        _uname = uname;
-        _passwd = passwd;
+    public DriverManagerConnectionFactory(final String connectionUri, final String userName,
+            final String userPassword) {
+        this.connectionUri = connectionUri;
+        this.userName = userName;
+        this.userPassword = userPassword;
     }
 
     @Override
     public Connection createConnection() throws SQLException {
-        if(null == _props) {
-            if(_uname == null && _passwd == null) {
-                return DriverManager.getConnection(_connectUri);
+        if (null == propeties) {
+            if (userName == null && userPassword == null) {
+                return DriverManager.getConnection(connectionUri);
             }
-            return DriverManager.getConnection(_connectUri,_uname,_passwd);
+            return DriverManager.getConnection(connectionUri, userName, userPassword);
         }
-        return DriverManager.getConnection(_connectUri,_props);
+        return DriverManager.getConnection(connectionUri, propeties);
     }
 
-    private String _connectUri = null;
-    private String _uname = null;
-    private String _passwd = null;
-    private Properties _props = null;
+    private final String connectionUri;
+    private String userName;
+    private String userPassword;
+    private Properties propeties;
 }
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/LifetimeExceededException.java b/java/org/apache/tomcat/dbcp/dbcp2/LifetimeExceededException.java
index 0fb8fd7..31f8030 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/LifetimeExceededException.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/LifetimeExceededException.java
@@ -21,7 +21,7 @@
  *
  * @since 2.1
  */
- class LifetimeExceededException extends Exception {
+class LifetimeExceededException extends Exception {
 
     private static final long serialVersionUID = -3783783104516492659L;
 
@@ -34,6 +34,9 @@
 
     /**
      * Create a LifetimeExceededException with the given message.
+     *
+     * @param message
+     *            The message with which to create the exception
      */
     public LifetimeExceededException(final String message) {
         super(message);
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/ListException.java b/java/org/apache/tomcat/dbcp/dbcp2/ListException.java
new file mode 100644
index 0000000..1f6b8f7
--- /dev/null
+++ b/java/org/apache/tomcat/dbcp/dbcp2/ListException.java
@@ -0,0 +1,57 @@
+/*
+ * 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.tomcat.dbcp.dbcp2;
+
+import java.util.List;
+
+/**
+ * An exception wrapping a list of exceptions.
+ *
+ * @since 2.4.0
+ */
+public class ListException extends Exception {
+
+    private static final long serialVersionUID = 1L;
+
+    private final List<Throwable> exceptionList;
+
+    /**
+     * Constructs a new exception with the specified detail message. The cause is not initialized, and may subsequently
+     * be initialized by a call to {@link #initCause}.
+     *
+     * @param message
+     *            the detail message. The detail message is saved for later retrieval by the {@link #getMessage()}
+     *            method.
+     * @param exceptionList
+     *            a list of exceptions.
+     */
+    public ListException(final String message, final List<Throwable> exceptionList) {
+        super(message);
+        this.exceptionList = exceptionList;
+    }
+
+    /**
+     * Gets the list of exceptions.
+     *
+     * @return the list of exceptions.
+     */
+    public List<Throwable> getExceptionList() {
+        return exceptionList;
+    }
+
+}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/ObjectNameWrapper.java b/java/org/apache/tomcat/dbcp/dbcp2/ObjectNameWrapper.java
new file mode 100644
index 0000000..f036989
--- /dev/null
+++ b/java/org/apache/tomcat/dbcp/dbcp2/ObjectNameWrapper.java
@@ -0,0 +1,96 @@
+/*
+ * 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.tomcat.dbcp.dbcp2;
+
+import java.lang.management.ManagementFactory;
+
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+
+/**
+ * Internal wrapper class that allows JMX to be a noop if absent or disabled.
+ *
+ * @since 2.2.1
+ */
+class ObjectNameWrapper {
+
+    private static final Log log = LogFactory.getLog(ObjectNameWrapper.class);
+
+    private static MBeanServer MBEAN_SERVER = getPlatformMBeanServer();
+
+    private static MBeanServer getPlatformMBeanServer() {
+        try {
+            return ManagementFactory.getPlatformMBeanServer();
+        } catch (LinkageError | Exception e) {
+            // ignore - JMX not available
+            log.debug("Failed to get platform MBeanServer", e);
+            return null;
+        }
+    }
+
+    public static ObjectName unwrap(final ObjectNameWrapper wrapper) {
+        return wrapper == null ? null : wrapper.unwrap();
+    }
+
+    public static ObjectNameWrapper wrap(final ObjectName objectName) {
+        return new ObjectNameWrapper(objectName);
+    }
+
+    public static ObjectNameWrapper wrap(final String name) throws MalformedObjectNameException {
+        return wrap(new ObjectName(name));
+    }
+
+    private final ObjectName objectName;
+
+    public ObjectNameWrapper(final ObjectName objectName) {
+        this.objectName = objectName;
+    }
+
+    public void registerMBean(final Object object) {
+        if (MBEAN_SERVER == null || objectName == null) {
+            return;
+        }
+        try {
+            MBEAN_SERVER.registerMBean(object, objectName);
+        } catch (LinkageError | Exception e) {
+            log.warn("Failed to complete JMX registration for " + objectName, e);
+        }
+    }
+
+    public void unregisterMBean() {
+        if (MBEAN_SERVER == null || objectName == null) {
+            return;
+        }
+        if (MBEAN_SERVER.isRegistered(objectName)) {
+            try {
+                MBEAN_SERVER.unregisterMBean(objectName);
+            } catch (LinkageError | Exception e) {
+                log.warn("Failed to complete JMX unregistration for " + objectName, e);
+            }
+        }
+    }
+
+    public ObjectName unwrap() {
+        return objectName;
+    }
+
+}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/PStmtKey.java b/java/org/apache/tomcat/dbcp/dbcp2/PStmtKey.java
index f986d68..29cc510 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/PStmtKey.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/PStmtKey.java
@@ -26,201 +26,419 @@
 
 /**
  * A key uniquely identifying {@link java.sql.PreparedStatement PreparedStatement}s.
+ *
  * @since 2.0
  */
 public class PStmtKey {
 
-    /** SQL defining Prepared or Callable Statement */
-    private final String _sql;
+    /**
+     * SQL defining Prepared or Callable Statement
+     */
+    private final String sql;
 
-    /** Result set type */
-    private final Integer _resultSetType;
+    /**
+     * Result set type; one of <code>ResultSet.TYPE_FORWARD_ONLY</code>, <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>,
+     * or <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>.
+     */
+    private final Integer resultSetType;
 
-    /** Result set concurrency */
-    private final Integer _resultSetConcurrency;
+    /**
+     * Result set concurrency. A concurrency type; one of <code>ResultSet.CONCUR_READ_ONLY</code> or
+     * <code>ResultSet.CONCUR_UPDATABLE</code>.
+     */
+    private final Integer resultSetConcurrency;
 
-    /** Result set holdability */
-    private final Integer _resultSetHoldability;
+    /**
+     * Result set holdability. One of the following <code>ResultSet</code> constants:
+     * <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>.
+     */
+    private final Integer resultSetHoldability;
 
     /** Database catalog */
-    private final String _catalog;
+    private final String catalog;
 
-    /** Auto generated keys */
-    private final Integer _autoGeneratedKeys;
+    /**
+     * A flag indicating whether auto-generated keys should be returned; one of
+     * <code>Statement.RETURN_GENERATED_KEYS</code> or <code>Statement.NO_GENERATED_KEYS</code>.
+     */
+    private final Integer autoGeneratedKeys;
 
-    /** column indexes */
-    private final int[] _columnIndexes;
+    /**
+     * An array of column indexes indicating the columns that should be returned from the inserted row or rows.
+     */
+    private final int[] columnIndexes;
 
-    /** column names */
-    private final String[] _columnNames;
+    /**
+     * An array of column names indicating the columns that should be returned from the inserted row or rows.
+     */
+    private final String[] columnNames;
 
-    /** Statement type */
-    private final StatementType _stmtType;
+    /**
+     * Statement type, prepared or callable.
+     */
+    private final StatementType statementType;
 
     /** Statement builder */
     private StatementBuilder builder;
 
+    /**
+     * Constructs a key to uniquely identify a prepared statement.
+     *
+     * @param sql
+     *            The SQL statement.
+     */
     public PStmtKey(final String sql) {
         this(sql, null, StatementType.PREPARED_STATEMENT);
     }
 
+    /**
+     * Constructs a key to uniquely identify a prepared statement.
+     *
+     * @param sql
+     *            The SQL statement.
+     * @param catalog
+     *            The catalog.
+     */
     public PStmtKey(final String sql, final String catalog) {
         this(sql, catalog, StatementType.PREPARED_STATEMENT);
     }
 
-    public PStmtKey(final String sql, final String catalog, final StatementType stmtType) {
-        _sql = sql;
-        _catalog = catalog;
-        _stmtType = stmtType;
-        _autoGeneratedKeys = null;
-        _columnIndexes = null;
-        _columnNames = null;
-        _resultSetType = null;
-        _resultSetConcurrency = null;
-        _resultSetHoldability = null;
+    /**
+     * Constructs a key to uniquely identify a prepared statement.
+     *
+     * @param sql
+     *            The SQL statement.
+     * @param catalog
+     *            The catalog.
+     * @param statementType
+     *            The SQL statement type, prepared or callable.
+     */
+    public PStmtKey(final String sql, final String catalog, final StatementType statementType) {
+        this.sql = sql;
+        this.catalog = catalog;
+        this.statementType = statementType;
+        this.autoGeneratedKeys = null;
+        this.columnIndexes = null;
+        this.columnNames = null;
+        this.resultSetType = null;
+        this.resultSetConcurrency = null;
+        this.resultSetHoldability = null;
         // create builder
-        if (stmtType == StatementType.PREPARED_STATEMENT) {
-            builder = new PreparedStatementSQL();
-        } else if (stmtType == StatementType.CALLABLE_STATEMENT) {
-            builder = new PreparedCallSQL();
+        if (statementType == StatementType.PREPARED_STATEMENT) {
+            this.builder = new PreparedStatementSQL();
+        } else if (statementType == StatementType.CALLABLE_STATEMENT) {
+            this.builder = new PreparedCallSQL();
         }
     }
 
+    /**
+     * Constructs a key to uniquely identify a prepared statement.
+     *
+     * @param sql
+     *            The SQL statement.
+     * @param catalog
+     *            The catalog.
+     * @param autoGeneratedKeys
+     *            A flag indicating whether auto-generated keys should be returned; one of
+     *            <code>Statement.RETURN_GENERATED_KEYS</code> or <code>Statement.NO_GENERATED_KEYS</code>.
+     */
     public PStmtKey(final String sql, final String catalog, final int autoGeneratedKeys) {
         this(sql, catalog, StatementType.PREPARED_STATEMENT, Integer.valueOf(autoGeneratedKeys));
     }
 
-    public PStmtKey(final String sql, final String catalog, final StatementType stmtType, final Integer autoGeneratedKeys) {
-        _sql = sql;
-        _catalog = catalog;
-        _stmtType = stmtType;
-        _autoGeneratedKeys = autoGeneratedKeys;
-        _columnIndexes = null;
-        _columnNames = null;
-        _resultSetType = null;
-        _resultSetConcurrency = null;
-        _resultSetHoldability = null;
+    /**
+     * Constructs a key to uniquely identify a prepared statement.
+     *
+     * @param sql
+     *            The SQL statement.
+     * @param catalog
+     *            The catalog.
+     * @param statementType
+     *            The SQL statement type, prepared or callable.
+     * @param autoGeneratedKeys
+     *            A flag indicating whether auto-generated keys should be returned; one of
+     *            <code>Statement.RETURN_GENERATED_KEYS</code> or <code>Statement.NO_GENERATED_KEYS</code>.
+     */
+    public PStmtKey(final String sql, final String catalog, final StatementType statementType,
+            final Integer autoGeneratedKeys) {
+        this.sql = sql;
+        this.catalog = catalog;
+        this.statementType = statementType;
+        this.autoGeneratedKeys = autoGeneratedKeys;
+        this.columnIndexes = null;
+        this.columnNames = null;
+        this.resultSetType = null;
+        this.resultSetConcurrency = null;
+        this.resultSetHoldability = null;
         // create builder
-        if (stmtType == StatementType.PREPARED_STATEMENT) {
-            builder = new PreparedStatementWithAutoGeneratedKeys();
-        } else if (stmtType == StatementType.CALLABLE_STATEMENT) {
-            builder = new PreparedCallSQL();
+        if (statementType == StatementType.PREPARED_STATEMENT) {
+            this.builder = new PreparedStatementWithAutoGeneratedKeys();
+        } else if (statementType == StatementType.CALLABLE_STATEMENT) {
+            this.builder = new PreparedCallSQL();
         }
     }
 
+    /**
+     * Constructs a key to uniquely identify a prepared statement.
+     *
+     * @param sql
+     *            The SQL statement.
+     * @param catalog
+     *            The catalog.
+     * @param columnIndexes
+     *            An array of column indexes indicating the columns that should be returned from the inserted row or
+     *            rows.
+     */
     public PStmtKey(final String sql, final String catalog, final int[] columnIndexes) {
-        _sql = sql;
-        _catalog = catalog;
-        _stmtType = StatementType.PREPARED_STATEMENT;
-        _autoGeneratedKeys = null;
-        _columnIndexes = columnIndexes;
-        _columnNames = null;
-        _resultSetType = null;
-        _resultSetConcurrency = null;
-        _resultSetHoldability = null;
+        this.sql = sql;
+        this.catalog = catalog;
+        this.statementType = StatementType.PREPARED_STATEMENT;
+        this.autoGeneratedKeys = null;
+        this.columnIndexes = columnIndexes == null ? null : Arrays.copyOf(columnIndexes, columnIndexes.length);
+        this.columnNames = null;
+        this.resultSetType = null;
+        this.resultSetConcurrency = null;
+        this.resultSetHoldability = null;
         // create builder
-        builder = new PreparedStatementWithColumnIndexes();
+        this.builder = new PreparedStatementWithColumnIndexes();
     }
 
+    /**
+     * Constructs a key to uniquely identify a prepared statement.
+     *
+     * @param sql
+     *            The SQL statement.
+     * @param catalog
+     *            The catalog.
+     * @param columnNames
+     *            An array of column names indicating the columns that should be returned from the inserted row or rows.
+     */
     public PStmtKey(final String sql, final String catalog, final String[] columnNames) {
-        _sql = sql;
-        _catalog = catalog;
-        _stmtType = StatementType.PREPARED_STATEMENT;
-        _autoGeneratedKeys = null;
-        _columnIndexes = null;
-        _columnNames = columnNames;
-        _resultSetType = null;
-        _resultSetConcurrency = null;
-        _resultSetHoldability = null;
+        this.sql = sql;
+        this.catalog = catalog;
+        this.statementType = StatementType.PREPARED_STATEMENT;
+        this.autoGeneratedKeys = null;
+        this.columnIndexes = null;
+        this.columnNames = columnNames == null ? null : Arrays.copyOf(columnNames, columnNames.length);
+        this.resultSetType = null;
+        this.resultSetConcurrency = null;
+        this.resultSetHoldability = null;
         // create builder
         builder = new PreparedStatementWithColumnNames();
     }
 
-    public  PStmtKey(final String sql, final int resultSetType, final int resultSetConcurrency) {
+    /**
+     * Constructs a key to uniquely identify a prepared statement.
+     *
+     * @param sql
+     *            The SQL statement.
+     * @param resultSetType
+     *            A result set type; one of <code>ResultSet.TYPE_FORWARD_ONLY</code>,
+     *            <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>.
+     * @param resultSetConcurrency
+     *            A concurrency type; one of <code>ResultSet.CONCUR_READ_ONLY</code> or
+     *            <code>ResultSet.CONCUR_UPDATABLE</code>.
+     */
+    public PStmtKey(final String sql, final int resultSetType, final int resultSetConcurrency) {
         this(sql, null, resultSetType, resultSetConcurrency, StatementType.PREPARED_STATEMENT);
     }
 
+    /**
+     * Constructs a key to uniquely identify a prepared statement.
+     *
+     * @param sql
+     *            The SQL statement.
+     * @param catalog
+     *            The catalog.
+     * @param resultSetType
+     *            A result set type; one of <code>ResultSet.TYPE_FORWARD_ONLY</code>,
+     *            <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>.
+     * @param resultSetConcurrency
+     *            A concurrency type; one of <code>ResultSet.CONCUR_READ_ONLY</code> or
+     *            <code>ResultSet.CONCUR_UPDATABLE</code>.
+     */
     public PStmtKey(final String sql, final String catalog, final int resultSetType, final int resultSetConcurrency) {
         this(sql, catalog, resultSetType, resultSetConcurrency, StatementType.PREPARED_STATEMENT);
     }
 
-    public PStmtKey(final String sql, final String catalog, final int resultSetType, final int resultSetConcurrency, final StatementType stmtType) {
-        _sql = sql;
-        _catalog = catalog;
-        _resultSetType = Integer.valueOf(resultSetType);
-        _resultSetConcurrency = Integer.valueOf(resultSetConcurrency);
-        _resultSetHoldability = null;
-        _stmtType = stmtType;
-        _autoGeneratedKeys = null;
-        _columnIndexes = null;
-        _columnNames = null;
+    /**
+     * Constructs a key to uniquely identify a prepared statement.
+     *
+     * @param sql
+     *            The SQL statement.
+     * @param catalog
+     *            The catalog.
+     * @param resultSetType
+     *            A result set type; one of <code>ResultSet.TYPE_FORWARD_ONLY</code>,
+     *            <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>.
+     * @param resultSetConcurrency
+     *            A concurrency type; one of <code>ResultSet.CONCUR_READ_ONLY</code> or
+     *            <code>ResultSet.CONCUR_UPDATABLE</code>.
+     * @param statementType
+     *            The SQL statement type, prepared or callable.
+     */
+    public PStmtKey(final String sql, final String catalog, final int resultSetType, final int resultSetConcurrency,
+            final StatementType statementType) {
+        this.sql = sql;
+        this.catalog = catalog;
+        this.resultSetType = Integer.valueOf(resultSetType);
+        this.resultSetConcurrency = Integer.valueOf(resultSetConcurrency);
+        this.resultSetHoldability = null;
+        this.statementType = statementType;
+        this.autoGeneratedKeys = null;
+        this.columnIndexes = null;
+        this.columnNames = null;
         // create builder
-        if (stmtType == StatementType.PREPARED_STATEMENT) {
-            builder = new PreparedStatementWithResultSetConcurrency();
-        } else if (stmtType == StatementType.CALLABLE_STATEMENT) {
-            builder = new PreparedCallWithResultSetConcurrency();
+        if (statementType == StatementType.PREPARED_STATEMENT) {
+            this.builder = new PreparedStatementWithResultSetConcurrency();
+        } else if (statementType == StatementType.CALLABLE_STATEMENT) {
+            this.builder = new PreparedCallWithResultSetConcurrency();
         }
     }
 
+    /**
+     * Constructs a key to uniquely identify a prepared statement.
+     *
+     * @param sql
+     *            The SQL statement.
+     * @param catalog
+     *            The catalog.
+     * @param resultSetType
+     *            a result set type; one of <code>ResultSet.TYPE_FORWARD_ONLY</code>,
+     *            <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>.
+     * @param resultSetConcurrency
+     *            A concurrency type; one of <code>ResultSet.CONCUR_READ_ONLY</code> or
+     *            <code>ResultSet.CONCUR_UPDATABLE</code>
+     * @param resultSetHoldability
+     *            One of the following <code>ResultSet</code> constants: <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code>
+     *            or <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>.
+     */
     public PStmtKey(final String sql, final String catalog, final int resultSetType, final int resultSetConcurrency,
             final int resultSetHoldability) {
         this(sql, catalog, resultSetType, resultSetConcurrency, resultSetHoldability, StatementType.PREPARED_STATEMENT);
     }
 
+    /**
+     * Constructs a key to uniquely identify a prepared statement.
+     *
+     * @param sql
+     *            The SQL statement.
+     * @param catalog
+     *            The catalog.
+     * @param resultSetType
+     *            a result set type; one of <code>ResultSet.TYPE_FORWARD_ONLY</code>,
+     *            <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
+     * @param resultSetConcurrency
+     *            A concurrency type; one of <code>ResultSet.CONCUR_READ_ONLY</code> or
+     *            <code>ResultSet.CONCUR_UPDATABLE</code>.
+     * @param resultSetHoldability
+     *            One of the following <code>ResultSet</code> constants: <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code>
+     *            or <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>.
+     * @param statementType
+     *            The SQL statement type, prepared or callable.
+     */
     public PStmtKey(final String sql, final String catalog, final int resultSetType, final int resultSetConcurrency,
-            final int resultSetHoldability, final StatementType stmtType) {
-        _sql = sql;
-        _catalog = catalog;
-        _resultSetType = Integer.valueOf(resultSetType);
-        _resultSetConcurrency = Integer.valueOf(resultSetConcurrency);
-        _resultSetHoldability = Integer.valueOf(resultSetHoldability);
-        _stmtType = stmtType;
-        _autoGeneratedKeys = null;
-        _columnIndexes = null;
-        _columnNames = null;
+            final int resultSetHoldability, final StatementType statementType) {
+        this.sql = sql;
+        this.catalog = catalog;
+        this.resultSetType = Integer.valueOf(resultSetType);
+        this.resultSetConcurrency = Integer.valueOf(resultSetConcurrency);
+        this.resultSetHoldability = Integer.valueOf(resultSetHoldability);
+        this.statementType = statementType;
+        this.autoGeneratedKeys = null;
+        this.columnIndexes = null;
+        this.columnNames = null;
         // create builder
-        if (stmtType == StatementType.PREPARED_STATEMENT) {
-            builder = new PreparedStatementWithResultSetHoldability();
-        } else if (stmtType == StatementType.CALLABLE_STATEMENT) {
-            builder = new PreparedCallWithResultSetHoldability();
+        if (statementType == StatementType.PREPARED_STATEMENT) {
+            this.builder = new PreparedStatementWithResultSetHoldability();
+        } else if (statementType == StatementType.CALLABLE_STATEMENT) {
+            this.builder = new PreparedCallWithResultSetHoldability();
         }
     }
 
-
+    /**
+     * Gets the SQL statement.
+     *
+     * @return the SQL statement.
+     */
     public String getSql() {
-        return _sql;
+        return sql;
     }
 
+    /**
+     * Gets the result set type, one of <code>ResultSet.TYPE_FORWARD_ONLY</code>,
+     * <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>.
+     *
+     * @return the result set type.
+     */
     public Integer getResultSetType() {
-        return _resultSetType;
+        return resultSetType;
     }
 
+    /**
+     * Gets the result set concurrency type; one of <code>ResultSet.CONCUR_READ_ONLY</code> or
+     * <code>ResultSet.CONCUR_UPDATABLE</code>.
+     *
+     * @return The result set concurrency type.
+     */
     public Integer getResultSetConcurrency() {
-        return _resultSetConcurrency;
+        return resultSetConcurrency;
     }
 
+    /**
+     * Gets the result set holdability, one of the following <code>ResultSet</code> constants:
+     * <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>.
+     *
+     * @return The result set holdability.
+     */
     public Integer getResultSetHoldability() {
-        return _resultSetHoldability;
+        return resultSetHoldability;
     }
 
+    /**
+     * Gets a flag indicating whether auto-generated keys should be returned; one of
+     * <code>Statement.RETURN_GENERATED_KEYS</code> or <code>Statement.NO_GENERATED_KEYS</code>.
+     *
+     * @return a flag indicating whether auto-generated keys should be returned.
+     */
     public Integer getAutoGeneratedKeys() {
-        return _autoGeneratedKeys;
+        return autoGeneratedKeys;
     }
 
+    /**
+     * Gets an array of column indexes indicating the columns that should be returned from the inserted row or rows.
+     *
+     * @return An array of column indexes.
+     */
     public int[] getColumnIndexes() {
-        return _columnIndexes;
+        return columnIndexes;
     }
 
+    /**
+     * Gets an array of column names indicating the columns that should be returned from the inserted row or rows.
+     *
+     * @return An array of column names.
+     */
     public String[] getColumnNames() {
-        return _columnNames;
+        return columnNames;
     }
 
+    /**
+     * The catalog.
+     *
+     * @return The catalog.
+     */
     public String getCatalog() {
-        return _catalog;
+        return catalog;
     }
 
+    /**
+     * The SQL statement type.
+     *
+     * @return The SQL statement type.
+     */
     public StatementType getStmtType() {
-        return _stmtType;
+        return statementType;
     }
 
     @Override
@@ -235,55 +453,55 @@
             return false;
         }
         final PStmtKey other = (PStmtKey) obj;
-        if (_catalog == null) {
-            if (other._catalog != null) {
+        if (catalog == null) {
+            if (other.catalog != null) {
                 return false;
             }
-        } else if (!_catalog.equals(other._catalog)) {
+        } else if (!catalog.equals(other.catalog)) {
             return false;
         }
-        if (_resultSetConcurrency == null) {
-            if (other._resultSetConcurrency != null) {
+        if (resultSetConcurrency == null) {
+            if (other.resultSetConcurrency != null) {
                 return false;
             }
-        } else if (!_resultSetConcurrency.equals(other._resultSetConcurrency)) {
+        } else if (!resultSetConcurrency.equals(other.resultSetConcurrency)) {
             return false;
         }
-        if (_resultSetType == null) {
-            if (other._resultSetType != null) {
+        if (resultSetType == null) {
+            if (other.resultSetType != null) {
                 return false;
             }
-        } else if (!_resultSetType.equals(other._resultSetType)) {
+        } else if (!resultSetType.equals(other.resultSetType)) {
             return false;
         }
-        if (_resultSetHoldability == null) {
-            if (other._resultSetHoldability != null) {
+        if (resultSetHoldability == null) {
+            if (other.resultSetHoldability != null) {
                 return false;
             }
-        } else if (!_resultSetHoldability.equals(other._resultSetHoldability)) {
+        } else if (!resultSetHoldability.equals(other.resultSetHoldability)) {
             return false;
         }
-        if (_autoGeneratedKeys == null) {
-            if (other._autoGeneratedKeys != null) {
+        if (autoGeneratedKeys == null) {
+            if (other.autoGeneratedKeys != null) {
                 return false;
             }
-        } else if (!_autoGeneratedKeys.equals(other._autoGeneratedKeys)) {
+        } else if (!autoGeneratedKeys.equals(other.autoGeneratedKeys)) {
             return false;
         }
-        if (!Arrays.equals(_columnIndexes, other._columnIndexes)) {
+        if (!Arrays.equals(columnIndexes, other.columnIndexes)) {
             return false;
         }
-        if (!Arrays.equals(_columnNames, other._columnNames)) {
+        if (!Arrays.equals(columnNames, other.columnNames)) {
             return false;
         }
-        if (_sql == null) {
-            if (other._sql != null) {
+        if (sql == null) {
+            if (other.sql != null) {
                 return false;
             }
-        } else if (!_sql.equals(other._sql)) {
+        } else if (!sql.equals(other.sql)) {
             return false;
         }
-        if (_stmtType != other._stmtType) {
+        if (statementType != other.statementType) {
             return false;
         }
         return true;
@@ -293,15 +511,15 @@
     public int hashCode() {
         final int prime = 31;
         int result = 1;
-        result = prime * result + (_catalog == null ? 0 : _catalog.hashCode());
-        result = prime * result + (_resultSetConcurrency == null ? 0 : _resultSetConcurrency.hashCode());
-        result = prime * result + (_resultSetType == null ? 0 : _resultSetType.hashCode());
-        result = prime * result + (_resultSetHoldability == null ? 0 : _resultSetHoldability.hashCode());
-        result = prime * result + (_sql == null ? 0 : _sql.hashCode());
-        result = prime * result + (_autoGeneratedKeys == null ? 0 : _autoGeneratedKeys.hashCode());
-        result = prime * result + Arrays.hashCode(_columnIndexes);
-        result = prime * result + Arrays.hashCode(_columnNames);
-        result = prime * result + _stmtType.hashCode();
+        result = prime * result + (catalog == null ? 0 : catalog.hashCode());
+        result = prime * result + (resultSetConcurrency == null ? 0 : resultSetConcurrency.hashCode());
+        result = prime * result + (resultSetType == null ? 0 : resultSetType.hashCode());
+        result = prime * result + (resultSetHoldability == null ? 0 : resultSetHoldability.hashCode());
+        result = prime * result + (sql == null ? 0 : sql.hashCode());
+        result = prime * result + (autoGeneratedKeys == null ? 0 : autoGeneratedKeys.hashCode());
+        result = prime * result + Arrays.hashCode(columnIndexes);
+        result = prime * result + Arrays.hashCode(columnNames);
+        result = prime * result + statementType.hashCode();
         return result;
     }
 
@@ -309,26 +527,35 @@
     public String toString() {
         final StringBuffer buf = new StringBuffer();
         buf.append("PStmtKey: sql=");
-        buf.append(_sql);
+        buf.append(sql);
         buf.append(", catalog=");
-        buf.append(_catalog);
+        buf.append(catalog);
         buf.append(", resultSetType=");
-        buf.append(_resultSetType);
+        buf.append(resultSetType);
         buf.append(", resultSetConcurrency=");
-        buf.append(_resultSetConcurrency);
+        buf.append(resultSetConcurrency);
         buf.append(", resultSetHoldability=");
-        buf.append(_resultSetHoldability);
+        buf.append(resultSetHoldability);
         buf.append(", autoGeneratedKeys=");
-        buf.append(_autoGeneratedKeys);
+        buf.append(autoGeneratedKeys);
         buf.append(", columnIndexes=");
-        buf.append(Arrays.toString(_columnIndexes));
+        buf.append(Arrays.toString(columnIndexes));
         buf.append(", columnNames=");
-        buf.append(Arrays.toString(_columnNames));
+        buf.append(Arrays.toString(columnNames));
         buf.append(", statementType=");
-        buf.append(_stmtType);
+        buf.append(statementType);
         return buf.toString();
     }
 
+    /**
+     * Creates a new Statement from the given Connection.
+     *
+     * @param connection
+     *            The Connection to use to create the statement.
+     * @return The statement.
+     * @throws SQLException
+     *             Thrown when there is a problem creating the statement.
+     */
     public Statement createStatement(final Connection connection) throws SQLException {
         if (builder == null) {
             throw new IllegalStateException("Prepared statement key is invalid.");
@@ -337,116 +564,111 @@
     }
 
     /**
-     * Interface for Prepared or Callable Statement
+     * Interface for Prepared or Callable Statement.
      */
     private interface StatementBuilder {
         public Statement createStatement(Connection connection) throws SQLException;
     }
 
     /**
-     * Builder for prepareStatement(String sql)
+     * Builder for prepareStatement(String sql).
      */
     private class PreparedStatementSQL implements StatementBuilder {
         @Override
         public Statement createStatement(final Connection connection) throws SQLException {
-            final PreparedStatement statement = connection.prepareStatement(_sql);
+            final PreparedStatement statement = connection.prepareStatement(sql);
             return statement;
         }
     }
 
     /**
-     * Builder for prepareStatement(String sql, int autoGeneratedKeys)
+     * Builder for prepareStatement(String sql, int autoGeneratedKeys).
      */
     private class PreparedStatementWithAutoGeneratedKeys implements StatementBuilder {
         @Override
         public Statement createStatement(final Connection connection) throws SQLException {
-            final PreparedStatement statement = connection.prepareStatement(
-                    _sql, _autoGeneratedKeys.intValue());
+            final PreparedStatement statement = connection.prepareStatement(sql, autoGeneratedKeys.intValue());
             return statement;
         }
     }
 
     /**
-     * Builder for prepareStatement(String sql, int[] columnIndexes)
+     * Builder for prepareStatement(String sql, int[] columnIndexes).
      */
     private class PreparedStatementWithColumnIndexes implements StatementBuilder {
         @Override
         public Statement createStatement(final Connection connection) throws SQLException {
-            final PreparedStatement statement = connection.prepareStatement(
-                    _sql, _columnIndexes);
+            final PreparedStatement statement = connection.prepareStatement(sql, columnIndexes);
             return statement;
         }
     }
 
     /**
-     * Builder for prepareStatement(String sql, int resultSetType, int resultSetConcurrency)
+     * Builder for prepareStatement(String sql, int resultSetType, int resultSetConcurrency).
      */
     private class PreparedStatementWithResultSetConcurrency implements StatementBuilder {
         @Override
         public Statement createStatement(final Connection connection) throws SQLException {
-            final PreparedStatement statement = connection.prepareStatement(
-                    _sql, _resultSetType.intValue(), _resultSetConcurrency.intValue());
+            final PreparedStatement statement = connection.prepareStatement(sql, resultSetType.intValue(),
+                    resultSetConcurrency.intValue());
             return statement;
         }
     }
 
     /**
-     * Builder for prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability)
+     * Builder for prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability).
      */
     private class PreparedStatementWithResultSetHoldability implements StatementBuilder {
         @Override
         public Statement createStatement(final Connection connection) throws SQLException {
-            final PreparedStatement statement = connection.prepareStatement(
-                    _sql, _resultSetType.intValue(), _resultSetConcurrency.intValue(),
-                    _resultSetHoldability.intValue());
+            final PreparedStatement statement = connection.prepareStatement(sql, resultSetType.intValue(),
+                    resultSetConcurrency.intValue(), resultSetHoldability.intValue());
             return statement;
         }
     }
 
     /**
-     * Builder for prepareStatement(String sql, String[] columnNames)
+     * Builder for prepareStatement(String sql, String[] columnNames).
      */
     private class PreparedStatementWithColumnNames implements StatementBuilder {
         @Override
         public Statement createStatement(final Connection connection) throws SQLException {
-            final PreparedStatement statement = connection.prepareStatement(
-                    _sql, _columnNames);
+            final PreparedStatement statement = connection.prepareStatement(sql, columnNames);
             return statement;
         }
     }
 
     /**
-     * Builder for prepareCall(String sql)
+     * Builder for prepareCall(String sql).
      */
     private class PreparedCallSQL implements StatementBuilder {
         @Override
         public Statement createStatement(final Connection connection) throws SQLException {
-            final PreparedStatement statement = connection.prepareCall(_sql);
+            final PreparedStatement statement = connection.prepareCall(sql);
             return statement;
         }
     }
 
     /**
-     * Builder for prepareCall(String sql, int resultSetType, int resultSetConcurrency)
+     * Builder for prepareCall(String sql, int resultSetType, int resultSetConcurrency).
      */
     private class PreparedCallWithResultSetConcurrency implements StatementBuilder {
         @Override
         public Statement createStatement(final Connection connection) throws SQLException {
-            final PreparedStatement statement = connection.prepareCall(
-                    _sql, _resultSetType.intValue(), _resultSetConcurrency.intValue());
+            final PreparedStatement statement = connection.prepareCall(sql, resultSetType.intValue(),
+                    resultSetConcurrency.intValue());
             return statement;
         }
     }
 
     /**
-     * Builder for prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability)
+     * Builder for prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability).
      */
     private class PreparedCallWithResultSetHoldability implements StatementBuilder {
         @Override
         public Statement createStatement(final Connection connection) throws SQLException {
-            final PreparedStatement statement = connection.prepareCall(
-                    _sql, _resultSetType.intValue(), _resultSetConcurrency.intValue(),
-                    _resultSetHoldability.intValue());
+            final PreparedStatement statement = connection.prepareCall(sql, resultSetType.intValue(),
+                    resultSetConcurrency.intValue(), resultSetHoldability.intValue());
             return statement;
         }
     }
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/PoolableCallableStatement.java b/java/org/apache/tomcat/dbcp/dbcp2/PoolableCallableStatement.java
index 9fb2bfd..486da28 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/PoolableCallableStatement.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/PoolableCallableStatement.java
@@ -26,8 +26,8 @@
 import org.apache.tomcat.dbcp.pool2.KeyedObjectPool;
 
 /**
- * A {@link DelegatingCallableStatement} that cooperates with
- * {@link PoolingConnection} to implement a pool of {@link CallableStatement}s.
+ * A {@link DelegatingCallableStatement} that cooperates with {@link PoolingConnection} to implement a pool of
+ * {@link CallableStatement}s.
  * <p>
  * The {@link #close} method returns this statement to its containing pool. (See {@link PoolingConnection}.)
  *
@@ -39,75 +39,83 @@
     /**
      * The {@link KeyedObjectPool} from which this CallableStatement was obtained.
      */
-    private final KeyedObjectPool<PStmtKey,DelegatingPreparedStatement> _pool;
+    private final KeyedObjectPool<PStmtKey, DelegatingPreparedStatement> pool;
 
     /**
      * Key for this statement in the containing {@link KeyedObjectPool}.
      */
-    private final PStmtKey _key;
+    private final PStmtKey key;
 
     /**
      * Constructor.
      *
-     * @param stmt the underlying {@link CallableStatement}
-     * @param key the key for this statement in the {@link KeyedObjectPool}
-     * @param pool the {@link KeyedObjectPool} from which this CallableStatement was obtained
-     * @param conn the {@link DelegatingConnection} that created this CallableStatement
+     * @param callableStatement
+     *            the underlying {@link CallableStatement}
+     * @param key
+     *            the key for this statement in the {@link KeyedObjectPool}
+     * @param pool
+     *            the {@link KeyedObjectPool} from which this CallableStatement was obtained
+     * @param connection
+     *            the {@link DelegatingConnection} that created this CallableStatement
      */
-    public PoolableCallableStatement(final CallableStatement stmt, final PStmtKey key,
-            final KeyedObjectPool<PStmtKey,DelegatingPreparedStatement> pool,
-            final DelegatingConnection<Connection> conn) {
-        super(conn, stmt);
-        _pool = pool;
-        _key = key;
+    public PoolableCallableStatement(final CallableStatement callableStatement, final PStmtKey key,
+            final KeyedObjectPool<PStmtKey, DelegatingPreparedStatement> pool,
+            final DelegatingConnection<Connection> connection) {
+        super(connection, callableStatement);
+        this.pool = pool;
+        this.key = key;
 
         // Remove from trace now because this statement will be
         // added by the activate method.
-        if(getConnectionInternal() != null) {
+        if (getConnectionInternal() != null) {
             getConnectionInternal().removeTrace(this);
         }
     }
 
     /**
-     * Returns the CallableStatement to the pool.  If {{@link #isClosed()}, this is a No-op.
+     * Returns the CallableStatement to the pool. If {{@link #isClosed()}, this is a No-op.
      */
     @Override
     public void close() throws SQLException {
         // calling close twice should have no effect
         if (!isClosed()) {
             try {
-                _pool.returnObject(_key,this);
-            } catch(final SQLException e) {
+                pool.returnObject(key, this);
+            } catch (final SQLException e) {
                 throw e;
-            } catch(final RuntimeException e) {
+            } catch (final RuntimeException e) {
                 throw e;
-            } catch(final Exception e) {
+            } catch (final Exception e) {
                 throw new SQLException("Cannot close CallableStatement (return to pool failed)", e);
             }
         }
     }
 
     /**
-     * Activates after retrieval from the pool. Adds a trace for this CallableStatement to the Connection
-     * that created it.
+     * Activates after retrieval from the pool. Adds a trace for this CallableStatement to the Connection that created
+     * it.
+     *
+     * @since 2.4.0 made public, was protected in 2.3.0.
      */
     @Override
-    protected void activate() throws SQLException {
+    public void activate() throws SQLException {
         setClosedInternal(false);
-        if( getConnectionInternal() != null ) {
-            getConnectionInternal().addTrace( this );
+        if (getConnectionInternal() != null) {
+            getConnectionInternal().addTrace(this);
         }
         super.activate();
     }
 
     /**
-     * Passivates to prepare for return to the pool.  Removes the trace associated with this CallableStatement
-     * from the Connection that created it.  Also closes any associated ResultSets.
+     * Passivates to prepare for return to the pool. Removes the trace associated with this CallableStatement from the
+     * Connection that created it. Also closes any associated ResultSets.
+     *
+     * @since 2.4.0 made public, was protected in 2.3.0.
      */
     @Override
-    protected void passivate() throws SQLException {
+    public void passivate() throws SQLException {
         setClosedInternal(true);
-        if( getConnectionInternal() != null ) {
+        if (getConnectionInternal() != null) {
             getConnectionInternal().removeTrace(this);
         }
 
@@ -116,7 +124,7 @@
         // FIXME The PreparedStatement we're wrapping should handle this for us.
         // See DBCP-10 for what could happen when ResultSets are closed twice.
         final List<AbandonedTrace> resultSets = getTrace();
-        if(resultSets != null) {
+        if (resultSets != null) {
             final ResultSet[] set = resultSets.toArray(new ResultSet[resultSets.size()]);
             for (final ResultSet element : set) {
                 element.close();
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnection.java b/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnection.java
index dddf78e..d383c6a 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnection.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnection.java
@@ -24,7 +24,6 @@
 import java.util.Collection;
 
 import javax.management.InstanceAlreadyExistsException;
-import javax.management.InstanceNotFoundException;
 import javax.management.MBeanRegistrationException;
 import javax.management.MBeanServer;
 import javax.management.NotCompliantMBeanException;
@@ -33,19 +32,14 @@
 import org.apache.tomcat.dbcp.pool2.ObjectPool;
 
 /**
- * A delegating connection that, rather than closing the underlying
- * connection, returns itself to an {@link ObjectPool} when
- * closed.
+ * A delegating connection that, rather than closing the underlying connection, returns itself to an {@link ObjectPool}
+ * when closed.
  *
- * @author Rodney Waldhoff
- * @author Glenn L. Nielsen
- * @author James House
  * @since 2.0
  */
-public class PoolableConnection extends DelegatingConnection<Connection>
-        implements PoolableConnectionMXBean {
+public class PoolableConnection extends DelegatingConnection<Connection> implements PoolableConnectionMXBean {
 
-    private static MBeanServer MBEAN_SERVER = null;
+    private static MBeanServer MBEAN_SERVER;
 
     static {
         try {
@@ -56,70 +50,75 @@
     }
 
     /** The pool to which I should return. */
-    private final ObjectPool<PoolableConnection> _pool;
+    private final ObjectPool<PoolableConnection> pool;
 
-    private final ObjectName _jmxName;
+    private final ObjectNameWrapper jmxObjectName;
 
     // Use a prepared statement for validation, retaining the last used SQL to
     // check if the validation query has changed.
-    private PreparedStatement validationPreparedStatement = null;
-    private String lastValidationSql = null;
+    private PreparedStatement validationPreparedStatement;
+    private String lastValidationSql;
 
     /**
-     *  Indicate that unrecoverable SQLException was thrown when using this connection.
-     *  Such a connection should be considered broken and not pass validation in the future.
+     * Indicate that unrecoverable SQLException was thrown when using this connection. Such a connection should be
+     * considered broken and not pass validation in the future.
      */
-    private boolean _fatalSqlExceptionThrown = false;
+    private boolean fatalSqlExceptionThrown = false;
 
     /**
-     * SQL_STATE codes considered to signal fatal conditions. Overrides the
-     * defaults in {@link Utils#DISCONNECTION_SQL_CODES} (plus anything starting
-     * with {@link Utils#DISCONNECTION_SQL_CODE_PREFIX}).
+     * SQL_STATE codes considered to signal fatal conditions. Overrides the defaults in
+     * {@link Utils#DISCONNECTION_SQL_CODES} (plus anything starting with {@link Utils#DISCONNECTION_SQL_CODE_PREFIX}).
      */
-    private final Collection<String> _disconnectionSqlCodes;
+    private final Collection<String> disconnectionSqlCodes;
 
     /** Whether or not to fast fail validation after fatal connection errors */
-    private final boolean _fastFailValidation;
+    private final boolean fastFailValidation;
 
     /**
      *
-     * @param conn my underlying connection
-     * @param pool the pool to which I should return when closed
-     * @param jmxName JMX name
-     * @param disconnectSqlCodes SQL_STATE codes considered fatal disconnection errors
-     * @param fastFailValidation true means fatal disconnection errors cause subsequent
-     *        validations to fail immediately (no attempt to run query or isValid)
+     * @param conn
+     *            my underlying connection
+     * @param pool
+     *            the pool to which I should return when closed
+     * @param jmxObjectName
+     *            JMX name
+     * @param disconnectSqlCodes
+     *            SQL_STATE codes considered fatal disconnection errors
+     * @param fastFailValidation
+     *            true means fatal disconnection errors cause subsequent validations to fail immediately (no attempt to
+     *            run query or isValid)
      */
-    public PoolableConnection(final Connection conn,
-            final ObjectPool<PoolableConnection> pool, final ObjectName jmxName, final Collection<String> disconnectSqlCodes,
+    public PoolableConnection(final Connection conn, final ObjectPool<PoolableConnection> pool,
+            final ObjectName jmxObjectName, final Collection<String> disconnectSqlCodes,
             final boolean fastFailValidation) {
         super(conn);
-        _pool = pool;
-        _jmxName = jmxName;
-        _disconnectionSqlCodes = disconnectSqlCodes;
-        _fastFailValidation = fastFailValidation;
+        this.pool = pool;
+        this.jmxObjectName = ObjectNameWrapper.wrap(jmxObjectName);
+        this.disconnectionSqlCodes = disconnectSqlCodes;
+        this.fastFailValidation = fastFailValidation;
 
-        if (jmxName != null) {
+        if (jmxObjectName != null) {
             try {
-                MBEAN_SERVER.registerMBean(this, jmxName);
-            } catch (InstanceAlreadyExistsException |
-                    MBeanRegistrationException | NotCompliantMBeanException e) {
+                MBEAN_SERVER.registerMBean(this, jmxObjectName);
+            } catch (InstanceAlreadyExistsException | MBeanRegistrationException | NotCompliantMBeanException e) {
                 // For now, simply skip registration
             }
         }
     }
 
     /**
-    *
-    * @param conn my underlying connection
-    * @param pool the pool to which I should return when closed
-    * @param jmxName JMX name
-    */
-   public PoolableConnection(final Connection conn,
-           final ObjectPool<PoolableConnection> pool, final ObjectName jmxName) {
-       this(conn, pool, jmxName, null, false);
-   }
-
+     *
+     * @param conn
+     *            my underlying connection
+     * @param pool
+     *            the pool to which I should return when closed
+     * @param jmxName
+     *            JMX name
+     */
+    public PoolableConnection(final Connection conn, final ObjectPool<PoolableConnection> pool,
+            final ObjectName jmxName) {
+        this(conn, pool, jmxName, null, false);
+    }
 
     @Override
     protected void passivate() throws SQLException {
@@ -127,14 +126,12 @@
         setClosedInternal(true);
     }
 
-
     /**
      * {@inheritDoc}
      * <p>
-     * This method should not be used by a client to determine whether or not a
-     * connection should be return to the connection pool (by calling
-     * {@link #close()}). Clients should always attempt to return a connection
-     * to the pool once it is no longer required.
+     * This method should not be used by a client to determine whether or not a connection should be return to the
+     * connection pool (by calling {@link #close()}). Clients should always attempt to return a connection to the pool
+     * once it is no longer required.
      */
     @Override
     public boolean isClosed() throws SQLException {
@@ -153,11 +150,10 @@
         return false;
     }
 
-
     /**
      * Returns me to my pool.
      */
-     @Override
+    @Override
     public synchronized void close() throws SQLException {
         if (isClosedInternal()) {
             // already closed
@@ -169,8 +165,8 @@
             isUnderlyingConnectionClosed = getDelegateInternal().isClosed();
         } catch (final SQLException e) {
             try {
-                _pool.invalidateObject(this);
-            } catch(final IllegalStateException ise) {
+                pool.invalidateObject(this);
+            } catch (final IllegalStateException ise) {
                 // pool is closed, so close the connection
                 passivate();
                 getInnermostDelegate().close();
@@ -180,18 +176,17 @@
             throw new SQLException("Cannot close connection (isClosed check failed)", e);
         }
 
-        /* Can't set close before this code block since the connection needs to
-         * be open when validation runs. Can't set close after this code block
-         * since by then the connection will have been returned to the pool and
-         * may have been borrowed by another thread. Therefore, the close flag
-         * is set in passivate().
+        /*
+         * Can't set close before this code block since the connection needs to be open when validation runs. Can't set
+         * close after this code block since by then the connection will have been returned to the pool and may have
+         * been borrowed by another thread. Therefore, the close flag is set in passivate().
          */
         if (isUnderlyingConnectionClosed) {
             // Abnormal close: underlying connection closed unexpectedly, so we
             // must destroy this proxy
             try {
-                _pool.invalidateObject(this);
-            } catch(final IllegalStateException e) {
+                pool.invalidateObject(this);
+            } catch (final IllegalStateException e) {
                 // pool is closed, so close the connection
                 passivate();
                 getInnermostDelegate().close();
@@ -202,16 +197,16 @@
             // Normal close: underlying connection is still open, so we
             // simply need to return this proxy to the pool
             try {
-                _pool.returnObject(this);
-            } catch(final IllegalStateException e) {
+                pool.returnObject(this);
+            } catch (final IllegalStateException e) {
                 // pool is closed, so close the connection
                 passivate();
                 getInnermostDelegate().close();
-            } catch(final SQLException e) {
+            } catch (final SQLException e) {
                 throw e;
-            } catch(final RuntimeException e) {
+            } catch (final RuntimeException e) {
                 throw e;
-            } catch(final Exception e) {
+            } catch (final Exception e) {
                 throw new SQLException("Cannot close connection (return to pool failed)", e);
             }
         }
@@ -222,15 +217,10 @@
      */
     @Override
     public void reallyClose() throws SQLException {
-        if (_jmxName != null) {
-            try {
-                MBEAN_SERVER.unregisterMBean(_jmxName);
-            } catch (MBeanRegistrationException | InstanceNotFoundException e) {
-                // Ignore
-            }
+        if (jmxObjectName != null) {
+            jmxObjectName.unregisterMBean();
         }
 
-
         if (validationPreparedStatement != null) {
             try {
                 validationPreparedStatement.close();
@@ -242,10 +232,8 @@
         super.closeInternal();
     }
 
-
     /**
-     * Expose the {@link #toString()} method via a bean getter so it can be read
-     * as a property via JMX.
+     * Expose the {@link #toString()} method via a bean getter so it can be read as a property via JMX.
      */
     @Override
     public String getToString() {
@@ -255,31 +243,31 @@
     /**
      * Validates the connection, using the following algorithm:
      * <ol>
-     *   <li>If {@code fastFailValidation} (constructor argument) is {@code true} and
-     *       this connection has previously thrown a fatal disconnection exception,
-     *       a {@code SQLException} is thrown. </li>
-     *   <li>If {@code sql} is null, the driver's
-     *       #{@link Connection#isValid(int) isValid(timeout)} is called.
-     *       If it returns {@code false}, {@code SQLException} is thrown;
-     *       otherwise, this method returns successfully.</li>
-     *   <li>If {@code sql} is not null, it is executed as a query and if the resulting
-     *       {@code ResultSet} contains at least one row, this method returns
-     *       successfully.  If not, {@code SQLException} is thrown.</li>
+     * <li>If {@code fastFailValidation} (constructor argument) is {@code true} and this connection has previously
+     * thrown a fatal disconnection exception, a {@code SQLException} is thrown.</li>
+     * <li>If {@code sql} is null, the driver's #{@link Connection#isValid(int) isValid(timeout)} is called. If it
+     * returns {@code false}, {@code SQLException} is thrown; otherwise, this method returns successfully.</li>
+     * <li>If {@code sql} is not null, it is executed as a query and if the resulting {@code ResultSet} contains at
+     * least one row, this method returns successfully. If not, {@code SQLException} is thrown.</li>
      * </ol>
-     * @param sql validation query
-     * @param timeout validation timeout
-     * @throws SQLException if validation fails or an SQLException occurs during validation
+     *
+     * @param sql
+     *            The validation SQL query.
+     * @param timeoutSeconds
+     *            The validation timeout in seconds.
+     * @throws SQLException
+     *             Thrown when validation fails or an SQLException occurs during validation
      */
-    public void validate(final String sql, int timeout) throws SQLException {
-        if (_fastFailValidation && _fatalSqlExceptionThrown) {
+    public void validate(final String sql, int timeoutSeconds) throws SQLException {
+        if (fastFailValidation && fatalSqlExceptionThrown) {
             throw new SQLException(Utils.getMessage("poolableConnection.validate.fastFail"));
         }
 
         if (sql == null || sql.length() == 0) {
-            if (timeout < 0) {
-                timeout = 0;
+            if (timeoutSeconds < 0) {
+                timeoutSeconds = 0;
             }
-            if (!isValid(timeout)) {
+            if (!isValid(timeoutSeconds)) {
                 throw new SQLException("isValid() returned false");
             }
             return;
@@ -289,16 +277,15 @@
             lastValidationSql = sql;
             // Has to be the innermost delegate else the prepared statement will
             // be closed when the pooled connection is passivated.
-            validationPreparedStatement =
-                    getInnermostDelegateInternal().prepareStatement(sql);
+            validationPreparedStatement = getInnermostDelegateInternal().prepareStatement(sql);
         }
 
-        if (timeout > 0) {
-            validationPreparedStatement.setQueryTimeout(timeout);
+        if (timeoutSeconds > 0) {
+            validationPreparedStatement.setQueryTimeout(timeoutSeconds);
         }
 
         try (ResultSet rs = validationPreparedStatement.executeQuery()) {
-            if(!rs.next()) {
+            if (!rs.next()) {
                 throw new SQLException("validationQuery didn't return a row");
             }
         } catch (final SQLException sqle) {
@@ -309,21 +296,24 @@
     /**
      * Checks the SQLState of the input exception and any nested SQLExceptions it wraps.
      * <p>
-     * If {@link #getDisconnectSqlCodes() disconnectSQLCodes} has been set, sql states
-     * are compared to those in the configured list of fatal exception codes.  If this
-     * property is not set, codes are compared against the default codes in
-     * #{@link Utils.DISCONNECTION_SQL_CODES} and in this case anything starting with
-     * #{link Utils.DISCONNECTION_SQL_CODE_PREFIX} is considered a disconnection.</p>
+     * If {@link #getDisconnectSqlCodes() disconnectSQLCodes} has been set, sql states are compared to those in the
+     * configured list of fatal exception codes. If this property is not set, codes are compared against the default
+     * codes in #{@link Utils.DISCONNECTION_SQL_CODES} and in this case anything starting with #{link
+     * Utils.DISCONNECTION_SQL_CODE_PREFIX} is considered a disconnection.
+     * </p>
      *
-     * @param e SQLException to be examined
+     * @param e
+     *            SQLException to be examined
      * @return true if the exception signals a disconnection
      */
     private boolean isDisconnectionSqlException(final SQLException e) {
         boolean fatalException = false;
         final String sqlState = e.getSQLState();
         if (sqlState != null) {
-            fatalException = _disconnectionSqlCodes == null ? sqlState.startsWith(Utils.DISCONNECTION_SQL_CODE_PREFIX)
-                    || Utils.DISCONNECTION_SQL_CODES.contains(sqlState) : _disconnectionSqlCodes.contains(sqlState);
+            fatalException = disconnectionSqlCodes == null
+                    ? sqlState.startsWith(Utils.DISCONNECTION_SQL_CODE_PREFIX)
+                            || Utils.DISCONNECTION_SQL_CODES.contains(sqlState)
+                    : disconnectionSqlCodes.contains(sqlState);
             if (!fatalException) {
                 final SQLException nextException = e.getNextException();
                 if (nextException != null && nextException != e) {
@@ -336,8 +326,7 @@
 
     @Override
     protected void handleException(final SQLException e) throws SQLException {
-        _fatalSqlExceptionThrown |= isDisconnectionSqlException(e);
+        fatalSqlExceptionThrown |= isDisconnectionSqlException(e);
         super.handleException(e);
     }
 }
-
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnectionFactory.java b/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnectionFactory.java
index fd8be9b..83fb669 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnectionFactory.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnectionFactory.java
@@ -21,6 +21,7 @@
 import java.sql.SQLException;
 import java.sql.Statement;
 import java.util.Collection;
+import java.util.Objects;
 import java.util.concurrent.atomic.AtomicLong;
 
 import javax.management.ObjectName;
@@ -36,147 +37,167 @@
 import org.apache.tomcat.dbcp.pool2.impl.GenericKeyedObjectPoolConfig;
 
 /**
- * A {@link PooledObjectFactory} that creates
- * {@link PoolableConnection}s.
+ * A {@link PooledObjectFactory} that creates {@link PoolableConnection}s.
  *
- * @author Rodney Waldhoff
- * @author Glenn L. Nielsen
- * @author James House
- * @author Dirk Verbeeck
  * @since 2.0
  */
-public class PoolableConnectionFactory
-        implements PooledObjectFactory<PoolableConnection> {
+public class PoolableConnectionFactory implements PooledObjectFactory<PoolableConnection> {
 
-    private static final Log log =
-            LogFactory.getLog(PoolableConnectionFactory.class);
+    private static final Log log = LogFactory.getLog(PoolableConnectionFactory.class);
 
     /**
-     * Create a new {@code PoolableConnectionFactory}.
-     * @param connFactory the {@link ConnectionFactory} from which to obtain
-     * base {@link Connection}s
+     * Creates a new {@code PoolableConnectionFactory}.
+     *
+     * @param connFactory
+     *            the {@link ConnectionFactory} from which to obtain base {@link Connection}s
+     * @param dataSourceJmxObjectName
+     *            The JMX object name, may be null.
      */
-    public PoolableConnectionFactory(final ConnectionFactory connFactory,
-            final ObjectName dataSourceJmxName) {
-        _connFactory = connFactory;
-        this.dataSourceJmxName = dataSourceJmxName;
+    public PoolableConnectionFactory(final ConnectionFactory connFactory, final ObjectName dataSourceJmxObjectName) {
+        this.connectionFactory = connFactory;
+        this.dataSourceJmxObjectName = dataSourceJmxObjectName;
     }
 
     /**
-     * Sets the query I use to {@link #validateObject validate} {@link Connection}s.
-     * Should return at least one row. If not specified,
-     * {@link Connection#isValid(int)} will be used to validate connections.
+     * Sets the query I use to {@link #validateObject validate} {@link Connection}s. Should return at least one row. If
+     * not specified, {@link Connection#isValid(int)} will be used to validate connections.
      *
-     * @param validationQuery a query to use to {@link #validateObject validate} {@link Connection}s.
+     * @param validationQuery
+     *            a query to use to {@link #validateObject validate} {@link Connection}s.
      */
     public void setValidationQuery(final String validationQuery) {
-        _validationQuery = validationQuery;
+        this.validationQuery = validationQuery;
     }
 
     /**
-     * Sets the validation query timeout, the amount of time, in seconds, that
-     * connection validation will wait for a response from the database when
-     * executing a validation query.  Use a value less than or equal to 0 for
-     * no timeout.
+     * Sets the validation query timeout, the amount of time, in seconds, that connection validation will wait for a
+     * response from the database when executing a validation query. Use a value less than or equal to 0 for no timeout.
      *
-     * @param timeout new validation query timeout value in seconds
+     * @param validationQueryTimeoutSeconds
+     *            new validation query timeout value in seconds
      */
-    public void setValidationQueryTimeout(final int timeout) {
-        _validationQueryTimeout = timeout;
+    public void setValidationQueryTimeout(final int validationQueryTimeoutSeconds) {
+        this.validationQueryTimeoutSeconds = validationQueryTimeoutSeconds;
     }
 
     /**
-     * Sets the SQL statements I use to initialize newly created {@link Connection}s.
-     * Using {@code null} turns off connection initialization.
-     * @param connectionInitSqls SQL statement to initialize {@link Connection}s.
+     * Sets the SQL statements I use to initialize newly created {@link Connection}s. Using {@code null} turns off
+     * connection initialization.
+     *
+     * @param connectionInitSqls
+     *            SQL statement to initialize {@link Connection}s.
      */
     public void setConnectionInitSql(final Collection<String> connectionInitSqls) {
-        _connectionInitSqls = connectionInitSqls;
+        this.connectionInitSqls = connectionInitSqls;
     }
 
     /**
      * Sets the {@link ObjectPool} in which to pool {@link Connection}s.
-     * @param pool the {@link ObjectPool} in which to pool those {@link Connection}s
+     *
+     * @param pool
+     *            the {@link ObjectPool} in which to pool those {@link Connection}s
      */
     public synchronized void setPool(final ObjectPool<PoolableConnection> pool) {
-        if(null != _pool && pool != _pool) {
+        if (null != this.pool && pool != this.pool) {
             try {
-                _pool.close();
-            } catch(final Exception e) {
+                this.pool.close();
+            } catch (final Exception e) {
                 // ignored !?!
             }
         }
-        _pool = pool;
+        this.pool = pool;
     }
 
     /**
      * Returns the {@link ObjectPool} in which {@link Connection}s are pooled.
+     *
      * @return the connection pool
      */
     public synchronized ObjectPool<PoolableConnection> getPool() {
-        return _pool;
+        return pool;
     }
 
     /**
      * Sets the default "read only" setting for borrowed {@link Connection}s
-     * @param defaultReadOnly the default "read only" setting for borrowed {@link Connection}s
+     *
+     * @param defaultReadOnly
+     *            the default "read only" setting for borrowed {@link Connection}s
      */
     public void setDefaultReadOnly(final Boolean defaultReadOnly) {
-        _defaultReadOnly = defaultReadOnly;
+        this.defaultReadOnly = defaultReadOnly;
     }
 
     /**
      * Sets the default "auto commit" setting for borrowed {@link Connection}s
-     * @param defaultAutoCommit the default "auto commit" setting for borrowed {@link Connection}s
+     *
+     * @param defaultAutoCommit
+     *            the default "auto commit" setting for borrowed {@link Connection}s
      */
     public void setDefaultAutoCommit(final Boolean defaultAutoCommit) {
-        _defaultAutoCommit = defaultAutoCommit;
+        this.defaultAutoCommit = defaultAutoCommit;
     }
 
     /**
      * Sets the default "Transaction Isolation" setting for borrowed {@link Connection}s
-     * @param defaultTransactionIsolation the default "Transaction Isolation" setting for returned {@link Connection}s
+     *
+     * @param defaultTransactionIsolation
+     *            the default "Transaction Isolation" setting for returned {@link Connection}s
      */
     public void setDefaultTransactionIsolation(final int defaultTransactionIsolation) {
-        _defaultTransactionIsolation = defaultTransactionIsolation;
+        this.defaultTransactionIsolation = defaultTransactionIsolation;
     }
 
     /**
      * Sets the default "catalog" setting for borrowed {@link Connection}s
-     * @param defaultCatalog the default "catalog" setting for borrowed {@link Connection}s
+     *
+     * @param defaultCatalog
+     *            the default "catalog" setting for borrowed {@link Connection}s
      */
     public void setDefaultCatalog(final String defaultCatalog) {
-        _defaultCatalog = defaultCatalog;
+        this.defaultCatalog = defaultCatalog;
     }
 
     public void setCacheState(final boolean cacheState) {
-        this._cacheState = cacheState;
+        this.cacheState = cacheState;
     }
 
     public void setPoolStatements(final boolean poolStatements) {
         this.poolStatements = poolStatements;
     }
 
+    /**
+     * Deprecated due to typo in method name.
+     *
+     * @param maxOpenPreparedStatements
+     *            The maximum number of open prepared statements.
+     * @deprecated Use {@link #setMaxOpenPreparedStatements(int)}.
+     */
     @Deprecated // Due to typo in method name.
     public void setMaxOpenPrepatedStatements(final int maxOpenPreparedStatements) {
         setMaxOpenPreparedStatements(maxOpenPreparedStatements);
     }
 
+    /**
+     * Sets the maximum number of open prepared statements.
+     *
+     * @param maxOpenPreparedStatements
+     *            The maximum number of open prepared statements.
+     */
     public void setMaxOpenPreparedStatements(final int maxOpenPreparedStatements) {
         this.maxOpenPreparedStatements = maxOpenPreparedStatements;
     }
 
     /**
-     * Sets the maximum lifetime in milliseconds of a connection after which the
-     * connection will always fail activation, passivation and validation. A
-     * value of zero or less indicates an infinite lifetime. The default value
-     * is -1.
+     * Sets the maximum lifetime in milliseconds of a connection after which the connection will always fail activation,
+     * passivation and validation. A value of zero or less indicates an infinite lifetime. The default value is -1.
+     *
+     * @param maxConnLifetimeMillis
+     *            The maximum lifetime in milliseconds.
      */
     public void setMaxConnLifetimeMillis(final long maxConnLifetimeMillis) {
         this.maxConnLifetimeMillis = maxConnLifetimeMillis;
     }
 
-
     public boolean isEnableAutoCommitOnReturn() {
         return enableAutoCommitOnReturn;
     }
@@ -185,7 +206,6 @@
         this.enableAutoCommitOnReturn = enableAutoCommitOnReturn;
     }
 
-
     public boolean isRollbackOnReturn() {
         return rollbackOnReturn;
     }
@@ -195,69 +215,68 @@
     }
 
     public Integer getDefaultQueryTimeout() {
-        return defaultQueryTimeout;
+        return defaultQueryTimeoutSeconds;
     }
 
-    public void setDefaultQueryTimeout(final Integer defaultQueryTimeout) {
-        this.defaultQueryTimeout = defaultQueryTimeout;
+    public void setDefaultQueryTimeout(final Integer defaultQueryTimeoutSeconds) {
+        this.defaultQueryTimeoutSeconds = defaultQueryTimeoutSeconds;
     }
 
     /**
      * SQL_STATE codes considered to signal fatal conditions.
      * <p>
-     * Overrides the defaults in {@link Utils#DISCONNECTION_SQL_CODES}
-     * (plus anything starting with {@link Utils#DISCONNECTION_SQL_CODE_PREFIX}).
-     * If this property is non-null and {@link #isFastFailValidation()} is
-     * {@code true}, whenever connections created by this factory generate exceptions
-     * with SQL_STATE codes in this list, they will be marked as "fatally disconnected"
-     * and subsequent validations will fail fast (no attempt at isValid or validation
-     * query).</p>
+     * Overrides the defaults in {@link Utils#DISCONNECTION_SQL_CODES} (plus anything starting with
+     * {@link Utils#DISCONNECTION_SQL_CODE_PREFIX}). If this property is non-null and {@link #isFastFailValidation()} is
+     * {@code true}, whenever connections created by this factory generate exceptions with SQL_STATE codes in this list,
+     * they will be marked as "fatally disconnected" and subsequent validations will fail fast (no attempt at isValid or
+     * validation query).
+     * </p>
      * <p>
-     * If {@link #isFastFailValidation()} is {@code false} setting this property has no
-     * effect.</p>
+     * If {@link #isFastFailValidation()} is {@code false} setting this property has no effect.
+     * </p>
      *
      * @return SQL_STATE codes overriding defaults
      * @since 2.1
      */
     public Collection<String> getDisconnectionSqlCodes() {
-        return _disconnectionSqlCodes;
+        return disconnectionSqlCodes;
     }
 
     /**
-     * @see #getDisconnectionSqlCodes()
      * @param disconnectionSqlCodes
+     *            The disconnection SQL codes.
+     * @see #getDisconnectionSqlCodes()
      * @since 2.1
      */
     public void setDisconnectionSqlCodes(final Collection<String> disconnectionSqlCodes) {
-        _disconnectionSqlCodes = disconnectionSqlCodes;
+        this.disconnectionSqlCodes = disconnectionSqlCodes;
     }
 
     /**
-     * True means that validation will fail immediately for connections that
-     * have previously thrown SQLExceptions with SQL_STATE indicating fatal
-     * disconnection errors.
+     * True means that validation will fail immediately for connections that have previously thrown SQLExceptions with
+     * SQL_STATE indicating fatal disconnection errors.
      *
      * @return true if connections created by this factory will fast fail validation.
      * @see #setDisconnectionSqlCodes(Collection)
      * @since 2.1
      */
     public boolean isFastFailValidation() {
-        return _fastFailValidation;
+        return fastFailValidation;
     }
 
     /**
      * @see #isFastFailValidation()
-     * @param fastFailValidation true means connections created by this factory will
-     * fast fail validation
+     * @param fastFailValidation
+     *            true means connections created by this factory will fast fail validation
      * @since 2.1
      */
     public void setFastFailValidation(final boolean fastFailValidation) {
-        _fastFailValidation = fastFailValidation;
+        this.fastFailValidation = fastFailValidation;
     }
 
     @Override
     public PooledObject<PoolableConnection> makeObject() throws Exception {
-        Connection conn = _connFactory.createConnection();
+        Connection conn = connectionFactory.createConnection();
         if (conn == null) {
             throw new IllegalStateException("Connection factory returned null from createConnection");
         }
@@ -276,16 +295,16 @@
 
         final long connIndex = connectionIndex.getAndIncrement();
 
-        if(poolStatements) {
+        if (poolStatements) {
             conn = new PoolingConnection(conn);
-            final GenericKeyedObjectPoolConfig<DelegatingPreparedStatement> config = new GenericKeyedObjectPoolConfig<>();
+            final GenericKeyedObjectPoolConfig config = new GenericKeyedObjectPoolConfig();
             config.setMaxTotalPerKey(-1);
             config.setBlockWhenExhausted(false);
             config.setMaxWaitMillis(0);
             config.setMaxIdlePerKey(1);
             config.setMaxTotal(maxOpenPreparedStatements);
-            if (dataSourceJmxName != null) {
-                final StringBuilder base = new StringBuilder(dataSourceJmxName.toString());
+            if (dataSourceJmxObjectName != null) {
+                final StringBuilder base = new StringBuilder(dataSourceJmxObjectName.toString());
                 base.append(Constants.JMX_CONNECTION_BASE_EXT);
                 base.append(Long.toString(connIndex));
                 config.setJmxNameBase(base.toString());
@@ -293,40 +312,37 @@
             } else {
                 config.setJmxEnabled(false);
             }
-            final KeyedObjectPool<PStmtKey,DelegatingPreparedStatement> stmtPool =
-                    new GenericKeyedObjectPool<>((PoolingConnection)conn, config);
-            ((PoolingConnection)conn).setStatementPool(stmtPool);
-            ((PoolingConnection) conn).setCacheState(_cacheState);
+            final KeyedObjectPool<PStmtKey, DelegatingPreparedStatement> stmtPool = new GenericKeyedObjectPool<>(
+                    (PoolingConnection) conn, config);
+            ((PoolingConnection) conn).setStatementPool(stmtPool);
+            ((PoolingConnection) conn).setCacheState(cacheState);
         }
 
         // Register this connection with JMX
         ObjectName connJmxName;
-        if (dataSourceJmxName == null) {
+        if (dataSourceJmxObjectName == null) {
             connJmxName = null;
         } else {
-            connJmxName = new ObjectName(dataSourceJmxName.toString() +
-                    Constants.JMX_CONNECTION_BASE_EXT + connIndex);
+            connJmxName = new ObjectName(
+                    dataSourceJmxObjectName.toString() + Constants.JMX_CONNECTION_BASE_EXT + connIndex);
         }
 
-        final PoolableConnection pc = new PoolableConnection(conn, _pool, connJmxName,
-                                      _disconnectionSqlCodes, _fastFailValidation);
-        pc.setCacheState(_cacheState);
+        final PoolableConnection pc = new PoolableConnection(conn, pool, connJmxName, disconnectionSqlCodes,
+                fastFailValidation);
+        pc.setCacheState(cacheState);
 
         return new DefaultPooledObject<>(pc);
     }
 
     protected void initializeConnection(final Connection conn) throws SQLException {
-        final Collection<String> sqls = _connectionInitSqls;
-        if(conn.isClosed()) {
+        final Collection<String> sqls = connectionInitSqls;
+        if (conn.isClosed()) {
             throw new SQLException("initializeConnection: connection closed");
         }
-        if(null != sqls) {
+        if (null != sqls) {
             try (Statement stmt = conn.createStatement();) {
                 for (final String sql : sqls) {
-                    if (sql == null) {
-                        throw new NullPointerException(
-                                "null connectionInitSqls element");
-                    }
+                    Objects.requireNonNull(sql, "null connectionInitSqls element");
                     stmt.execute(sql);
                 }
             }
@@ -334,8 +350,7 @@
     }
 
     @Override
-    public void destroyObject(final PooledObject<PoolableConnection> p)
-            throws Exception {
+    public void destroyObject(final PooledObject<PoolableConnection> p) throws Exception {
         p.getObject().reallyClose();
     }
 
@@ -348,23 +363,21 @@
             return true;
         } catch (final Exception e) {
             if (log.isDebugEnabled()) {
-                log.debug(Utils.getMessage(
-                        "poolableConnectionFactory.validateObject.fail"), e);
+                log.debug(Utils.getMessage("poolableConnectionFactory.validateObject.fail"), e);
             }
             return false;
         }
     }
 
     public void validateConnection(final PoolableConnection conn) throws SQLException {
-        if(conn.isClosed()) {
+        if (conn.isClosed()) {
             throw new SQLException("validateConnection: connection closed");
         }
-        conn.validate(_validationQuery, _validationQueryTimeout);
+        conn.validate(validationQuery, validationQueryTimeoutSeconds);
     }
 
     @Override
-    public void passivateObject(final PooledObject<PoolableConnection> p)
-            throws Exception {
+    public void passivateObject(final PooledObject<PoolableConnection> p) throws Exception {
 
         validateLifetime(p);
 
@@ -372,7 +385,7 @@
         Boolean connAutoCommit = null;
         if (rollbackOnReturn) {
             connAutoCommit = Boolean.valueOf(conn.getAutoCommit());
-            if(!connAutoCommit.booleanValue() && !conn.isReadOnly()) {
+            if (!connAutoCommit.booleanValue() && !conn.isReadOnly()) {
                 conn.rollback();
             }
         }
@@ -385,7 +398,7 @@
             if (connAutoCommit == null) {
                 connAutoCommit = Boolean.valueOf(conn.getAutoCommit());
             }
-            if(!connAutoCommit.booleanValue()) {
+            if (!connAutoCommit.booleanValue()) {
                 conn.setAutoCommit(true);
             }
         }
@@ -394,48 +407,41 @@
     }
 
     @Override
-    public void activateObject(final PooledObject<PoolableConnection> p)
-            throws Exception {
+    public void activateObject(final PooledObject<PoolableConnection> p) throws Exception {
 
         validateLifetime(p);
 
         final PoolableConnection conn = p.getObject();
         conn.activate();
 
-        if (_defaultAutoCommit != null &&
-                conn.getAutoCommit() != _defaultAutoCommit.booleanValue()) {
-            conn.setAutoCommit(_defaultAutoCommit.booleanValue());
+        if (defaultAutoCommit != null && conn.getAutoCommit() != defaultAutoCommit.booleanValue()) {
+            conn.setAutoCommit(defaultAutoCommit.booleanValue());
         }
-        if (_defaultTransactionIsolation != UNKNOWN_TRANSACTIONISOLATION &&
-                conn.getTransactionIsolation() != _defaultTransactionIsolation) {
-            conn.setTransactionIsolation(_defaultTransactionIsolation);
+        if (defaultTransactionIsolation != UNKNOWN_TRANSACTIONISOLATION
+                && conn.getTransactionIsolation() != defaultTransactionIsolation) {
+            conn.setTransactionIsolation(defaultTransactionIsolation);
         }
-        if (_defaultReadOnly != null &&
-                conn.isReadOnly() != _defaultReadOnly.booleanValue()) {
-            conn.setReadOnly(_defaultReadOnly.booleanValue());
+        if (defaultReadOnly != null && conn.isReadOnly() != defaultReadOnly.booleanValue()) {
+            conn.setReadOnly(defaultReadOnly.booleanValue());
         }
-        if (_defaultCatalog != null &&
-                !_defaultCatalog.equals(conn.getCatalog())) {
-            conn.setCatalog(_defaultCatalog);
+        if (defaultCatalog != null && !defaultCatalog.equals(conn.getCatalog())) {
+            conn.setCatalog(defaultCatalog);
         }
-        conn.setDefaultQueryTimeout(defaultQueryTimeout);
+        conn.setDefaultQueryTimeout(defaultQueryTimeoutSeconds);
     }
 
-    private void validateLifetime(final PooledObject<PoolableConnection> p)
-            throws Exception {
+    private void validateLifetime(final PooledObject<PoolableConnection> p) throws Exception {
         if (maxConnLifetimeMillis > 0) {
             final long lifetime = System.currentTimeMillis() - p.getCreateTime();
             if (lifetime > maxConnLifetimeMillis) {
-                throw new LifetimeExceededException(Utils.getMessage(
-                        "connectionFactory.lifetimeExceeded",
-                        Long.valueOf(lifetime),
-                        Long.valueOf(maxConnLifetimeMillis)));
+                throw new LifetimeExceededException(Utils.getMessage("connectionFactory.lifetimeExceeded",
+                        Long.valueOf(lifetime), Long.valueOf(maxConnLifetimeMillis)));
             }
         }
     }
 
     protected ConnectionFactory getConnectionFactory() {
-        return _connFactory;
+        return connectionFactory;
     }
 
     protected boolean getPoolStatements() {
@@ -447,38 +453,37 @@
     }
 
     protected boolean getCacheState() {
-        return _cacheState;
+        return cacheState;
     }
 
     protected ObjectName getDataSourceJmxName() {
-        return dataSourceJmxName;
+        return dataSourceJmxObjectName;
     }
 
     protected AtomicLong getConnectionIndex() {
         return connectionIndex;
     }
 
-    private final ConnectionFactory _connFactory;
-    private final ObjectName dataSourceJmxName;
-    private volatile String _validationQuery = null;
-    private volatile int _validationQueryTimeout = -1;
-    private Collection<String> _connectionInitSqls = null;
-    private Collection<String> _disconnectionSqlCodes = null;
-    private boolean _fastFailValidation = false;
-    private volatile ObjectPool<PoolableConnection> _pool = null;
-    private Boolean _defaultReadOnly = null;
-    private Boolean _defaultAutoCommit = null;
+    private final ConnectionFactory connectionFactory;
+    private final ObjectName dataSourceJmxObjectName;
+    private volatile String validationQuery;
+    private volatile int validationQueryTimeoutSeconds = -1;
+    private Collection<String> connectionInitSqls;
+    private Collection<String> disconnectionSqlCodes;
+    private boolean fastFailValidation;
+    private volatile ObjectPool<PoolableConnection> pool;
+    private Boolean defaultReadOnly;
+    private Boolean defaultAutoCommit;
     private boolean enableAutoCommitOnReturn = true;
     private boolean rollbackOnReturn = true;
-    private int _defaultTransactionIsolation = UNKNOWN_TRANSACTIONISOLATION;
-    private String _defaultCatalog;
-    private boolean _cacheState;
-    private boolean poolStatements = false;
-    private int maxOpenPreparedStatements =
-        GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL_PER_KEY;
+    private int defaultTransactionIsolation = UNKNOWN_TRANSACTIONISOLATION;
+    private String defaultCatalog;
+    private boolean cacheState;
+    private boolean poolStatements;
+    private int maxOpenPreparedStatements = GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL_PER_KEY;
     private long maxConnLifetimeMillis = -1;
     private final AtomicLong connectionIndex = new AtomicLong(0);
-    private Integer defaultQueryTimeout = null;
+    private Integer defaultQueryTimeoutSeconds;
 
     /**
      * Internal constant to indicate the level is not set.
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnectionMXBean.java b/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnectionMXBean.java
index dbf9f7a..eaa9fdd 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnectionMXBean.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnectionMXBean.java
@@ -19,41 +19,52 @@
 import java.sql.SQLException;
 
 /**
- * Defines the attributes and methods that will be exposed via JMX for
- * {@link PoolableConnection} instances.
+ * Defines the attributes and methods that will be exposed via JMX for {@link PoolableConnection} instances.
+ *
  * @since 2.0
  */
 public interface PoolableConnectionMXBean {
     // Read-only properties
     boolean isClosed() throws SQLException;
-    //SQLWarning getWarnings() throws SQLException;
+
+    // SQLWarning getWarnings() throws SQLException;
     String getToString();
 
     // Read-write properties
     boolean getAutoCommit() throws SQLException;
+
     void setAutoCommit(boolean autoCommit) throws SQLException;
 
     boolean getCacheState();
+
     void setCacheState(boolean cacheState);
 
     String getCatalog() throws SQLException;
+
     void setCatalog(String catalog) throws SQLException;
 
     int getHoldability() throws SQLException;
+
     void setHoldability(int holdability) throws SQLException;
 
     boolean isReadOnly() throws SQLException;
+
     void setReadOnly(boolean readOnly) throws SQLException;
 
     String getSchema() throws SQLException;
+
     void setSchema(String schema) throws SQLException;
 
     int getTransactionIsolation() throws SQLException;
+
     void setTransactionIsolation(int level) throws SQLException;
 
     // Methods
     void clearCachedState();
+
     void clearWarnings() throws SQLException;
+
     void close() throws SQLException;
+
     void reallyClose() throws SQLException;
 }
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/PoolablePreparedStatement.java b/java/org/apache/tomcat/dbcp/dbcp2/PoolablePreparedStatement.java
index 1b88f32..29136d0 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/PoolablePreparedStatement.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/PoolablePreparedStatement.java
@@ -25,50 +25,51 @@
 import org.apache.tomcat.dbcp.pool2.KeyedObjectPool;
 
 /**
- * A {@link DelegatingPreparedStatement} that cooperates with
- * {@link PoolingConnection} to implement a pool of {@link PreparedStatement}s.
+ * A {@link DelegatingPreparedStatement} that cooperates with {@link PoolingConnection} to implement a pool of
+ * {@link PreparedStatement}s.
  * <p>
  * My {@link #close} method returns me to my containing pool. (See {@link PoolingConnection}.)
  *
- * @param <K> the key type
+ * @param <K>
+ *            the key type
  *
  * @see PoolingConnection
- * @author Rodney Waldhoff
- * @author Glenn L. Nielsen
- * @author James House
- * @author Dirk Verbeeck
  * @since 2.0
  */
 public class PoolablePreparedStatement<K> extends DelegatingPreparedStatement {
     /**
      * The {@link KeyedObjectPool} from which I was obtained.
      */
-    private final KeyedObjectPool<K, PoolablePreparedStatement<K>> _pool;
+    private final KeyedObjectPool<K, PoolablePreparedStatement<K>> pool;
 
     /**
      * My "key" as used by {@link KeyedObjectPool}.
      */
-    private final K _key;
+    private final K key;
 
     private volatile boolean batchAdded = false;
 
     /**
      * Constructor
-     * @param stmt my underlying {@link PreparedStatement}
-     * @param key my key" as used by {@link KeyedObjectPool}
-     * @param pool the {@link KeyedObjectPool} from which I was obtained.
-     * @param conn the {@link java.sql.Connection Connection} from which I was created
+     *
+     * @param stmt
+     *            my underlying {@link PreparedStatement}
+     * @param key
+     *            my key" as used by {@link KeyedObjectPool}
+     * @param pool
+     *            the {@link KeyedObjectPool} from which I was obtained.
+     * @param conn
+     *            the {@link java.sql.Connection Connection} from which I was created
      */
     public PoolablePreparedStatement(final PreparedStatement stmt, final K key,
-            final KeyedObjectPool<K, PoolablePreparedStatement<K>> pool,
-            final DelegatingConnection<?> conn) {
+            final KeyedObjectPool<K, PoolablePreparedStatement<K>> pool, final DelegatingConnection<?> conn) {
         super(conn, stmt);
-        _pool = pool;
-        _key = key;
+        this.pool = pool;
+        this.key = key;
 
         // Remove from trace now because this statement will be
         // added by the activate method.
-        if(getConnectionInternal() != null) {
+        if (getConnectionInternal() != null) {
             getConnectionInternal().removeTrace(this);
         }
     }
@@ -99,21 +100,21 @@
         // calling close twice should have no effect
         if (!isClosed()) {
             try {
-                _pool.returnObject(_key, this);
-            } catch(final SQLException e) {
+                pool.returnObject(key, this);
+            } catch (final SQLException e) {
                 throw e;
-            } catch(final RuntimeException e) {
+            } catch (final RuntimeException e) {
                 throw e;
-            } catch(final Exception e) {
+            } catch (final Exception e) {
                 throw new SQLException("Cannot close preparedstatement (return to pool failed)", e);
             }
         }
     }
 
     @Override
-    public void activate() throws SQLException{
+    public void activate() throws SQLException {
         setClosedInternal(false);
-        if(getConnectionInternal() != null) {
+        if (getConnectionInternal() != null) {
             getConnectionInternal().addTrace(this);
         }
         super.activate();
@@ -127,7 +128,7 @@
             clearBatch();
         }
         setClosedInternal(true);
-        if(getConnectionInternal() != null) {
+        if (getConnectionInternal() != null) {
             getConnectionInternal().removeTrace(this);
         }
 
@@ -136,7 +137,7 @@
         // FIXME The PreparedStatement we're wrapping should handle this for us.
         // See bug 17301 for what could happen when ResultSets are closed twice.
         final List<AbandonedTrace> resultSets = getTrace();
-        if( resultSets != null) {
+        if (resultSets != null) {
             final ResultSet[] set = resultSets.toArray(new ResultSet[resultSets.size()]);
             for (final ResultSet element : set) {
                 element.close();
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/PoolingConnection.java b/java/org/apache/tomcat/dbcp/dbcp2/PoolingConnection.java
index 8d98ccb..04d67fb 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/PoolingConnection.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/PoolingConnection.java
@@ -31,56 +31,79 @@
 /**
  * A {@link DelegatingConnection} that pools {@link PreparedStatement}s.
  * <p>
- * The {@link #prepareStatement} and {@link #prepareCall} methods, rather than
- * creating a new PreparedStatement each time, may actually pull the statement
- * from a pool of unused statements.
- * The {@link PreparedStatement#close} method of the returned statement doesn't
- * actually close the statement, but rather returns it to the pool.
- * (See {@link PoolablePreparedStatement}, {@link PoolableCallableStatement}.)
- *
+ * The {@link #prepareStatement} and {@link #prepareCall} methods, rather than creating a new PreparedStatement each
+ * time, may actually pull the statement from a pool of unused statements. The {@link PreparedStatement#close} method of
+ * the returned statement doesn't actually close the statement, but rather returns it to the pool. (See
+ * {@link PoolablePreparedStatement}, {@link PoolableCallableStatement}.)
+ * </p>
  *
  * @see PoolablePreparedStatement
- * @author Rodney Waldhoff
- * @author Dirk Verbeeck
  * @since 2.0
  */
 public class PoolingConnection extends DelegatingConnection<Connection>
-        implements KeyedPooledObjectFactory<PStmtKey,DelegatingPreparedStatement> {
+        implements KeyedPooledObjectFactory<PStmtKey, DelegatingPreparedStatement> {
+
+    /**
+     * Statement types.
+     *
+     * @since 2.0 protected enum.
+     * @since 2.4.0 public enum.
+     */
+    public enum StatementType {
+
+        /**
+         * Callable statement.
+         */
+        CALLABLE_STATEMENT,
+
+        /**
+         * Prepared statement.
+         */
+        PREPARED_STATEMENT
+    }
 
     /** Pool of {@link PreparedStatement}s. and {@link CallableStatement}s */
-    private KeyedObjectPool<PStmtKey,DelegatingPreparedStatement> _pstmtPool = null;
+    private KeyedObjectPool<PStmtKey, DelegatingPreparedStatement> pstmtPool;
 
     /**
      * Constructor.
-     * @param c the underlying {@link Connection}.
+     *
+     * @param connection
+     *            the underlying {@link Connection}.
      */
-    public PoolingConnection(final Connection c) {
-        super(c);
+    public PoolingConnection(final Connection connection) {
+        super(connection);
     }
 
-
-    public void setStatementPool(
-            final KeyedObjectPool<PStmtKey,DelegatingPreparedStatement> pool) {
-        _pstmtPool = pool;
-    }
-
-
     /**
-     * Close and free all {@link PreparedStatement}s or
-     * {@link CallableStatement}s from the pool, and close the underlying
-     * connection.
+     * {@link KeyedPooledObjectFactory} method for activating pooled statements.
+     *
+     * @param key
+     *            ignored
+     * @param pooledObject
+     *            wrapped pooled statement to be activated
+     */
+    @Override
+    public void activateObject(final PStmtKey key, final PooledObject<DelegatingPreparedStatement> pooledObject)
+            throws Exception {
+        pooledObject.getObject().activate();
+    }
+
+    /**
+     * Closes and frees all {@link PreparedStatement}s or {@link CallableStatement}s from the pool, and close the
+     * underlying connection.
      */
     @Override
     public synchronized void close() throws SQLException {
         try {
-            if (null != _pstmtPool) {
-                final KeyedObjectPool<PStmtKey,DelegatingPreparedStatement> oldpool = _pstmtPool;
-                _pstmtPool = null;
+            if (null != pstmtPool) {
+                final KeyedObjectPool<PStmtKey, DelegatingPreparedStatement> oldpool = pstmtPool;
+                pstmtPool = null;
                 try {
                     oldpool.close();
-                } catch(final RuntimeException e) {
+                } catch (final RuntimeException e) {
                     throw e;
-                } catch(final Exception e) {
+                } catch (final Exception e) {
                     throw new SQLException("Cannot close connection", e);
                 }
             }
@@ -94,209 +117,19 @@
     }
 
     /**
-     * Create or obtain a {@link PreparedStatement} from the pool.
-     * @param sql the sql string used to define the PreparedStatement
-     * @return a {@link PoolablePreparedStatement}
+     * Creates a PStmtKey for the given arguments.
+     *
+     * @param sql
+     *            the SQL string used to define the statement
      */
-    @Override
-    public PreparedStatement prepareStatement(final String sql) throws SQLException {
-        if (null == _pstmtPool) {
-            throw new SQLException(
-                    "Statement pool is null - closed or invalid PoolingConnection.");
-        }
+    protected PStmtKey createKey(final String sql) {
+        String catalog = null;
         try {
-            return _pstmtPool.borrowObject(createKey(sql));
-        } catch(final NoSuchElementException e) {
-            throw new SQLException("MaxOpenPreparedStatements limit reached", e);
-        } catch(final RuntimeException e) {
-            throw e;
-        } catch(final Exception e) {
-            throw new SQLException("Borrow prepareStatement from pool failed", e);
+            catalog = getCatalog();
+        } catch (final SQLException e) {
+            // Ignored
         }
-    }
-
-    @Override
-    public PreparedStatement prepareStatement(final String sql, final int autoGeneratedKeys) throws SQLException {
-        if (null == _pstmtPool) {
-            throw new SQLException(
-                    "Statement pool is null - closed or invalid PoolingConnection.");
-        }
-        try {
-            return _pstmtPool.borrowObject(createKey(sql, autoGeneratedKeys));
-        }
-        catch (final NoSuchElementException e) {
-            throw new SQLException("MaxOpenPreparedStatements limit reached", e);
-        }
-        catch (final RuntimeException e) {
-            throw e;
-        }
-        catch (final Exception e) {
-            throw new SQLException("Borrow prepareStatement from pool failed", e);
-        }
-    }
-
-    /**
-     * Create or obtain a {@link PreparedStatement} from the pool.
-     * @param sql the sql string used to define the PreparedStatement
-     * @param resultSetType result set type
-     * @param resultSetConcurrency result set concurrency
-     * @return a {@link PoolablePreparedStatement}
-     */
-    @Override
-    public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency) throws SQLException {
-        if (null == _pstmtPool) {
-            throw new SQLException(
-                    "Statement pool is null - closed or invalid PoolingConnection.");
-        }
-        try {
-            return _pstmtPool.borrowObject(createKey(sql,resultSetType,resultSetConcurrency));
-        } catch(final NoSuchElementException e) {
-            throw new SQLException("MaxOpenPreparedStatements limit reached", e);
-        } catch(final RuntimeException e) {
-            throw e;
-        } catch(final Exception e) {
-            throw new SQLException("Borrow prepareStatement from pool failed", e);
-        }
-    }
-
-    /**
-     * Create or obtain a {@link CallableStatement} from the pool.
-     * @param sql the sql string used to define the CallableStatement
-     * @return a {@link PoolableCallableStatement}
-     * @throws SQLException
-     */
-    @Override
-    public CallableStatement prepareCall(final String sql) throws SQLException {
-        try {
-            return (CallableStatement) _pstmtPool.borrowObject(createKey(sql, StatementType.CALLABLE_STATEMENT));
-        } catch (final NoSuchElementException e) {
-            throw new SQLException("MaxOpenCallableStatements limit reached", e);
-        } catch (final RuntimeException e) {
-            throw e;
-        } catch (final Exception e) {
-            throw new SQLException("Borrow callableStatement from pool failed", e);
-        }
-    }
-
-    /**
-     * Create or obtain a {@link CallableStatement} from the pool.
-     * @param sql the sql string used to define the CallableStatement
-     * @param resultSetType result set type
-     * @param resultSetConcurrency result set concurrency
-     * @return a {@link PoolableCallableStatement}
-     * @throws SQLException
-     */
-    @Override
-    public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency) throws SQLException {
-        try {
-            return (CallableStatement) _pstmtPool.borrowObject(createKey(sql, resultSetType,
-                            resultSetConcurrency, StatementType.CALLABLE_STATEMENT));
-        } catch (final NoSuchElementException e) {
-            throw new SQLException("MaxOpenCallableStatements limit reached", e);
-        } catch (final RuntimeException e) {
-            throw e;
-        } catch (final Exception e) {
-            throw new SQLException("Borrow callableStatement from pool failed", e);
-        }
-    }
-
-    /**
-     * Create or obtain a {@link PreparedStatement} from the pool.
-     * @param sql the sql string used to define the PreparedStatement
-     * @param resultSetType result set type
-     * @param resultSetConcurrency result set concurrency
-     * @param resultSetHoldability result set holdability
-     * @return a {@link PoolablePreparedStatement}
-     */
-    @Override
-    public PreparedStatement prepareStatement(final String sql, final int resultSetType,
-            final int resultSetConcurrency, final int resultSetHoldability) throws SQLException {
-        if (null == _pstmtPool) {
-            throw new SQLException(
-                    "Statement pool is null - closed or invalid PoolingConnection.");
-        }
-        try {
-            return _pstmtPool.borrowObject(createKey(sql, resultSetType, resultSetConcurrency, resultSetHoldability));
-        } catch(final NoSuchElementException e) {
-            throw new SQLException("MaxOpenPreparedStatements limit reached", e);
-        } catch(final RuntimeException e) {
-            throw e;
-        } catch(final Exception e) {
-            throw new SQLException("Borrow prepareStatement from pool failed", e);
-        }
-    }
-
-    /**
-     * Create or obtain a {@link PreparedStatement} from the pool.
-     * @param sql the sql string used to define the PreparedStatement
-     * @param columnIndexes column indexes
-     * @return a {@link PoolablePreparedStatement}
-     */
-    @Override
-    public PreparedStatement prepareStatement(final String sql, final int columnIndexes[])
-            throws SQLException {
-        if (null == _pstmtPool) {
-            throw new SQLException(
-                    "Statement pool is null - closed or invalid PoolingConnection.");
-        }
-        try {
-            return _pstmtPool.borrowObject(createKey(sql, columnIndexes));
-        } catch(final NoSuchElementException e) {
-            throw new SQLException("MaxOpenPreparedStatements limit reached", e);
-        } catch(final RuntimeException e) {
-            throw e;
-        } catch(final Exception e) {
-            throw new SQLException("Borrow prepareStatement from pool failed", e);
-        }
-    }
-
-    /**
-     * Create or obtain a {@link PreparedStatement} from the pool.
-     * @param sql the sql string used to define the PreparedStatement
-     * @param columnNames column names
-     * @return a {@link PoolablePreparedStatement}
-     */
-    @Override
-    public PreparedStatement prepareStatement(final String sql, final String columnNames[])
-            throws SQLException {
-        if (null == _pstmtPool) {
-            throw new SQLException(
-                    "Statement pool is null - closed or invalid PoolingConnection.");
-        }
-        try {
-            return _pstmtPool.borrowObject(createKey(sql, columnNames));
-        } catch(final NoSuchElementException e) {
-            throw new SQLException("MaxOpenPreparedStatements limit reached", e);
-        } catch(final RuntimeException e) {
-            throw e;
-        } catch(final Exception e) {
-            throw new SQLException("Borrow prepareStatement from pool failed", e);
-        }
-    }
-
-    /**
-     * Create or obtain a {@link CallableStatement} from the pool.
-     * @param sql the sql string used to define the CallableStatement
-     * @param resultSetType result set type
-     * @param resultSetConcurrency result set concurrency
-     * @param resultSetHoldability result set holdability
-     * @return a {@link PoolableCallableStatement}
-     * @throws SQLException if a {@link CallableStatement} cannot be obtained
-     *                      from the pool
-     */
-    @Override
-    public CallableStatement prepareCall(final String sql, final int resultSetType,
-            final int resultSetConcurrency, final int resultSetHoldability) throws SQLException {
-        try {
-            return (CallableStatement) _pstmtPool.borrowObject(createKey(sql, resultSetType,
-                            resultSetConcurrency, resultSetHoldability, StatementType.CALLABLE_STATEMENT));
-        } catch (final NoSuchElementException e) {
-            throw new SQLException("MaxOpenCallableStatements limit reached", e);
-        } catch (final RuntimeException e) {
-            throw e;
-        } catch (final Exception e) {
-            throw new SQLException("Borrow callableStatement from pool failed", e);
-        }
+        return new PStmtKey(normalizeSQL(sql), catalog);
     }
 
     protected PStmtKey createKey(final String sql, final int autoGeneratedKeys) {
@@ -310,10 +143,32 @@
     }
 
     /**
-     * Create a PStmtKey for the given arguments.
-     * @param sql the sql string used to define the statement
-     * @param resultSetType result set type
-     * @param resultSetConcurrency result set concurrency
+     * Creates a PStmtKey for the given arguments.
+     *
+     * @param sql
+     *            the SQL string used to define the statement
+     * @param columnIndexes
+     *            column indexes
+     */
+    protected PStmtKey createKey(final String sql, final int columnIndexes[]) {
+        String catalog = null;
+        try {
+            catalog = getCatalog();
+        } catch (final SQLException e) {
+            // Ignored
+        }
+        return new PStmtKey(normalizeSQL(sql), catalog, columnIndexes);
+    }
+
+    /**
+     * Creates a PStmtKey for the given arguments.
+     *
+     * @param sql
+     *            the SQL string used to define the statement
+     * @param resultSetType
+     *            result set type
+     * @param resultSetConcurrency
+     *            result set concurrency
      */
     protected PStmtKey createKey(final String sql, final int resultSetType, final int resultSetConcurrency) {
         String catalog = null;
@@ -326,58 +181,16 @@
     }
 
     /**
-     * Create a PStmtKey for the given arguments.
-     * @param sql the sql string used to define the statement
-     * @param resultSetType result set type
-     * @param resultSetConcurrency result set concurrency
-     * @param stmtType statement type
-     */
-    protected PStmtKey createKey(final String sql, final int resultSetType, final int resultSetConcurrency, final StatementType stmtType) {
-        String catalog = null;
-        try {
-            catalog = getCatalog();
-        } catch (final SQLException e) {
-            // Ignored
-        }
-        return new PStmtKey(normalizeSQL(sql), catalog, resultSetType, resultSetConcurrency, stmtType);
-    }
-
-    /**
-     * Create a PStmtKey for the given arguments.
-     * @param sql the sql string used to define the statement
-     */
-    protected PStmtKey createKey(final String sql) {
-        String catalog = null;
-        try {
-            catalog = getCatalog();
-        } catch (final SQLException e) {
-            // Ignored
-        }
-        return new PStmtKey(normalizeSQL(sql), catalog);
-    }
-
-    /**
-     * Create a PStmtKey for the given arguments.
-     * @param sql the SQL string used to define the statement
-     * @param stmtType statement type
-     */
-    protected PStmtKey createKey(final String sql, final StatementType stmtType) {
-        String catalog = null;
-        try {
-            catalog = getCatalog();
-        } catch (final SQLException e) {
-            // Ignored
-        }
-        return new PStmtKey(normalizeSQL(sql), catalog, stmtType, null);
-    }
-
-    /**
-     * Create a PStmtKey for the given arguments.
-     * @param sql the sql string used to define the statement
-     * @param resultSetType result set type
-     * @param resultSetConcurrency result set concurrency
-     * @param resultSetHoldability result set holdability
-     * @return a newly created key for the given arguments
+     * Creates a PStmtKey for the given arguments.
+     *
+     * @param sql
+     *            the SQL string used to define the statement
+     * @param resultSetType
+     *            result set type
+     * @param resultSetConcurrency
+     *            result set concurrency
+     * @param resultSetHoldability
+     *            result set holdability
      */
     protected PStmtKey createKey(final String sql, final int resultSetType, final int resultSetConcurrency,
             final int resultSetHoldability) {
@@ -391,13 +204,18 @@
     }
 
     /**
-     * Create a PStmtKey for the given arguments.
-     * @param sql the sql string used to define the statement
-     * @param resultSetType result set type
-     * @param resultSetConcurrency result set concurrency
-     * @param resultSetHoldability result set holdability
-     * @param stmtType statement type
-     * @return a newly created key for the given arguments
+     * Creates a PStmtKey for the given arguments.
+     *
+     * @param sql
+     *            the SQL string used to define the statement
+     * @param resultSetType
+     *            result set type
+     * @param resultSetConcurrency
+     *            result set concurrency
+     * @param resultSetHoldability
+     *            result set holdability
+     * @param stmtType
+     *            statement type
      */
     protected PStmtKey createKey(final String sql, final int resultSetType, final int resultSetConcurrency,
             final int resultSetHoldability, final StatementType stmtType) {
@@ -407,30 +225,58 @@
         } catch (final SQLException e) {
             // Ignored
         }
-        return new PStmtKey(normalizeSQL(sql), catalog, resultSetType, resultSetConcurrency, resultSetHoldability,  stmtType);
+        return new PStmtKey(normalizeSQL(sql), catalog, resultSetType, resultSetConcurrency, resultSetHoldability,
+                stmtType);
     }
 
     /**
-     * Create a PStmtKey for the given arguments.
-     * @param sql the sql string used to define the statement
-     * @param columnIndexes column indexes
-     * @return a newly created key for the given arguments
+     * Creates a PStmtKey for the given arguments.
+     *
+     * @param sql
+     *            the SQL string used to define the statement
+     * @param resultSetType
+     *            result set type
+     * @param resultSetConcurrency
+     *            result set concurrency
+     * @param stmtType
+     *            statement type
      */
-    protected PStmtKey createKey(final String sql, final int columnIndexes[]) {
+    protected PStmtKey createKey(final String sql, final int resultSetType, final int resultSetConcurrency,
+            final StatementType stmtType) {
         String catalog = null;
         try {
             catalog = getCatalog();
         } catch (final SQLException e) {
             // Ignored
         }
-        return new PStmtKey(normalizeSQL(sql), catalog, columnIndexes);
+        return new PStmtKey(normalizeSQL(sql), catalog, resultSetType, resultSetConcurrency, stmtType);
     }
 
     /**
-     * Create a PStmtKey for the given arguments.
-     * @param sql the sql string used to define the statement
-     * @param columnNames column names
-     * @return a newly created key for the given arguments
+     * Creates a PStmtKey for the given arguments.
+     *
+     * @param sql
+     *            the SQL string used to define the statement
+     * @param stmtType
+     *            statement type
+     */
+    protected PStmtKey createKey(final String sql, final StatementType stmtType) {
+        String catalog = null;
+        try {
+            catalog = getCatalog();
+        } catch (final SQLException e) {
+            // Ignored
+        }
+        return new PStmtKey(normalizeSQL(sql), catalog, stmtType, null);
+    }
+
+    /**
+     * Creates a PStmtKey for the given arguments.
+     *
+     * @param sql
+     *            the SQL string used to define the statement
+     * @param columnNames
+     *            column names
      */
     protected PStmtKey createKey(final String sql, final String columnNames[]) {
         String catalog = null;
@@ -443,112 +289,327 @@
     }
 
     /**
-     * Normalize the given SQL statement, producing a
-     * canonical form that is semantically equivalent to the original.
+     * {@link KeyedPooledObjectFactory} method for destroying PoolablePreparedStatements and PoolableCallableStatements.
+     * Closes the underlying statement.
+     *
+     * @param key
+     *            ignored
+     * @param pooledObject
+     *            the wrapped pooled statement to be destroyed.
+     */
+    @Override
+    public void destroyObject(final PStmtKey key, final PooledObject<DelegatingPreparedStatement> pooledObject)
+            throws Exception {
+        pooledObject.getObject().getInnermostDelegate().close();
+    }
+
+    /**
+     * {@link KeyedPooledObjectFactory} method for creating {@link PoolablePreparedStatement}s or
+     * {@link PoolableCallableStatement}s. The <code>stmtType</code> field in the key determines whether a
+     * PoolablePreparedStatement or PoolableCallableStatement is created.
+     *
+     * @param key
+     *            the key for the {@link PreparedStatement} to be created
+     * @see #createKey(String, int, int, StatementType)
+     */
+    @SuppressWarnings("resource")
+    @Override
+    public PooledObject<DelegatingPreparedStatement> makeObject(final PStmtKey key) throws Exception {
+        if (null == key) {
+            throw new IllegalArgumentException("Prepared statement key is null or invalid.");
+        }
+        if (key.getStmtType() == StatementType.PREPARED_STATEMENT) {
+            final PreparedStatement statement = (PreparedStatement) key.createStatement(getDelegate());
+            @SuppressWarnings({"rawtypes", "unchecked" }) // Unable to find way to avoid this
+            final PoolablePreparedStatement pps = new PoolablePreparedStatement(statement, key, pstmtPool, this);
+            return new DefaultPooledObject<DelegatingPreparedStatement>(pps);
+        }
+        final CallableStatement statement = (CallableStatement) key.createStatement(getDelegate());
+        final PoolableCallableStatement pcs = new PoolableCallableStatement(statement, key, pstmtPool, this);
+        return new DefaultPooledObject<DelegatingPreparedStatement>(pcs);
+    }
+
+    /**
+     * Normalizes the given SQL statement, producing a canonical form that is semantically equivalent to the original.
      */
     protected String normalizeSQL(final String sql) {
         return sql.trim();
     }
 
     /**
-     * {@link KeyedPooledObjectFactory} method for creating
-     * {@link PoolablePreparedStatement}s or {@link PoolableCallableStatement}s.
-     * The <code>stmtType</code> field in the key determines whether
-     * a PoolablePreparedStatement or PoolableCallableStatement is created.
-     *
-     * @param key the key for the {@link PreparedStatement} to be created
-     * @see #createKey(String, int, int, StatementType)
-     */
-    @Override
-    public PooledObject<DelegatingPreparedStatement> makeObject(final PStmtKey key)
-            throws Exception {
-        if(null == key) {
-            throw new IllegalArgumentException("Prepared statement key is null or invalid.");
-        }
-        if (key.getStmtType() == StatementType.PREPARED_STATEMENT ) {
-            final PreparedStatement statement = (PreparedStatement) key.createStatement(getDelegate());
-            @SuppressWarnings({"rawtypes", "unchecked"}) // Unable to find way to avoid this
-            final
-            PoolablePreparedStatement pps = new PoolablePreparedStatement(statement, key, _pstmtPool, this);
-            return new DefaultPooledObject<DelegatingPreparedStatement>(pps);
-        }
-        final CallableStatement statement = (CallableStatement) key.createStatement(getDelegate());
-        final PoolableCallableStatement pcs = new PoolableCallableStatement(statement, key, _pstmtPool, this);
-        return new DefaultPooledObject<DelegatingPreparedStatement>(pcs);
-    }
-
-    /**
-     * {@link KeyedPooledObjectFactory} method for destroying
-     * PoolablePreparedStatements and PoolableCallableStatements.
-     * Closes the underlying statement.
-     *
-     * @param key ignored
-     * @param p the wrapped pooled statement to be destroyed.
-     */
-    @Override
-    public void destroyObject(final PStmtKey key,
-            final PooledObject<DelegatingPreparedStatement> p)
-            throws Exception {
-        p.getObject().getInnermostDelegate().close();
-    }
-
-    /**
-     * {@link KeyedPooledObjectFactory} method for validating
-     * pooled statements. Currently always returns true.
-     *
-     * @param key ignored
-     * @param p ignored
-     * @return {@code true}
-     */
-    @Override
-    public boolean validateObject(final PStmtKey key,
-            final PooledObject<DelegatingPreparedStatement> p) {
-        return true;
-    }
-
-    /**
-     * {@link KeyedPooledObjectFactory} method for activating
-     * pooled statements.
-     *
-     * @param key ignored
-     * @param p wrapped pooled statement to be activated
-     */
-    @Override
-    public void activateObject(final PStmtKey key,
-            final PooledObject<DelegatingPreparedStatement> p) throws Exception {
-        p.getObject().activate();
-    }
-
-    /**
-     * {@link KeyedPooledObjectFactory} method for passivating
-     * {@link PreparedStatement}s or {@link CallableStatement}s.
+     * {@link KeyedPooledObjectFactory} method for passivating {@link PreparedStatement}s or {@link CallableStatement}s.
      * Invokes {@link PreparedStatement#clearParameters}.
      *
-     * @param key ignored
-     * @param p a wrapped {@link PreparedStatement}
+     * @param key
+     *            ignored
+     * @param pooledObject
+     *            a wrapped {@link PreparedStatement}
      */
     @Override
-    public void passivateObject(final PStmtKey key,
-            final PooledObject<DelegatingPreparedStatement> p) throws Exception {
-        final DelegatingPreparedStatement dps = p.getObject();
+    public void passivateObject(final PStmtKey key, final PooledObject<DelegatingPreparedStatement> pooledObject)
+            throws Exception {
+        @SuppressWarnings("resource")
+        final DelegatingPreparedStatement dps = pooledObject.getObject();
         dps.clearParameters();
         dps.passivate();
     }
 
+    /**
+     * Creates or obtains a {@link CallableStatement} from the pool.
+     *
+     * @param sql
+     *            the SQL string used to define the CallableStatement
+     * @return a {@link PoolableCallableStatement}
+     * @throws SQLException
+     *             Wraps an underlying exception.
+     */
+    @Override
+    public CallableStatement prepareCall(final String sql) throws SQLException {
+        try {
+            return (CallableStatement) pstmtPool.borrowObject(createKey(sql, StatementType.CALLABLE_STATEMENT));
+        } catch (final NoSuchElementException e) {
+            throw new SQLException("MaxOpenCallableStatements limit reached", e);
+        } catch (final RuntimeException e) {
+            throw e;
+        } catch (final Exception e) {
+            throw new SQLException("Borrow callableStatement from pool failed", e);
+        }
+    }
+
+    /**
+     * Creates or obtains a {@link CallableStatement} from the pool.
+     *
+     * @param sql
+     *            the SQL string used to define the CallableStatement
+     * @param resultSetType
+     *            result set type
+     * @param resultSetConcurrency
+     *            result set concurrency
+     * @return a {@link PoolableCallableStatement}
+     * @throws SQLException
+     *             Wraps an underlying exception.
+     */
+    @Override
+    public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency)
+            throws SQLException {
+        try {
+            return (CallableStatement) pstmtPool.borrowObject(
+                    createKey(sql, resultSetType, resultSetConcurrency, StatementType.CALLABLE_STATEMENT));
+        } catch (final NoSuchElementException e) {
+            throw new SQLException("MaxOpenCallableStatements limit reached", e);
+        } catch (final RuntimeException e) {
+            throw e;
+        } catch (final Exception e) {
+            throw new SQLException("Borrow callableStatement from pool failed", e);
+        }
+    }
+
+    /**
+     * Creates or obtains a {@link CallableStatement} from the pool.
+     *
+     * @param sql
+     *            the SQL string used to define the CallableStatement
+     * @param resultSetType
+     *            result set type
+     * @param resultSetConcurrency
+     *            result set concurrency
+     * @param resultSetHoldability
+     *            result set holdability
+     * @return a {@link PoolableCallableStatement}
+     * @throws SQLException
+     *             Wraps an underlying exception.
+     */
+    @Override
+    public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency,
+            final int resultSetHoldability) throws SQLException {
+        try {
+            return (CallableStatement) pstmtPool.borrowObject(createKey(sql, resultSetType, resultSetConcurrency,
+                    resultSetHoldability, StatementType.CALLABLE_STATEMENT));
+        } catch (final NoSuchElementException e) {
+            throw new SQLException("MaxOpenCallableStatements limit reached", e);
+        } catch (final RuntimeException e) {
+            throw e;
+        } catch (final Exception e) {
+            throw new SQLException("Borrow callableStatement from pool failed", e);
+        }
+    }
+
+    /**
+     * Creates or obtains a {@link PreparedStatement} from the pool.
+     *
+     * @param sql
+     *            the SQL string used to define the PreparedStatement
+     * @return a {@link PoolablePreparedStatement}
+     */
+    @Override
+    public PreparedStatement prepareStatement(final String sql) throws SQLException {
+        if (null == pstmtPool) {
+            throw new SQLException("Statement pool is null - closed or invalid PoolingConnection.");
+        }
+        try {
+            return pstmtPool.borrowObject(createKey(sql));
+        } catch (final NoSuchElementException e) {
+            throw new SQLException("MaxOpenPreparedStatements limit reached", e);
+        } catch (final RuntimeException e) {
+            throw e;
+        } catch (final Exception e) {
+            throw new SQLException("Borrow prepareStatement from pool failed", e);
+        }
+    }
+
+    @Override
+    public PreparedStatement prepareStatement(final String sql, final int autoGeneratedKeys) throws SQLException {
+        if (null == pstmtPool) {
+            throw new SQLException("Statement pool is null - closed or invalid PoolingConnection.");
+        }
+        try {
+            return pstmtPool.borrowObject(createKey(sql, autoGeneratedKeys));
+        } catch (final NoSuchElementException e) {
+            throw new SQLException("MaxOpenPreparedStatements limit reached", e);
+        } catch (final RuntimeException e) {
+            throw e;
+        } catch (final Exception e) {
+            throw new SQLException("Borrow prepareStatement from pool failed", e);
+        }
+    }
+
+    /**
+     * Creates or obtains a {@link PreparedStatement} from the pool.
+     *
+     * @param sql
+     *            the SQL string used to define the PreparedStatement
+     * @param columnIndexes
+     *            column indexes
+     * @return a {@link PoolablePreparedStatement}
+     */
+    @Override
+    public PreparedStatement prepareStatement(final String sql, final int columnIndexes[]) throws SQLException {
+        if (null == pstmtPool) {
+            throw new SQLException("Statement pool is null - closed or invalid PoolingConnection.");
+        }
+        try {
+            return pstmtPool.borrowObject(createKey(sql, columnIndexes));
+        } catch (final NoSuchElementException e) {
+            throw new SQLException("MaxOpenPreparedStatements limit reached", e);
+        } catch (final RuntimeException e) {
+            throw e;
+        } catch (final Exception e) {
+            throw new SQLException("Borrow prepareStatement from pool failed", e);
+        }
+    }
+
+    /**
+     * Creates or obtains a {@link PreparedStatement} from the pool.
+     *
+     * @param sql
+     *            the SQL string used to define the PreparedStatement
+     * @param resultSetType
+     *            result set type
+     * @param resultSetConcurrency
+     *            result set concurrency
+     * @return a {@link PoolablePreparedStatement}
+     */
+    @Override
+    public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency)
+            throws SQLException {
+        if (null == pstmtPool) {
+            throw new SQLException("Statement pool is null - closed or invalid PoolingConnection.");
+        }
+        try {
+            return pstmtPool.borrowObject(createKey(sql, resultSetType, resultSetConcurrency));
+        } catch (final NoSuchElementException e) {
+            throw new SQLException("MaxOpenPreparedStatements limit reached", e);
+        } catch (final RuntimeException e) {
+            throw e;
+        } catch (final Exception e) {
+            throw new SQLException("Borrow prepareStatement from pool failed", e);
+        }
+    }
+
+    /**
+     * Creates or obtains a {@link PreparedStatement} from the pool.
+     *
+     * @param sql
+     *            the SQL string used to define the PreparedStatement
+     * @param resultSetType
+     *            result set type
+     * @param resultSetConcurrency
+     *            result set concurrency
+     * @param resultSetHoldability
+     *            result set holdability
+     * @return a {@link PoolablePreparedStatement}
+     */
+    @Override
+    public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency,
+            final int resultSetHoldability) throws SQLException {
+        if (null == pstmtPool) {
+            throw new SQLException("Statement pool is null - closed or invalid PoolingConnection.");
+        }
+        try {
+            return pstmtPool.borrowObject(createKey(sql, resultSetType, resultSetConcurrency, resultSetHoldability));
+        } catch (final NoSuchElementException e) {
+            throw new SQLException("MaxOpenPreparedStatements limit reached", e);
+        } catch (final RuntimeException e) {
+            throw e;
+        } catch (final Exception e) {
+            throw new SQLException("Borrow prepareStatement from pool failed", e);
+        }
+    }
+
+    /**
+     * Creates or obtains a {@link PreparedStatement} from the pool.
+     *
+     * @param sql
+     *            the SQL string used to define the PreparedStatement
+     * @param columnNames
+     *            column names
+     * @return a {@link PoolablePreparedStatement}
+     */
+    @Override
+    public PreparedStatement prepareStatement(final String sql, final String columnNames[]) throws SQLException {
+        if (null == pstmtPool) {
+            throw new SQLException("Statement pool is null - closed or invalid PoolingConnection.");
+        }
+        try {
+            return pstmtPool.borrowObject(createKey(sql, columnNames));
+        } catch (final NoSuchElementException e) {
+            throw new SQLException("MaxOpenPreparedStatements limit reached", e);
+        } catch (final RuntimeException e) {
+            throw e;
+        } catch (final Exception e) {
+            throw new SQLException("Borrow prepareStatement from pool failed", e);
+        }
+    }
+
+    /**
+     * Sets the prepared statement pool.
+     *
+     * @param pool
+     *            the prepared statement pool.
+     */
+    public void setStatementPool(final KeyedObjectPool<PStmtKey, DelegatingPreparedStatement> pool) {
+        pstmtPool = pool;
+    }
+
     @Override
     public String toString() {
-        if (_pstmtPool != null ) {
-            return "PoolingConnection: " + _pstmtPool.toString();
+        if (pstmtPool != null) {
+            return "PoolingConnection: " + pstmtPool.toString();
         }
         return "PoolingConnection: null";
     }
 
     /**
-     * The possible statement types.
-     * @since 2.0
+     * {@link KeyedPooledObjectFactory} method for validating pooled statements. Currently always returns true.
+     *
+     * @param key
+     *            ignored
+     * @param pooledObject
+     *            ignored
+     * @return {@code true}
      */
-    protected enum StatementType {
-        CALLABLE_STATEMENT,
-        PREPARED_STATEMENT
+    @Override
+    public boolean validateObject(final PStmtKey key, final PooledObject<DelegatingPreparedStatement> pooledObject) {
+        return true;
     }
 }
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/PoolingDataSource.java b/java/org/apache/tomcat/dbcp/dbcp2/PoolingDataSource.java
index c854adc..70601b0 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/PoolingDataSource.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/PoolingDataSource.java
@@ -21,6 +21,7 @@
 import java.sql.SQLException;
 import java.sql.SQLFeatureNotSupportedException;
 import java.util.NoSuchElementException;
+import java.util.Objects;
 import java.util.logging.Logger;
 
 import javax.sql.DataSource;
@@ -31,15 +32,11 @@
 import org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool;
 
 /**
- * A simple {@link DataSource} implementation that obtains
- * {@link Connection}s from the specified {@link ObjectPool}.
+ * A simple {@link DataSource} implementation that obtains {@link Connection}s from the specified {@link ObjectPool}.
  *
- * @param <C> The connection type
+ * @param <C>
+ *            The connection type
  *
- * @author Rodney Waldhoff
- * @author Glenn L. Nielsen
- * @author James House
- * @author Dirk Verbeeck
  * @since 2.0
  */
 public class PoolingDataSource<C extends Connection> implements DataSource, AutoCloseable {
@@ -47,40 +44,43 @@
     private static final Log log = LogFactory.getLog(PoolingDataSource.class);
 
     /** Controls access to the underlying connection */
-    private boolean accessToUnderlyingConnectionAllowed = false;
+    private boolean accessToUnderlyingConnectionAllowed;
 
+    /**
+     * Constructs a new instance backed by the given connection pool.
+     *
+     * @param pool
+     *            the given connection pool.
+     */
     public PoolingDataSource(final ObjectPool<C> pool) {
-        if (null == pool) {
-            throw new NullPointerException("Pool must not be null.");
-        }
-        _pool = pool;
-        // Verify that _pool's factory refers back to it.  If not, log a warning and try to fix.
-        if (_pool instanceof GenericObjectPool<?>) {
-            final PoolableConnectionFactory pcf = (PoolableConnectionFactory) ((GenericObjectPool<?>) _pool).getFactory();
-            if (pcf == null) {
-                throw new NullPointerException("PoolableConnectionFactory must not be null.");
-            }
-            if (pcf.getPool() != _pool) {
+        Objects.requireNonNull(pool, "Pool must not be null.");
+        this.pool = pool;
+        // Verify that pool's factory refers back to it. If not, log a warning and try to fix.
+        if (this.pool instanceof GenericObjectPool<?>) {
+            final PoolableConnectionFactory pcf = (PoolableConnectionFactory) ((GenericObjectPool<?>) this.pool)
+                    .getFactory();
+            Objects.requireNonNull(pcf, "PoolableConnectionFactory must not be null.");
+            if (pcf.getPool() != this.pool) {
                 log.warn(Utils.getMessage("poolingDataSource.factoryConfig"));
                 @SuppressWarnings("unchecked") // PCF must have a pool of PCs
-                final
-                ObjectPool<PoolableConnection> p = (ObjectPool<PoolableConnection>) _pool;
+                final ObjectPool<PoolableConnection> p = (ObjectPool<PoolableConnection>) this.pool;
                 pcf.setPool(p);
             }
         }
     }
 
     /**
-     * Close and free all {@link Connection}s from the pool.
+     * Closes and free all {@link Connection}s from the pool.
+     *
      * @since 2.1
      */
     @Override
     public void close() throws Exception {
         try {
-            _pool.close();
-        } catch(final RuntimeException rte) {
+            pool.close();
+        } catch (final RuntimeException rte) {
             throw new RuntimeException(Utils.getMessage("pool.close.fail"), rte);
-        } catch(final Exception e) {
+        } catch (final Exception e) {
             throw new SQLException(Utils.getMessage("pool.close.fail"), e);
         }
     }
@@ -95,11 +95,11 @@
     }
 
     /**
-     * Sets the value of the accessToUnderlyingConnectionAllowed property.
-     * It controls if the PoolGuard allows access to the underlying connection.
-     * (Default: false)
+     * Sets the value of the accessToUnderlyingConnectionAllowed property. It controls if the PoolGuard allows access to
+     * the underlying connection. (Default: false)
      *
-     * @param allow Access to the underlying connection is granted when true.
+     * @param allow
+     *            Access to the underlying connection is granted when true.
      */
     public void setAccessToUnderlyingConnectionAllowed(final boolean allow) {
         this.accessToUnderlyingConnectionAllowed = allow;
@@ -122,38 +122,40 @@
         throw new SQLFeatureNotSupportedException();
     }
 
-    //--- DataSource methods -----------------------------------------
+    // --- DataSource methods -----------------------------------------
 
     /**
-     * Return a {@link java.sql.Connection} from my pool,
-     * according to the contract specified by {@link ObjectPool#borrowObject}.
+     * Returns a {@link java.sql.Connection} from my pool, according to the contract specified by
+     * {@link ObjectPool#borrowObject}.
      */
     @Override
     public Connection getConnection() throws SQLException {
         try {
-            final C conn = _pool.borrowObject();
+            final C conn = pool.borrowObject();
             if (conn == null) {
                 return null;
             }
             return new PoolGuardConnectionWrapper<>(conn);
-        } catch(final SQLException e) {
+        } catch (final SQLException e) {
             throw e;
-        } catch(final NoSuchElementException e) {
+        } catch (final NoSuchElementException e) {
             throw new SQLException("Cannot get a connection, pool error " + e.getMessage(), e);
-        } catch(final RuntimeException e) {
+        } catch (final RuntimeException e) {
             throw e;
-        } catch(final InterruptedException e) {
+        } catch (final InterruptedException e) {
             // Reset the interrupt status so it is visible to callers
             Thread.currentThread().interrupt();
             throw new SQLException("Cannot get a connection, general error", e);
-        } catch(final Exception e) {
+        } catch (final Exception e) {
             throw new SQLException("Cannot get a connection, general error", e);
         }
     }
 
     /**
      * Throws {@link UnsupportedOperationException}
+     *
      * @throws UnsupportedOperationException
+     *             always thrown
      */
     @Override
     public Connection getConnection(final String uname, final String passwd) throws SQLException {
@@ -162,18 +164,20 @@
 
     /**
      * Returns my log writer.
+     *
      * @return my log writer
      * @see DataSource#getLogWriter
      */
     @Override
     public PrintWriter getLogWriter() {
-        return _logWriter;
+        return logWriter;
     }
 
     /**
      * Throws {@link UnsupportedOperationException}.
-     * @throws UnsupportedOperationException As this
-     *   implementation does not support this feature.
+     *
+     * @throws UnsupportedOperationException
+     *             As this implementation does not support this feature.
      */
     @Override
     public int getLoginTimeout() {
@@ -182,8 +186,9 @@
 
     /**
      * Throws {@link UnsupportedOperationException}.
-     * @throws UnsupportedOperationException As this
-     *   implementation does not support this feature.
+     *
+     * @throws UnsupportedOperationException
+     *             As this implementation does not support this feature.
      */
     @Override
     public void setLoginTimeout(final int seconds) {
@@ -192,29 +197,29 @@
 
     /**
      * Sets my log writer.
+     *
      * @see DataSource#setLogWriter
      */
     @Override
     public void setLogWriter(final PrintWriter out) {
-        _logWriter = out;
+        logWriter = out;
     }
 
     /** My log writer. */
-    private PrintWriter _logWriter = null;
+    private PrintWriter logWriter = null;
 
-    private final ObjectPool<C> _pool;
+    private final ObjectPool<C> pool;
 
     protected ObjectPool<C> getPool() {
-        return _pool;
+        return pool;
     }
 
     /**
-     * PoolGuardConnectionWrapper is a Connection wrapper that makes sure a
-     * closed connection cannot be used anymore.
+     * PoolGuardConnectionWrapper is a Connection wrapper that makes sure a closed connection cannot be used anymore.
+     *
      * @since 2.0
      */
-    private class PoolGuardConnectionWrapper<D extends Connection>
-            extends DelegatingConnection<D> {
+    private class PoolGuardConnectionWrapper<D extends Connection> extends DelegatingConnection<D> {
 
         PoolGuardConnectionWrapper(final D delegate) {
             super(delegate);
@@ -225,10 +230,7 @@
          */
         @Override
         public D getDelegate() {
-            if (isAccessToUnderlyingConnectionAllowed()) {
-                return super.getDelegate();
-            }
-            return null;
+            return isAccessToUnderlyingConnectionAllowed() ? super.getDelegate() : null;
         }
 
         /**
@@ -236,10 +238,7 @@
          */
         @Override
         public Connection getInnermostDelegate() {
-            if (isAccessToUnderlyingConnectionAllowed()) {
-                return super.getInnermostDelegate();
-            }
-            return null;
+            return isAccessToUnderlyingConnectionAllowed() ? super.getInnermostDelegate() : null;
         }
 
         @Override
@@ -252,10 +251,7 @@
 
         @Override
         public boolean isClosed() throws SQLException {
-            if (getDelegateInternal() == null) {
-                return true;
-            }
-            return super.isClosed();
+            return getDelegateInternal() == null ? true : super.isClosed();
         }
     }
 }
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/PoolingDriver.java b/java/org/apache/tomcat/dbcp/dbcp2/PoolingDriver.java
index 25889a2..4c5b495 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/PoolingDriver.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/PoolingDriver.java
@@ -30,32 +30,31 @@
 
 import org.apache.tomcat.dbcp.pool2.ObjectPool;
 
-
 /**
- * A {@link Driver} implementation that obtains
- * {@link Connection}s from a registered
- * {@link ObjectPool}.
+ * A {@link Driver} implementation that obtains {@link Connection}s from a registered {@link ObjectPool}.
  *
- * @author Rodney Waldhoff
- * @author Dirk Verbeeck
  * @since 2.0
  */
 public class PoolingDriver implements Driver {
+
     /** Register myself with the {@link DriverManager}. */
     static {
         try {
             DriverManager.registerDriver(new PoolingDriver());
-        } catch(final Exception e) {
+        } catch (final Exception e) {
+            // ignore
         }
     }
 
     /** The map of registered pools. */
-    protected static final HashMap<String,ObjectPool<? extends Connection>> pools =
-            new HashMap<>();
+    protected static final HashMap<String, ObjectPool<? extends Connection>> pools = new HashMap<>();
 
     /** Controls access to the underlying connection */
     private final boolean accessToUnderlyingConnectionAllowed;
 
+    /**
+     * Constructs a new driver with <code>accessToUnderlyingConnectionAllowed</code> enabled.
+     */
     public PoolingDriver() {
         this(true);
     }
@@ -67,7 +66,6 @@
         this.accessToUnderlyingConnectionAllowed = accessToUnderlyingConnectionAllowed;
     }
 
-
     /**
      * Returns the value of the accessToUnderlyingConnectionAllowed property.
      *
@@ -77,52 +75,75 @@
         return accessToUnderlyingConnectionAllowed;
     }
 
-    public synchronized ObjectPool<? extends Connection> getConnectionPool(final String name)
-            throws SQLException {
+    /**
+     * Gets the connection pool for the given name.
+     *
+     * @param name
+     *            The pool name
+     * @return The pool
+     * @throws SQLException
+     *             Thrown when the named pool is not registered.
+     */
+    public synchronized ObjectPool<? extends Connection> getConnectionPool(final String name) throws SQLException {
         final ObjectPool<? extends Connection> pool = pools.get(name);
         if (null == pool) {
-            throw new SQLException("Pool not registered.");
+            throw new SQLException("Pool not registered: " + name);
         }
         return pool;
     }
 
-    public synchronized void registerPool(final String name,
-            final ObjectPool<? extends Connection> pool) {
-        pools.put(name,pool);
+    /**
+     * Registers a named pool.
+     *
+     * @param name
+     *            The pool name.
+     * @param pool
+     *            The pool.
+     */
+    public synchronized void registerPool(final String name, final ObjectPool<? extends Connection> pool) {
+        pools.put(name, pool);
     }
 
+    /**
+     * Closes a named pool.
+     *
+     * @param name
+     *            The pool name.
+     * @throws SQLException
+     *             Thrown when a problem is caught closing the pool.
+     */
     public synchronized void closePool(final String name) throws SQLException {
+        @SuppressWarnings("resource")
         final ObjectPool<? extends Connection> pool = pools.get(name);
         if (pool != null) {
             pools.remove(name);
             try {
                 pool.close();
-            }
-            catch (final Exception e) {
+            } catch (final Exception e) {
                 throw new SQLException("Error closing pool " + name, e);
             }
         }
     }
 
-    public synchronized String[] getPoolNames(){
+    /**
+     * Gets the pool names.
+     *
+     * @return the pool names.
+     */
+    public synchronized String[] getPoolNames() {
         final Set<String> names = pools.keySet();
         return names.toArray(new String[names.size()]);
     }
 
     @Override
     public boolean acceptsURL(final String url) throws SQLException {
-        try {
-            return url.startsWith(URL_PREFIX);
-        } catch(final NullPointerException e) {
-            return false;
-        }
+        return url == null ? false : url.startsWith(URL_PREFIX);
     }
 
     @Override
     public Connection connect(final String url, final Properties info) throws SQLException {
-        if(acceptsURL(url)) {
-            final ObjectPool<? extends Connection> pool =
-                getConnectionPool(url.substring(URL_PREFIX_LEN));
+        if (acceptsURL(url)) {
+            final ObjectPool<? extends Connection> pool = getConnectionPool(url.substring(URL_PREFIX_LEN));
 
             try {
                 final Connection conn = pool.borrowObject();
@@ -130,13 +151,13 @@
                     return null;
                 }
                 return new PoolGuardConnectionWrapper(pool, conn);
-            } catch(final SQLException e) {
+            } catch (final SQLException e) {
                 throw e;
-            } catch(final NoSuchElementException e) {
+            } catch (final NoSuchElementException e) {
                 throw new SQLException("Cannot get a connection, pool error: " + e.getMessage(), e);
-            } catch(final RuntimeException e) {
+            } catch (final RuntimeException e) {
                 throw e;
-            } catch(final Exception e) {
+            } catch (final Exception e) {
                 throw new SQLException("Cannot get a connection, general error: " + e.getMessage(), e);
             }
         }
@@ -151,24 +172,23 @@
     /**
      * Invalidates the given connection.
      *
-     * @param conn connection to invalidate
-     * @throws SQLException if the connection is not a
-     * <code>PoolGuardConnectionWrapper</code> or an error occurs invalidating
-     * the connection
+     * @param conn
+     *            connection to invalidate
+     * @throws SQLException
+     *             if the connection is not a <code>PoolGuardConnectionWrapper</code> or an error occurs invalidating
+     *             the connection
      */
     public void invalidateConnection(final Connection conn) throws SQLException {
         if (conn instanceof PoolGuardConnectionWrapper) { // normal case
             final PoolGuardConnectionWrapper pgconn = (PoolGuardConnectionWrapper) conn;
             @SuppressWarnings("unchecked")
-            final
-            ObjectPool<Connection> pool = (ObjectPool<Connection>) pgconn.pool;
+            final ObjectPool<Connection> pool = (ObjectPool<Connection>) pgconn.pool;
             try {
                 pool.invalidateObject(pgconn.getDelegateInternal());
+            } catch (final Exception e) {
+                // Ignore.
             }
-            catch (final Exception e) {
-            }
-        }
-        else {
+        } else {
             throw new SQLException("Invalid connection class");
         }
     }
@@ -194,7 +214,7 @@
     }
 
     /** My URL prefix */
-    protected static final String URL_PREFIX = "jdbc:apache:commons:dbcp:";
+    public static final String URL_PREFIX = "jdbc:apache:commons:dbcp:";
     protected static final int URL_PREFIX_LEN = URL_PREFIX.length();
 
     // version numbers
@@ -202,16 +222,15 @@
     protected static final int MINOR_VERSION = 0;
 
     /**
-     * PoolGuardConnectionWrapper is a Connection wrapper that makes sure a
-     * closed connection cannot be used anymore.
+     * PoolGuardConnectionWrapper is a Connection wrapper that makes sure a closed connection cannot be used anymore.
+     *
      * @since 2.0
      */
     private class PoolGuardConnectionWrapper extends DelegatingConnection<Connection> {
 
         private final ObjectPool<? extends Connection> pool;
 
-        PoolGuardConnectionWrapper(final ObjectPool<? extends Connection> pool,
-                final Connection delegate) {
+        PoolGuardConnectionWrapper(final ObjectPool<? extends Connection> pool, final Connection delegate) {
             super(delegate);
             this.pool = pool;
         }
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/SwallowedExceptionLogger.java b/java/org/apache/tomcat/dbcp/dbcp2/SwallowedExceptionLogger.java
index 99f3ba7..99f0e16 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/SwallowedExceptionLogger.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/SwallowedExceptionLogger.java
@@ -21,29 +21,31 @@
 
 /**
  * Class for logging swallowed exceptions.
+ *
  * @since 2.0
  */
-public class SwallowedExceptionLogger implements SwallowedExceptionListener{
+public class SwallowedExceptionLogger implements SwallowedExceptionListener {
 
     private final Log log;
     private final boolean logExpiredConnections;
 
     /**
-     * Create a SwallowedExceptionLogger with the given logger.  By default,
-     * expired connection logging is turned on.
+     * Create a SwallowedExceptionLogger with the given logger. By default, expired connection logging is turned on.
      *
-     * @param log logger
+     * @param log
+     *            logger
      */
     public SwallowedExceptionLogger(final Log log) {
         this(log, true);
     }
 
     /**
-     * Create a SwallowedExceptionLogger with the given logger and expired
-     * connection logging property.
+     * Create a SwallowedExceptionLogger with the given logger and expired connection logging property.
      *
-     * @param log logger
-     * @param logExpiredConnections false suppresses logging of expired connection events
+     * @param log
+     *            logger
+     * @param logExpiredConnections
+     *            false suppresses logging of expired connection events
      */
     public SwallowedExceptionLogger(final Log log, final boolean logExpiredConnections) {
         this.log = log;
@@ -53,8 +55,7 @@
     @Override
     public void onSwallowException(final Exception e) {
         if (logExpiredConnections || !(e instanceof LifetimeExceededException)) {
-            log.warn(Utils.getMessage(
-                    "swallowedExceptionLogger.onSwallowedException"), e);
+            log.warn(Utils.getMessage("swallowedExceptionLogger.onSwallowedException"), e);
         }
     }
 }
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/Utils.java b/java/org/apache/tomcat/dbcp/dbcp2/Utils.java
index f9a87a2..0886b18 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/Utils.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/Utils.java
@@ -28,15 +28,18 @@
 
 /**
  * Utility methods.
+ *
  * @since 2.0
  */
 public final class Utils {
 
-    private static final ResourceBundle messages = ResourceBundle.getBundle(
-            Utils.class.getPackage().getName() + ".LocalStrings");
+    private static final ResourceBundle messages = ResourceBundle
+            .getBundle(Utils.class.getPackage().getName() + ".LocalStrings");
 
-    public static final boolean IS_SECURITY_ENABLED =
-            System.getSecurityManager() != null;
+    /**
+     * Whether the security manager is enabled.
+     */
+    public static final boolean IS_SECURITY_ENABLED = System.getSecurityManager() != null;
 
     /** Any SQL_STATE starting with this value is considered a fatal disconnect */
     public static final String DISCONNECTION_SQL_CODE_PREFIX = "08";
@@ -44,12 +47,12 @@
     /**
      * SQL codes of fatal connection errors.
      * <ul>
-     *  <li>57P01 (ADMIN SHUTDOWN)</li>
-     *  <li>57P02 (CRASH SHUTDOWN)</li>
-     *  <li>57P03 (CANNOT CONNECT NOW)</li>
-     *  <li>01002 (SQL92 disconnect error)</li>
-     *  <li>JZ0C0 (Sybase disconnect error)</li>
-     *  <li>JZ0C1 (Sybase disconnect error)</li>
+     * <li>57P01 (ADMIN SHUTDOWN)</li>
+     * <li>57P02 (CRASH SHUTDOWN)</li>
+     * <li>57P03 (CANNOT CONNECT NOW)</li>
+     * <li>01002 (SQL92 disconnect error)</li>
+     * <li>JZ0C0 (Sybase disconnect error)</li>
+     * <li>JZ0C1 (Sybase disconnect error)</li>
      * </ul>
      */
     public static final Set<String> DISCONNECTION_SQL_CODES;
@@ -71,12 +74,13 @@
     /**
      * Closes the ResultSet (which may be null).
      *
-     * @param rset a ResultSet, may be {@code null}
+     * @param resultSet
+     *            a ResultSet, may be {@code null}
      */
-    public static void closeQuietly(final ResultSet rset) {
-        if (rset != null) {
+    public static void closeQuietly(final ResultSet resultSet) {
+        if (resultSet != null) {
             try {
-                rset.close();
+                resultSet.close();
             } catch (final Exception e) {
                 // ignored
             }
@@ -86,12 +90,13 @@
     /**
      * Closes the Connection (which may be null).
      *
-     * @param conn a Connection, may be {@code null}
+     * @param connection
+     *            a Connection, may be {@code null}
      */
-    public static void closeQuietly(final Connection conn) {
-        if (conn != null) {
+    public static void closeQuietly(final Connection connection) {
+        if (connection != null) {
             try {
-                conn.close();
+                connection.close();
             } catch (final Exception e) {
                 // ignored
             }
@@ -101,37 +106,67 @@
     /**
      * Closes the Statement (which may be null).
      *
-     * @param stmt a Statement, may be {@code null}
+     * @param statement
+     *            a Statement, may be {@code null}.
      */
-    public static void closeQuietly(final Statement stmt) {
-        if (stmt != null) {
+    public static void closeQuietly(final Statement statement) {
+        if (statement != null) {
             try {
-                stmt.close();
+                statement.close();
             } catch (final Exception e) {
                 // ignored
             }
         }
     }
 
-
     /**
-     * Obtain the correct i18n message for the given key.
+     * Gets the correct i18n message for the given key.
+     *
+     * @param key
+     *            The key to look up an i18n message.
+     * @return The i18n message.
      */
     public static String getMessage(final String key) {
         return getMessage(key, (Object[]) null);
     }
 
-
     /**
-     * Obtain the correct i18n message for the given key with placeholders
-     * replaced by the supplied arguments.
+     * Gets the correct i18n message for the given key with placeholders replaced by the supplied arguments.
+     *
+     * @param key
+     *            A message key.
+     * @param args
+     *            The message arguments.
+     * @return An i18n message.
      */
     public static String getMessage(final String key, final Object... args) {
-        final String msg =  messages.getString(key);
+        final String msg = messages.getString(key);
         if (args == null || args.length == 0) {
             return msg;
         }
         final MessageFormat mf = new MessageFormat(msg);
         return mf.format(args, new StringBuffer(), null).toString();
     }
+
+    /**
+     * Converts the given String to a char[].
+     *
+     * @param value
+     *            may be null.
+     * @return a char[] or null.
+     */
+    public static char[] toCharArray(final String value) {
+        return value != null ? value.toCharArray() : null;
+    }
+
+    /**
+     * Converts the given char[] to a String.
+     *
+     * @param value
+     *            may be null.
+     * @return a String or null.
+     */
+    public static String toString(final char[] value) {
+        return value == null ? null : String.valueOf(value);
+    }
 }
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/ConnectionImpl.java b/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/ConnectionImpl.java
index 5e1af7e..ca6498a 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/ConnectionImpl.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/ConnectionImpl.java
@@ -17,26 +17,25 @@
 
 package org.apache.tomcat.dbcp.dbcp2.cpdsadapter;
 
+import java.sql.CallableStatement;
 import java.sql.Connection;
 import java.sql.PreparedStatement;
 import java.sql.SQLException;
 
+import org.apache.tomcat.dbcp.dbcp2.DelegatingCallableStatement;
 import org.apache.tomcat.dbcp.dbcp2.DelegatingConnection;
 import org.apache.tomcat.dbcp.dbcp2.DelegatingPreparedStatement;
 
 /**
- * This class is the <code>Connection</code> that will be returned
- * from <code>PooledConnectionImpl.getConnection()</code>.
- * Most methods are wrappers around the JDBC 1.x <code>Connection</code>.
- * A few exceptions include preparedStatement and close.
- * In accordance with the JDBC specification this Connection cannot
- * be used after closed() is called.  Any further usage will result in an
+ * This class is the <code>Connection</code> that will be returned from
+ * <code>PooledConnectionImpl.getConnection()</code>. Most methods are wrappers around the JDBC 1.x
+ * <code>Connection</code>. A few exceptions include preparedStatement and close. In accordance with the JDBC
+ * specification this Connection cannot be used after closed() is called. Any further usage will result in an
  * SQLException.
+ * <p>
+ * ConnectionImpl extends DelegatingConnection to enable access to the underlying connection.
+ * </p>
  *
- * ConnectionImpl extends DelegatingConnection to enable access to the
- * underlying connection.
- *
- * @author John D. McNally
  * @since 2.0
  */
 class ConnectionImpl extends DelegatingConnection<Connection> {
@@ -44,32 +43,34 @@
     private final boolean accessToUnderlyingConnectionAllowed;
 
     /** The object that instantiated this object */
-     private final PooledConnectionImpl pooledConnection;
+    private final PooledConnectionImpl pooledConnection;
 
     /**
      * Creates a <code>ConnectionImpl</code>.
      *
-     * @param pooledConnection The PooledConnection that is calling the ctor.
-     * @param connection The JDBC 1.x Connection to wrap.
-     * @param accessToUnderlyingConnectionAllowed if true, then access is allowed to the underlying connection
+     * @param pooledConnection
+     *            The PooledConnection that is calling the ctor.
+     * @param connection
+     *            The JDBC 1.x Connection to wrap.
+     * @param accessToUnderlyingConnectionAllowed
+     *            if true, then access is allowed to the underlying connection
      */
-    ConnectionImpl(final PooledConnectionImpl pooledConnection,
-            final Connection connection,
+    ConnectionImpl(final PooledConnectionImpl pooledConnection, final Connection connection,
             final boolean accessToUnderlyingConnectionAllowed) {
         super(connection);
         this.pooledConnection = pooledConnection;
-        this.accessToUnderlyingConnectionAllowed =
-            accessToUnderlyingConnectionAllowed;
+        this.accessToUnderlyingConnectionAllowed = accessToUnderlyingConnectionAllowed;
     }
 
     /**
-     * Marks the Connection as closed, and notifies the pool that the
-     * pooled connection is available.
-     * In accordance with the JDBC specification this Connection cannot
-     * be used after closed() is called.  Any further usage will result in an
-     * SQLException.
+     * Marks the Connection as closed, and notifies the pool that the pooled connection is available.
+     * <p>
+     * In accordance with the JDBC specification this Connection cannot be used after closed() is called. Any further
+     * usage will result in an SQLException.
+     * </p>
      *
-     * @throws SQLException The database connection couldn't be closed.
+     * @throws SQLException
+     *             The database connection couldn't be closed.
      */
     @Override
     public void close() throws SQLException {
@@ -84,106 +85,179 @@
     }
 
     /**
-     * If pooling of <code>PreparedStatement</code>s is turned on in the
-     * {@link DriverAdapterCPDS}, a pooled object may be returned, otherwise
-     * delegate to the wrapped JDBC 1.x {@link java.sql.Connection}.
+     * If pooling of <code>CallableStatement</code>s is turned on in the {@link DriverAdapterCPDS}, a pooled object may
+     * be returned, otherwise delegate to the wrapped JDBC 1.x {@link java.sql.Connection}.
      *
-     * @param sql SQL statement to be prepared
-     * @return the prepared statement
-     * @throws SQLException if this connection is closed or an error occurs
-     * in the wrapped connection.
+     * @param sql
+     *            an SQL statement that may contain one or more '?' parameter placeholders. Typically this statement is
+     *            specified using JDBC call escape syntax.
+     * @return a default <code>CallableStatement</code> object containing the pre-compiled SQL statement.
+     * @exception SQLException
+     *                Thrown if a database access error occurs or this method is called on a closed connection.
+     * @since 2.4.0
      */
     @Override
-    public PreparedStatement prepareStatement(final String sql) throws SQLException {
+    public CallableStatement prepareCall(final String sql) throws SQLException {
         checkOpen();
         try {
-            return new DelegatingPreparedStatement
-                (this, pooledConnection.prepareStatement(sql));
-        }
-        catch (final SQLException e) {
+            return new DelegatingCallableStatement(this, pooledConnection.prepareCall(sql));
+        } catch (final SQLException e) {
             handleException(e); // Does not return
             return null;
         }
     }
 
     /**
-     * If pooling of <code>PreparedStatement</code>s is turned on in the
-     * {@link DriverAdapterCPDS}, a pooled object may be returned, otherwise
-     * delegate to the wrapped JDBC 1.x {@link java.sql.Connection}.
+     * If pooling of <code>CallableStatement</code>s is turned on in the {@link DriverAdapterCPDS}, a pooled object may
+     * be returned, otherwise delegate to the wrapped JDBC 1.x {@link java.sql.Connection}.
      *
-     * @throws SQLException if this connection is closed or an error occurs
-     * in the wrapped connection.
+     * @param sql
+     *            a <code>String</code> object that is the SQL statement to be sent to the database; may contain on or
+     *            more '?' parameters.
+     * @param resultSetType
+     *            a result set type; one of <code>ResultSet.TYPE_FORWARD_ONLY</code>,
+     *            <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>.
+     * @param resultSetConcurrency
+     *            a concurrency type; one of <code>ResultSet.CONCUR_READ_ONLY</code> or
+     *            <code>ResultSet.CONCUR_UPDATABLE</code>.
+     * @return a <code>CallableStatement</code> object containing the pre-compiled SQL statement that will produce
+     *         <code>ResultSet</code> objects with the given type and concurrency.
+     * @throws SQLException
+     *             Thrown if a database access error occurs, this method is called on a closed connection or the given
+     *             parameters are not <code>ResultSet</code> constants indicating type and concurrency.
+     * @since 2.4.0
      */
     @Override
-    public PreparedStatement prepareStatement(final String sql, final int resultSetType,
-                                              final int resultSetConcurrency)
+    public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency)
             throws SQLException {
         checkOpen();
         try {
-            return new DelegatingPreparedStatement
-                (this, pooledConnection.prepareStatement
-                    (sql,resultSetType,resultSetConcurrency));
+            return new DelegatingCallableStatement(this,
+                    pooledConnection.prepareCall(sql, resultSetType, resultSetConcurrency));
+        } catch (final SQLException e) {
+            handleException(e); // Does not return
+            return null;
         }
-        catch (final SQLException e) {
+    }
+
+    /**
+     * If pooling of <code>CallableStatement</code>s is turned on in the {@link DriverAdapterCPDS}, a pooled object may
+     * be returned, otherwise delegate to the wrapped JDBC 1.x {@link java.sql.Connection}.
+     *
+     * @param sql
+     *            a <code>String</code> object that is the SQL statement to be sent to the database; may contain on or
+     *            more '?' parameters.
+     * @param resultSetType
+     *            one of the following <code>ResultSet</code> constants: <code>ResultSet.TYPE_FORWARD_ONLY</code>,
+     *            <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>.
+     * @param resultSetConcurrency
+     *            one of the following <code>ResultSet</code> constants: <code>ResultSet.CONCUR_READ_ONLY</code> or
+     *            <code>ResultSet.CONCUR_UPDATABLE</code>.
+     * @param resultSetHoldability
+     *            one of the following <code>ResultSet</code> constants: <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code>
+     *            or <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>.
+     * @return a new <code>CallableStatement</code> object, containing the pre-compiled SQL statement, that will
+     *         generate <code>ResultSet</code> objects with the given type, concurrency, and holdability.
+     * @throws SQLException
+     *             Thrown if a database access error occurs, this method is called on a closed connection or the given
+     *             parameters are not <code>ResultSet</code> constants indicating type, concurrency, and holdability.
+     * @since 2.4.0
+     */
+    @Override
+    public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency,
+            final int resultSetHoldability) throws SQLException {
+        checkOpen();
+        try {
+            return new DelegatingCallableStatement(this,
+                    pooledConnection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability));
+        } catch (final SQLException e) {
+            handleException(e); // Does not return
+            return null;
+        }
+    }
+
+    /**
+     * If pooling of <code>PreparedStatement</code>s is turned on in the {@link DriverAdapterCPDS}, a pooled object may
+     * be returned, otherwise delegate to the wrapped JDBC 1.x {@link java.sql.Connection}.
+     *
+     * @param sql
+     *            SQL statement to be prepared
+     * @return the prepared statement
+     * @throws SQLException
+     *             if this connection is closed or an error occurs in the wrapped connection.
+     */
+    @Override
+    public PreparedStatement prepareStatement(final String sql) throws SQLException {
+        checkOpen();
+        try {
+            return new DelegatingPreparedStatement(this, pooledConnection.prepareStatement(sql));
+        } catch (final SQLException e) {
+            handleException(e); // Does not return
+            return null;
+        }
+    }
+
+    /**
+     * If pooling of <code>PreparedStatement</code>s is turned on in the {@link DriverAdapterCPDS}, a pooled object may
+     * be returned, otherwise delegate to the wrapped JDBC 1.x {@link java.sql.Connection}.
+     *
+     * @throws SQLException
+     *             if this connection is closed or an error occurs in the wrapped connection.
+     */
+    @Override
+    public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency)
+            throws SQLException {
+        checkOpen();
+        try {
+            return new DelegatingPreparedStatement(this,
+                    pooledConnection.prepareStatement(sql, resultSetType, resultSetConcurrency));
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
     }
 
     @Override
-    public PreparedStatement prepareStatement(final String sql, final int resultSetType,
-                                              final int resultSetConcurrency,
-                                              final int resultSetHoldability)
-            throws SQLException {
+    public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency,
+            final int resultSetHoldability) throws SQLException {
         checkOpen();
         try {
             return new DelegatingPreparedStatement(this,
-                    pooledConnection.prepareStatement(sql, resultSetType,
-                            resultSetConcurrency, resultSetHoldability));
-        }
-        catch (final SQLException e) {
+                    pooledConnection.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability));
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
     }
 
     @Override
-    public PreparedStatement prepareStatement(final String sql, final int autoGeneratedKeys)
-            throws SQLException {
+    public PreparedStatement prepareStatement(final String sql, final int autoGeneratedKeys) throws SQLException {
         checkOpen();
         try {
-            return new DelegatingPreparedStatement(this,
-                    pooledConnection.prepareStatement(sql, autoGeneratedKeys));
-        }
-        catch (final SQLException e) {
+            return new DelegatingPreparedStatement(this, pooledConnection.prepareStatement(sql, autoGeneratedKeys));
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
     }
 
     @Override
-    public PreparedStatement prepareStatement(final String sql, final int columnIndexes[])
-            throws SQLException {
+    public PreparedStatement prepareStatement(final String sql, final int columnIndexes[]) throws SQLException {
         checkOpen();
         try {
-            return new DelegatingPreparedStatement(this,
-                    pooledConnection.prepareStatement(sql, columnIndexes));
-        }
-        catch (final SQLException e) {
+            return new DelegatingPreparedStatement(this, pooledConnection.prepareStatement(sql, columnIndexes));
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
     }
 
     @Override
-    public PreparedStatement prepareStatement(final String sql, final String columnNames[])
-            throws SQLException {
+    public PreparedStatement prepareStatement(final String sql, final String columnNames[]) throws SQLException {
         checkOpen();
         try {
-            return new DelegatingPreparedStatement(this,
-                    pooledConnection.prepareStatement(sql, columnNames));
-        }
-        catch (final SQLException e) {
+            return new DelegatingPreparedStatement(this, pooledConnection.prepareStatement(sql, columnNames));
+        } catch (final SQLException e) {
             handleException(e);
             return null;
         }
@@ -195,6 +269,7 @@
 
     /**
      * If false, getDelegate() and getInnermostDelegate() will return null.
+     *
      * @return true if access is allowed to the underlying connection
      * @see ConnectionImpl
      */
@@ -204,6 +279,7 @@
 
     /**
      * Get the delegated connection, if allowed.
+     *
      * @return the internal connection, or null if access is not allowed.
      * @see #isAccessToUnderlyingConnectionAllowed()
      */
@@ -217,6 +293,7 @@
 
     /**
      * Get the innermost connection, if allowed.
+     *
      * @return the innermost internal connection, or null if access is not allowed.
      * @see #isAccessToUnderlyingConnectionAllowed()
      */
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java b/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java
index 994751e..ba9c2c2 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java
@@ -37,7 +37,9 @@
 import javax.sql.ConnectionPoolDataSource;
 import javax.sql.PooledConnection;
 
-import org.apache.tomcat.dbcp.dbcp2.PoolablePreparedStatement;
+import org.apache.tomcat.dbcp.dbcp2.DelegatingPreparedStatement;
+import org.apache.tomcat.dbcp.dbcp2.PStmtKey;
+import org.apache.tomcat.dbcp.dbcp2.Utils;
 import org.apache.tomcat.dbcp.pool2.KeyedObjectPool;
 import org.apache.tomcat.dbcp.pool2.impl.BaseObjectPoolConfig;
 import org.apache.tomcat.dbcp.pool2.impl.GenericKeyedObjectPool;
@@ -45,92 +47,79 @@
 
 /**
  * <p>
- * An adapter for JDBC drivers that do not include an implementation
- * of {@link javax.sql.ConnectionPoolDataSource}, but still include a
- * {@link java.sql.DriverManager} implementation.
- * <code>ConnectionPoolDataSource</code>s are not used within general
- * applications.  They are used by <code>DataSource</code> implementations
- * that pool <code>Connection</code>s, such as
- * {@link org.apache.tomcat.dbcp.dbcp2.datasources.SharedPoolDataSource}.  A J2EE
- * container will normally provide some method of initializing the
- * <code>ConnectionPoolDataSource</code> whose attributes are presented
- * as bean getters/setters and then deploying it via JNDI.  It is then
- * available as a source of physical connections to the database, when
- * the pooling <code>DataSource</code> needs to create a new
- * physical connection.
+ * An adapter for JDBC drivers that do not include an implementation of {@link javax.sql.ConnectionPoolDataSource}, but
+ * still include a {@link java.sql.DriverManager} implementation. <code>ConnectionPoolDataSource</code>s are not used
+ * within general applications. They are used by <code>DataSource</code> implementations that pool
+ * <code>Connection</code>s, such as {@link org.apache.tomcat.dbcp.dbcp2.datasources.SharedPoolDataSource}. A J2EE container
+ * will normally provide some method of initializing the <code>ConnectionPoolDataSource</code> whose attributes are
+ * presented as bean getters/setters and then deploying it via JNDI. It is then available as a source of physical
+ * connections to the database, when the pooling <code>DataSource</code> needs to create a new physical connection.
  * </p>
- *
  * <p>
- * Although normally used within a JNDI environment, the DriverAdapterCPDS
- * can be instantiated and initialized as any bean and then attached
- * directly to a pooling <code>DataSource</code>.
- * <code>Jdbc2PoolDataSource</code> can use the
+ * Although normally used within a JNDI environment, the DriverAdapterCPDS can be instantiated and initialized as any
+ * bean and then attached directly to a pooling <code>DataSource</code>. <code>Jdbc2PoolDataSource</code> can use the
  * <code>ConnectionPoolDataSource</code> with or without the use of JNDI.
  * </p>
- *
  * <p>
- * The DriverAdapterCPDS also provides <code>PreparedStatement</code> pooling
- * which is not generally available in jdbc2
- * <code>ConnectionPoolDataSource</code> implementation, but is
- * addressed within the jdbc3 specification.  The <code>PreparedStatement</code>
- * pool in DriverAdapterCPDS has been in the dbcp package for some time, but
- * it has not undergone extensive testing in the configuration used here.
- * It should be considered experimental and can be toggled with the
- * poolPreparedStatements attribute.
+ * The DriverAdapterCPDS also provides <code>PreparedStatement</code> pooling which is not generally available in jdbc2
+ * <code>ConnectionPoolDataSource</code> implementation, but is addressed within the jdbc3 specification. The
+ * <code>PreparedStatement</code> pool in DriverAdapterCPDS has been in the dbcp package for some time, but it has not
+ * undergone extensive testing in the configuration used here. It should be considered experimental and can be toggled
+ * with the poolPreparedStatements attribute.
+ * </p>
+ * <p>
+ * The <a href="package-summary.html">package documentation</a> contains an example using catalina and JNDI. The
+ * <a href="../datasources/package-summary.html">datasources package documentation</a> shows how to use
+ * <code>DriverAdapterCPDS</code> as a source for <code>Jdbc2PoolDataSource</code> without the use of JNDI.
  * </p>
  *
- * <p>
- * The <a href="package-summary.html">package documentation</a> contains an
- * example using catalina and JNDI.  The <a
- * href="../datasources/package-summary.html">datasources package documentation</a>
- * shows how to use <code>DriverAdapterCPDS</code> as a source for
- * <code>Jdbc2PoolDataSource</code> without the use of JNDI.
- * </p>
- *
- * @author John D. McNally
  * @since 2.0
  */
-public class DriverAdapterCPDS
-    implements ConnectionPoolDataSource, Referenceable, Serializable,
-               ObjectFactory {
+public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceable, Serializable, ObjectFactory {
+
+    private static final String KEY_USER = "user";
+
+    private static final String KEY_PASSWORD = "password";
 
     private static final long serialVersionUID = -4820523787212147844L;
 
-
-    private static final String GET_CONNECTION_CALLED
-            = "A PooledConnection was already requested from this source, "
+    private static final String GET_CONNECTION_CALLED = "A PooledConnection was already requested from this source, "
             + "further initialization is not allowed.";
 
     /** Description */
     private String description;
-    /** Password */
-    private String password;
+
     /** Url name */
     private String url;
+
     /** User name */
-    private String user;
+    private String userName;
+
+    /** User password */
+    private char[] userPassword;
+
     /** Driver class name */
     private String driver;
 
     /** Login TimeOut in seconds */
     private int loginTimeout;
+
     /** Log stream. NOT USED */
-    private transient PrintWriter logWriter = null;
+    private transient PrintWriter logWriter;
 
     // PreparedStatement pool properties
     private boolean poolPreparedStatements;
     private int maxIdle = 10;
-    private long _timeBetweenEvictionRunsMillis =
-            BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
-    private int _numTestsPerEvictionRun = -1;
-    private int _minEvictableIdleTimeMillis = -1;
-    private int _maxPreparedStatements = -1;
+    private long timeBetweenEvictionRunsMillis = BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
+    private int numTestsPerEvictionRun = -1;
+    private int minEvictableIdleTimeMillis = -1;
+    private int maxPreparedStatements = -1;
 
     /** Whether or not getConnection has been called */
-    private volatile boolean getConnectionCalled = false;
+    private volatile boolean getConnectionCalled;
 
     /** Connection properties passed to JDBC Driver */
-    private Properties connectionProperties = null;
+    private Properties connectionProperties;
 
     static {
         // Attempt to prevent deadlocks - see DBCP - 272
@@ -140,7 +129,7 @@
     /**
      * Controls access to the underlying connection
      */
-    private boolean accessToUnderlyingConnectionAllowed = false;
+    private boolean accessToUnderlyingConnectionAllowed;
 
     /**
      * Default no-arg constructor for Serialization
@@ -149,8 +138,7 @@
     }
 
     /**
-     * Attempt to establish a database connection using the default
-     * user and password.
+     * Attempts to establish a database connection using the default user and password.
      */
     @Override
     public PooledConnection getPooledConnection() throws SQLException {
@@ -159,68 +147,65 @@
 
     /**
      * Attempt to establish a database connection.
-     * @param username name to be used for the connection
-     * @param pass password to be used fur the connection
+     *
+     * @param pooledUserName
+     *            name to be used for the connection
+     * @param pooledUserPassword
+     *            password to be used fur the connection
      */
     @Override
-    public PooledConnection getPooledConnection(final String username, final String pass)
+    public PooledConnection getPooledConnection(final String pooledUserName, final String pooledUserPassword)
             throws SQLException {
         getConnectionCalled = true;
-        PooledConnectionImpl pci = null;
-        // Workaround for buggy WebLogic 5.1 classloader - ignore the
-        // exception upon first invocation.
+        PooledConnectionImpl pooledConnection = null;
+        // Workaround for buggy WebLogic 5.1 classloader - ignore the exception upon first invocation.
         try {
             if (connectionProperties != null) {
-                connectionProperties.put("user", username);
-                connectionProperties.put("password", pass);
-                pci = new PooledConnectionImpl(DriverManager.getConnection(
-                        getUrl(), connectionProperties));
+                update(connectionProperties, KEY_USER, pooledUserName);
+                update(connectionProperties, KEY_PASSWORD, pooledUserPassword);
+                pooledConnection = new PooledConnectionImpl(
+                        DriverManager.getConnection(getUrl(), connectionProperties));
             } else {
-                pci = new PooledConnectionImpl(DriverManager.getConnection(
-                        getUrl(), username, pass));
+                pooledConnection = new PooledConnectionImpl(
+                        DriverManager.getConnection(getUrl(), pooledUserName, pooledUserPassword));
             }
-            pci.setAccessToUnderlyingConnectionAllowed(isAccessToUnderlyingConnectionAllowed());
-        }
-        catch (final ClassCircularityError e)
-        {
+            pooledConnection.setAccessToUnderlyingConnectionAllowed(isAccessToUnderlyingConnectionAllowed());
+        } catch (final ClassCircularityError e) {
             if (connectionProperties != null) {
-                pci = new PooledConnectionImpl(DriverManager.getConnection(
-                        getUrl(), connectionProperties));
+                pooledConnection = new PooledConnectionImpl(
+                        DriverManager.getConnection(getUrl(), connectionProperties));
             } else {
-                pci = new PooledConnectionImpl(DriverManager.getConnection(
-                        getUrl(), username, pass));
+                pooledConnection = new PooledConnectionImpl(
+                        DriverManager.getConnection(getUrl(), pooledUserName, pooledUserPassword));
             }
-            pci.setAccessToUnderlyingConnectionAllowed(isAccessToUnderlyingConnectionAllowed());
+            pooledConnection.setAccessToUnderlyingConnectionAllowed(isAccessToUnderlyingConnectionAllowed());
         }
-        KeyedObjectPool<PStmtKeyCPDS, PoolablePreparedStatement<PStmtKeyCPDS>> stmtPool = null;
+        KeyedObjectPool<PStmtKey, DelegatingPreparedStatement> stmtPool = null;
         if (isPoolPreparedStatements()) {
-            final GenericKeyedObjectPoolConfig<PoolablePreparedStatement<PStmtKeyCPDS>> config = new GenericKeyedObjectPoolConfig<>();
+            final GenericKeyedObjectPoolConfig config = new GenericKeyedObjectPoolConfig();
             config.setMaxTotalPerKey(Integer.MAX_VALUE);
             config.setBlockWhenExhausted(false);
             config.setMaxWaitMillis(0);
             config.setMaxIdlePerKey(getMaxIdle());
-            if (getMaxPreparedStatements() <= 0)
-            {
-                // since there is no limit, create a prepared statement pool with an eviction thread
-                //  evictor settings are the same as the connection pool settings.
+            if (getMaxPreparedStatements() <= 0) {
+                // since there is no limit, create a prepared statement pool with an eviction thread;
+                // evictor settings are the same as the connection pool settings.
                 config.setTimeBetweenEvictionRunsMillis(getTimeBetweenEvictionRunsMillis());
                 config.setNumTestsPerEvictionRun(getNumTestsPerEvictionRun());
                 config.setMinEvictableIdleTimeMillis(getMinEvictableIdleTimeMillis());
-            }
-            else
-            {
-                // since there is limit, create a prepared statement pool without an eviction thread
-                //  pool has LRU functionality so when the limit is reached, 15% of the pool is cleared.
-                // see org.apache.tomcat.dbcp.pool2.impl.GenericKeyedObjectPool.clearOldest method
+            } else {
+                // since there is a limit, create a prepared statement pool without an eviction thread;
+                // pool has LRU functionality so when the limit is reached, 15% of the pool is cleared.
+                // see org.apache.commons.pool2.impl.GenericKeyedObjectPool.clearOldest method
                 config.setMaxTotal(getMaxPreparedStatements());
                 config.setTimeBetweenEvictionRunsMillis(-1);
                 config.setNumTestsPerEvictionRun(0);
                 config.setMinEvictableIdleTimeMillis(0);
             }
-            stmtPool = new GenericKeyedObjectPool<>(pci, config);
-            pci.setStatementPool(stmtPool);
+            stmtPool = new GenericKeyedObjectPool<>(pooledConnection, config);
+            pooledConnection.setStatementPool(stmtPool);
         }
-        return pci;
+        return pooledConnection;
     }
 
     @Override
@@ -243,29 +228,21 @@
 
         ref.add(new StringRefAddr("description", getDescription()));
         ref.add(new StringRefAddr("driver", getDriver()));
-        ref.add(new StringRefAddr("loginTimeout",
-                                  String.valueOf(getLoginTimeout())));
-        ref.add(new StringRefAddr("password", getPassword()));
-        ref.add(new StringRefAddr("user", getUser()));
+        ref.add(new StringRefAddr("loginTimeout", String.valueOf(getLoginTimeout())));
+        ref.add(new StringRefAddr(KEY_PASSWORD, getPassword()));
+        ref.add(new StringRefAddr(KEY_USER, getUser()));
         ref.add(new StringRefAddr("url", getUrl()));
 
-        ref.add(new StringRefAddr("poolPreparedStatements",
-                                  String.valueOf(isPoolPreparedStatements())));
-        ref.add(new StringRefAddr("maxIdle",
-                                  String.valueOf(getMaxIdle())));
-        ref.add(new StringRefAddr("timeBetweenEvictionRunsMillis",
-            String.valueOf(getTimeBetweenEvictionRunsMillis())));
-        ref.add(new StringRefAddr("numTestsPerEvictionRun",
-            String.valueOf(getNumTestsPerEvictionRun())));
-        ref.add(new StringRefAddr("minEvictableIdleTimeMillis",
-            String.valueOf(getMinEvictableIdleTimeMillis())));
-        ref.add(new StringRefAddr("maxPreparedStatements",
-            String.valueOf(getMaxPreparedStatements())));
+        ref.add(new StringRefAddr("poolPreparedStatements", String.valueOf(isPoolPreparedStatements())));
+        ref.add(new StringRefAddr("maxIdle", String.valueOf(getMaxIdle())));
+        ref.add(new StringRefAddr("timeBetweenEvictionRunsMillis", String.valueOf(getTimeBetweenEvictionRunsMillis())));
+        ref.add(new StringRefAddr("numTestsPerEvictionRun", String.valueOf(getNumTestsPerEvictionRun())));
+        ref.add(new StringRefAddr("minEvictableIdleTimeMillis", String.valueOf(getMinEvictableIdleTimeMillis())));
+        ref.add(new StringRefAddr("maxPreparedStatements", String.valueOf(getMaxPreparedStatements())));
 
         return ref;
     }
 
-
     // ----------------------------------------------------------------------
     // ObjectFactory implementation
 
@@ -273,14 +250,13 @@
      * implements ObjectFactory to create an instance of this class
      */
     @Override
-    public Object getObjectInstance(final Object refObj, final Name name,
-                                    final Context context, final Hashtable<?,?> env)
-            throws Exception {
+    public Object getObjectInstance(final Object refObj, final Name name, final Context context,
+            final Hashtable<?, ?> env) throws Exception {
         // The spec says to return null if we can't create an instance
         // of the reference
         DriverAdapterCPDS cpds = null;
         if (refObj instanceof Reference) {
-            final Reference ref = (Reference)refObj;
+            final Reference ref = (Reference) refObj;
             if (ref.getClassName().equals(getClass().getName())) {
                 RefAddr ra = ref.get("description");
                 if (ra != null && ra.getContent() != null) {
@@ -295,19 +271,18 @@
                 if (ra != null && ra.getContent() != null) {
                     setUrl(ra.getContent().toString());
                 }
-                ra = ref.get("user");
+                ra = ref.get(KEY_USER);
                 if (ra != null && ra.getContent() != null) {
                     setUser(ra.getContent().toString());
                 }
-                ra = ref.get("password");
+                ra = ref.get(KEY_PASSWORD);
                 if (ra != null && ra.getContent() != null) {
                     setPassword(ra.getContent().toString());
                 }
 
                 ra = ref.get("poolPreparedStatements");
                 if (ra != null && ra.getContent() != null) {
-                    setPoolPreparedStatements(Boolean.valueOf(
-                        ra.getContent().toString()).booleanValue());
+                    setPoolPreparedStatements(Boolean.valueOf(ra.getContent().toString()).booleanValue());
                 }
                 ra = ref.get("maxIdle");
                 if (ra != null && ra.getContent() != null) {
@@ -316,31 +291,26 @@
 
                 ra = ref.get("timeBetweenEvictionRunsMillis");
                 if (ra != null && ra.getContent() != null) {
-                    setTimeBetweenEvictionRunsMillis(
-                        Integer.parseInt(ra.getContent().toString()));
+                    setTimeBetweenEvictionRunsMillis(Integer.parseInt(ra.getContent().toString()));
                 }
 
                 ra = ref.get("numTestsPerEvictionRun");
                 if (ra != null && ra.getContent() != null) {
-                    setNumTestsPerEvictionRun(
-                        Integer.parseInt(ra.getContent().toString()));
+                    setNumTestsPerEvictionRun(Integer.parseInt(ra.getContent().toString()));
                 }
 
                 ra = ref.get("minEvictableIdleTimeMillis");
                 if (ra != null && ra.getContent() != null) {
-                    setMinEvictableIdleTimeMillis(
-                        Integer.parseInt(ra.getContent().toString()));
+                    setMinEvictableIdleTimeMillis(Integer.parseInt(ra.getContent().toString()));
                 }
                 ra = ref.get("maxPreparedStatements");
                 if (ra != null && ra.getContent() != null) {
-                    setMaxPreparedStatements(
-                        Integer.parseInt(ra.getContent().toString()));
+                    setMaxPreparedStatements(Integer.parseInt(ra.getContent().toString()));
                 }
 
                 ra = ref.get("accessToUnderlyingConnectionAllowed");
                 if (ra != null && ra.getContent() != null) {
-                    setAccessToUnderlyingConnectionAllowed(
-                            Boolean.valueOf(ra.getContent().toString()).booleanValue());
+                    setAccessToUnderlyingConnectionAllowed(Boolean.valueOf(ra.getContent().toString()).booleanValue());
                 }
 
                 cpds = this;
@@ -350,8 +320,7 @@
     }
 
     /**
-     * Throws an IllegalStateException, if a PooledConnection has already
-     * been requested.
+     * Throws an IllegalStateException, if a PooledConnection has already been requested.
      */
     private void assertInitializationAllowed() throws IllegalStateException {
         if (getConnectionCalled) {
@@ -372,35 +341,40 @@
     }
 
     /**
-     * <p>Sets the connection properties passed to the JDBC driver.</p>
+     * <p>
+     * Sets the connection properties passed to the JDBC driver.
+     * </p>
      *
-     * <p>If <code>props</code> contains "user" and/or "password"
-     * properties, the corresponding instance properties are set. If these
-     * properties are not present, they are filled in using
-     * {@link #getUser()}, {@link #getPassword()} when {@link #getPooledConnection()}
-     * is called, or using the actual parameters to the method call when
-     * {@link #getPooledConnection(String, String)} is called. Calls to
-     * {@link #setUser(String)} or {@link #setPassword(String)} overwrite the values
-     * of these properties if <code>connectionProperties</code> is not null.</p>
+     * <p>
+     * If <code>props</code> contains "user" and/or "password" properties, the corresponding instance properties are
+     * set. If these properties are not present, they are filled in using {@link #getUser()}, {@link #getPassword()}
+     * when {@link #getPooledConnection()} is called, or using the actual parameters to the method call when
+     * {@link #getPooledConnection(String, String)} is called. Calls to {@link #setUser(String)} or
+     * {@link #setPassword(String)} overwrite the values of these properties if <code>connectionProperties</code> is not
+     * null.
+     * </p>
      *
-     * @param props Connection properties to use when creating new connections.
-     * @throws IllegalStateException if {@link #getPooledConnection()} has been called
+     * @param props
+     *            Connection properties to use when creating new connections.
+     * @throws IllegalStateException
+     *             if {@link #getPooledConnection()} has been called
      */
     public void setConnectionProperties(final Properties props) {
         assertInitializationAllowed();
         connectionProperties = props;
-        if (connectionProperties.containsKey("user")) {
-            setUser(connectionProperties.getProperty("user"));
-        }
-        if (connectionProperties.containsKey("password")) {
-            setPassword(connectionProperties.getProperty("password"));
+        if (connectionProperties != null) {
+            if (connectionProperties.containsKey(KEY_USER)) {
+                setUser(connectionProperties.getProperty(KEY_USER));
+            }
+            if (connectionProperties.containsKey(KEY_PASSWORD)) {
+                setPassword(connectionProperties.getProperty(KEY_PASSWORD));
+            }
         }
     }
 
     /**
-     * Gets the value of description.  This property is here for use by
-     * the code which will deploy this datasource.  It is not used
-     * internally.
+     * Gets the value of description. This property is here for use by the code which will deploy this datasource. It is
+     * not used internally.
      *
      * @return value of description, may be null.
      * @see #setDescription(String)
@@ -410,39 +384,66 @@
     }
 
     /**
-     * Sets the value of description.  This property is here for use by
-     * the code which will deploy this datasource.  It is not used
-     * internally.
+     * Sets the value of description. This property is here for use by the code which will deploy this datasource. It is
+     * not used internally.
      *
-     * @param v  Value to assign to description.
+     * @param v
+     *            Value to assign to description.
      */
-    public void setDescription(final String  v) {
+    public void setDescription(final String v) {
         this.description = v;
     }
 
     /**
      * Gets the value of password for the default user.
+     *
+     * @return value of password.
+     * @since 2.4.0
+     */
+    public char[] getPasswordCharArray() {
+        return userPassword;
+    }
+
+    /**
+     * Gets the value of password for the default user.
+     *
      * @return value of password.
      */
     public String getPassword() {
-        return password;
+        return Utils.toString(userPassword);
     }
 
     /**
      * Sets the value of password for the default user.
-     * @param v  Value to assign to password.
-     * @throws IllegalStateException if {@link #getPooledConnection()} has been called
+     *
+     * @param userPassword
+     *            Value to assign to password.
+     * @throws IllegalStateException
+     *             if {@link #getPooledConnection()} has been called
      */
-    public void setPassword(final String v) {
+    public void setPassword(final char[] userPassword) {
         assertInitializationAllowed();
-        this.password = v;
-        if (connectionProperties != null) {
-            connectionProperties.setProperty("password", v);
-        }
+        this.userPassword = userPassword;
+        update(connectionProperties, KEY_PASSWORD, Utils.toString(userPassword));
+    }
+
+    /**
+     * Sets the value of password for the default user.
+     *
+     * @param userPassword
+     *            Value to assign to password.
+     * @throws IllegalStateException
+     *             if {@link #getPooledConnection()} has been called
+     */
+    public void setPassword(final String userPassword) {
+        assertInitializationAllowed();
+        this.userPassword = Utils.toCharArray(userPassword);
+        update(connectionProperties, KEY_PASSWORD, userPassword);
     }
 
     /**
      * Gets the value of url used to locate the database for this datasource.
+     *
      * @return value of url.
      */
     public String getUrl() {
@@ -451,37 +452,43 @@
 
     /**
      * Sets the value of URL string used to locate the database for this datasource.
-     * @param v  Value to assign to url.
-     * @throws IllegalStateException if {@link #getPooledConnection()} has been called
-    */
+     *
+     * @param v
+     *            Value to assign to url.
+     * @throws IllegalStateException
+     *             if {@link #getPooledConnection()} has been called
+     */
     public void setUrl(final String v) {
         assertInitializationAllowed();
         this.url = v;
     }
 
     /**
-     * Gets the value of default user (login or username).
+     * Gets the value of default user (login or user name).
+     *
      * @return value of user.
      */
     public String getUser() {
-        return user;
+        return userName;
     }
 
     /**
-     * Sets the value of default user (login or username).
-     * @param v  Value to assign to user.
-     * @throws IllegalStateException if {@link #getPooledConnection()} has been called
+     * Sets the value of default user (login or user name).
+     *
+     * @param v
+     *            Value to assign to user.
+     * @throws IllegalStateException
+     *             if {@link #getPooledConnection()} has been called
      */
     public void setUser(final String v) {
         assertInitializationAllowed();
-        this.user = v;
-        if (connectionProperties != null) {
-            connectionProperties.setProperty("user", v);
-        }
+        this.userName = v;
+        update(connectionProperties, KEY_USER, v);
     }
 
     /**
-     * Gets the driver classname.
+     * Gets the driver class name.
+     *
      * @return value of driver.
      */
     public String getDriver() {
@@ -489,10 +496,15 @@
     }
 
     /**
-     * Sets the driver classname.  Setting the driver classname cause the
-     * driver to be registered with the DriverManager.
-     * @param v  Value to assign to driver.
-     * @throws IllegalStateException if {@link #getPooledConnection()} has been called
+     * Sets the driver class name. Setting the driver class name cause the driver to be registered with the
+     * DriverManager.
+     *
+     * @param v
+     *            Value to assign to driver.
+     * @throws IllegalStateException
+     *             if {@link #getPooledConnection()} has been called
+     * @throws ClassNotFoundException
+     *             if the class cannot be located
      */
     public void setDriver(final String v) throws ClassNotFoundException {
         assertInitializationAllowed();
@@ -502,8 +514,8 @@
     }
 
     /**
-     * Gets the maximum time in seconds that this data source can wait
-     * while attempting to connect to a database. NOT USED.
+     * Gets the maximum time in seconds that this data source can wait while attempting to connect to a database. NOT
+     * USED.
      */
     @Override
     public int getLoginTimeout() {
@@ -519,8 +531,8 @@
     }
 
     /**
-     * Sets the maximum time in seconds that this data source will wait
-     * while attempting to connect to a database. NOT USED.
+     * Sets the maximum time in seconds that this data source will wait while attempting to connect to a database. NOT
+     * USED.
      */
     @Override
     public void setLoginTimeout(final int seconds) {
@@ -535,13 +547,12 @@
         logWriter = out;
     }
 
-
     // ------------------------------------------------------------------
     // PreparedStatement pool properties
 
-
     /**
      * Flag to toggle the pooling of <code>PreparedStatement</code>s
+     *
      * @return value of poolPreparedStatements.
      */
     public boolean isPoolPreparedStatements() {
@@ -550,17 +561,21 @@
 
     /**
      * Flag to toggle the pooling of <code>PreparedStatement</code>s
-     * @param v  true to pool statements.
-     * @throws IllegalStateException if {@link #getPooledConnection()} has been called
+     *
+     * @param poolPreparedStatements
+     *            true to pool statements.
+     * @throws IllegalStateException
+     *             if {@link #getPooledConnection()} has been called
      */
-    public void setPoolPreparedStatements(final boolean v) {
+    public void setPoolPreparedStatements(final boolean poolPreparedStatements) {
         assertInitializationAllowed();
-        this.poolPreparedStatements = v;
+        this.poolPreparedStatements = poolPreparedStatements;
     }
 
     /**
-     * Gets the maximum number of statements that can remain idle in the
-     * pool, without extra ones being released, or negative for no limit.
+     * Gets the maximum number of statements that can remain idle in the pool, without extra ones being released, or
+     * negative for no limit.
+     *
      * @return the value of maxIdle
      */
     public int getMaxIdle() {
@@ -568,11 +583,13 @@
     }
 
     /**
-     * Gets the maximum number of statements that can remain idle in the
-     * pool, without extra ones being released, or negative for no limit.
+     * Gets the maximum number of statements that can remain idle in the pool, without extra ones being released, or
+     * negative for no limit.
      *
-     * @param maxIdle The maximum number of statements that can remain idle
-     * @throws IllegalStateException if {@link #getPooledConnection()} has been called
+     * @param maxIdle
+     *            The maximum number of statements that can remain idle
+     * @throws IllegalStateException
+     *             if {@link #getPooledConnection()} has been called
      */
     public void setMaxIdle(final int maxIdle) {
         assertInitializationAllowed();
@@ -580,87 +597,89 @@
     }
 
     /**
-     * Gets the number of milliseconds to sleep between runs of the
-     * idle object evictor thread.
-     * When non-positive, no idle object evictor thread will be
-     * run.
+     * Gets the number of milliseconds to sleep between runs of the idle object evictor thread. When non-positive, no
+     * idle object evictor thread will be run.
+     *
      * @return the value of the evictor thread timer
      * @see #setTimeBetweenEvictionRunsMillis(long)
      */
     public long getTimeBetweenEvictionRunsMillis() {
-        return _timeBetweenEvictionRunsMillis;
+        return timeBetweenEvictionRunsMillis;
     }
 
     /**
-     * Sets the number of milliseconds to sleep between runs of the
-     * idle object evictor thread.
-     * When non-positive, no idle object evictor thread will be
-     * run.
-     * @param timeBetweenEvictionRunsMillis
-     * @see #getTimeBetweenEvictionRunsMillis()
-     * @throws IllegalStateException if {@link #getPooledConnection()} has been called
-     */
-    public void setTimeBetweenEvictionRunsMillis(
-            final long timeBetweenEvictionRunsMillis) {
-        assertInitializationAllowed();
-        _timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
-    }
-
-    /**
-     * Gets the number of statements to examine during each run of the
-     * idle object evictor thread (if any).
+     * Sets the number of milliseconds to sleep between runs of the idle object evictor thread. When non-positive, no
+     * idle object evictor thread will be run.
      *
-     * *see #setNumTestsPerEvictionRun
-     * *see #setTimeBetweenEvictionRunsMillis
+     * @param timeBetweenEvictionRunsMillis
+     *            The number of milliseconds to sleep between runs of the idle object evictor thread. When non-positive,
+     *            no idle object evictor thread will be run.
+     * @see #getTimeBetweenEvictionRunsMillis()
+     * @throws IllegalStateException
+     *             if {@link #getPooledConnection()} has been called
+     */
+    public void setTimeBetweenEvictionRunsMillis(final long timeBetweenEvictionRunsMillis) {
+        assertInitializationAllowed();
+        this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
+    }
+
+    /**
+     * Gets the number of statements to examine during each run of the idle object evictor thread (if any.)
+     *
+     * @see #setNumTestsPerEvictionRun
+     * @see #setTimeBetweenEvictionRunsMillis
+     * @return the number of statements to examine during each run of the idle object evictor thread (if any.)
      */
     public int getNumTestsPerEvictionRun() {
-        return _numTestsPerEvictionRun;
+        return numTestsPerEvictionRun;
     }
 
     /**
-     * Sets the number of statements to examine during each run of the
-     * idle object evictor thread (if any).
+     * Sets the number of statements to examine during each run of the idle object evictor thread (if any).
      * <p>
-     * When a negative value is supplied, <tt>ceil({*link #numIdle})/abs({*link #getNumTestsPerEvictionRun})</tt>
-     * tests will be run.  I.e., when the value is <i>-n</i>, roughly one <i>n</i>th of the
-     * idle objects will be tested per run.
+     * When a negative value is supplied, <tt>ceil({*link #numIdle})/abs({*link #getNumTestsPerEvictionRun})</tt> tests
+     * will be run. I.e., when the value is <i>-n</i>, roughly one <i>n</i>th of the idle objects will be tested per
+     * run.
+     * </p>
      *
-     * @param numTestsPerEvictionRun number of statements to examine per run
+     * @param numTestsPerEvictionRun
+     *            number of statements to examine per run
      * @see #getNumTestsPerEvictionRun()
      * @see #setTimeBetweenEvictionRunsMillis(long)
-     * @throws IllegalStateException if {@link #getPooledConnection()} has been called
+     * @throws IllegalStateException
+     *             if {@link #getPooledConnection()} has been called
      */
     public void setNumTestsPerEvictionRun(final int numTestsPerEvictionRun) {
         assertInitializationAllowed();
-        _numTestsPerEvictionRun = numTestsPerEvictionRun;
+        this.numTestsPerEvictionRun = numTestsPerEvictionRun;
     }
 
     /**
-     * Gets the minimum amount of time a statement may sit idle in the pool
-     * before it is eligible for eviction by the idle object evictor
-     * (if any).
+     * Gets the minimum amount of time a statement may sit idle in the pool before it is eligible for eviction by the
+     * idle object evictor (if any).
      *
-     * *see #setMinEvictableIdleTimeMillis
-     * *see #setTimeBetweenEvictionRunsMillis
+     * @see #setMinEvictableIdleTimeMillis
+     * @see #setTimeBetweenEvictionRunsMillis
+     * @return the minimum amount of time a statement may sit idle in the pool.
      */
     public int getMinEvictableIdleTimeMillis() {
-        return _minEvictableIdleTimeMillis;
+        return minEvictableIdleTimeMillis;
     }
 
     /**
-     * Sets the minimum amount of time a statement may sit idle in the pool
-     * before it is eligible for eviction by the idle object evictor
-     * (if any).
-     * When non-positive, no objects will be evicted from the pool
-     * due to idle time alone.
-     * @param minEvictableIdleTimeMillis minimum time to set (in ms)
+     * Sets the minimum amount of time a statement may sit idle in the pool before it is eligible for eviction by the
+     * idle object evictor (if any). When non-positive, no objects will be evicted from the pool due to idle time alone.
+     *
+     * @param minEvictableIdleTimeMillis
+     *            minimum time to set (in ms)
      * @see #getMinEvictableIdleTimeMillis()
      * @see #setTimeBetweenEvictionRunsMillis(long)
-     * @throws IllegalStateException if {@link #getPooledConnection()} has been called
+     * @throws IllegalStateException
+     *             if {@link #getPooledConnection()} has been called
      */
     public void setMinEvictableIdleTimeMillis(final int minEvictableIdleTimeMillis) {
         assertInitializationAllowed();
-        _minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
+        this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
     }
 
     /**
@@ -673,11 +692,11 @@
     }
 
     /**
-     * Sets the value of the accessToUnderlyingConnectionAllowed property.
-     * It controls if the PoolGuard allows access to the underlying connection.
-     * (Default: false)
+     * Sets the value of the accessToUnderlyingConnectionAllowed property. It controls if the PoolGuard allows access to
+     * the underlying connection. (Default: false)
      *
-     * @param allow Access to the underlying connection is granted when true.
+     * @param allow
+     *            Access to the underlying connection is granted when true.
      */
     public synchronized void setAccessToUnderlyingConnectionAllowed(final boolean allow) {
         this.accessToUnderlyingConnectionAllowed = allow;
@@ -688,18 +707,27 @@
      *
      * @return maxPrepartedStatements value
      */
-    public int getMaxPreparedStatements()
-    {
-        return _maxPreparedStatements;
+    public int getMaxPreparedStatements() {
+        return maxPreparedStatements;
     }
 
     /**
      * Sets the maximum number of prepared statements.
-     * @param maxPreparedStatements the new maximum number of prepared
-     * statements
+     *
+     * @param maxPreparedStatements
+     *            the new maximum number of prepared statements
      */
-    public void setMaxPreparedStatements(final int maxPreparedStatements)
-    {
-        _maxPreparedStatements = maxPreparedStatements;
+    public void setMaxPreparedStatements(final int maxPreparedStatements) {
+        this.maxPreparedStatements = maxPreparedStatements;
+    }
+
+    private void update(final Properties properties, final String key, final String value) {
+        if (properties != null) {
+            if (value == null) {
+                properties.remove(key);
+            } else {
+                properties.setProperty(key, value);
+            }
+        }
     }
 }
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PStmtKeyCPDS.java b/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PStmtKeyCPDS.java
index 7d7144a..2fe63f9 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PStmtKeyCPDS.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PStmtKeyCPDS.java
@@ -16,122 +16,38 @@
  */
 package org.apache.tomcat.dbcp.dbcp2.cpdsadapter;
 
-import java.util.Arrays;
-
 import org.apache.tomcat.dbcp.dbcp2.PStmtKey;
 
 /**
  * A key uniquely identifying a {@link java.sql.PreparedStatement PreparedStatement}.
+ *
  * @since 2.0
+ * @deprecated Use {@link PStmtKey}.
  */
+@Deprecated
 public class PStmtKeyCPDS extends PStmtKey {
-    private final Integer _resultSetHoldability;
-    private final int _columnIndexes[];
-    private final String _columnNames[];
-
     public PStmtKeyCPDS(final String sql) {
         super(sql);
-        _resultSetHoldability = null;
-        _columnIndexes = null;
-        _columnNames = null;
     }
 
     public PStmtKeyCPDS(final String sql, final int autoGeneratedKeys) {
         super(sql, null, autoGeneratedKeys);
-        _resultSetHoldability = null;
-        _columnIndexes = null;
-        _columnNames = null;
     }
 
     public PStmtKeyCPDS(final String sql, final int resultSetType, final int resultSetConcurrency) {
         super(sql, resultSetType, resultSetConcurrency);
-        _resultSetHoldability = null;
-        _columnIndexes = null;
-        _columnNames = null;
     }
 
     public PStmtKeyCPDS(final String sql, final int resultSetType, final int resultSetConcurrency,
             final int resultSetHoldability) {
         super(sql, resultSetType, resultSetConcurrency);
-        _resultSetHoldability = Integer.valueOf(resultSetHoldability);
-        _columnIndexes = null;
-        _columnNames = null;
     }
 
     public PStmtKeyCPDS(final String sql, final int columnIndexes[]) {
-        super(sql);
-        _columnIndexes = Arrays.copyOf(columnIndexes, columnIndexes.length);
-        _resultSetHoldability = null;
-        _columnNames = null;
+        super(sql, null, columnIndexes);
     }
 
     public PStmtKeyCPDS(final String sql, final String columnNames[]) {
-        super(sql);
-        _columnNames = Arrays.copyOf(columnNames, columnNames.length);
-        _resultSetHoldability = null;
-        _columnIndexes = null;
-    }
-
-
-    @Override
-    public boolean equals(final Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (!super.equals(obj)) {
-            return false;
-        }
-        if (getClass() != obj.getClass()) {
-            return false;
-        }
-        final PStmtKeyCPDS other = (PStmtKeyCPDS) obj;
-        if (!Arrays.equals(_columnIndexes, other._columnIndexes)) {
-            return false;
-        }
-        if (!Arrays.equals(_columnNames, other._columnNames)) {
-            return false;
-        }
-        if (_resultSetHoldability == null) {
-            if (other._resultSetHoldability != null) {
-                return false;
-            }
-        } else if (!_resultSetHoldability.equals(other._resultSetHoldability)) {
-            return false;
-        }
-        return true;
-    }
-
-
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = super.hashCode();
-        result = prime * result + Arrays.hashCode(_columnIndexes);
-        result = prime * result + Arrays.hashCode(_columnNames);
-        result = prime * result + (_resultSetHoldability == null ? 0 : _resultSetHoldability.hashCode());
-        return result;
-    }
-
-
-    @Override
-    public String toString() {
-        final StringBuffer buf = new StringBuffer();
-        buf.append("PStmtKey: sql=");
-        buf.append(getSql());
-        buf.append(", catalog=");
-        buf.append(getCatalog());
-        buf.append(", resultSetType=");
-        buf.append(getResultSetType());
-        buf.append(", resultSetConcurrency=");
-        buf.append(getResultSetConcurrency());
-        buf.append(", statementType=");
-        buf.append(getStmtType());
-        buf.append(", resultSetHoldability=");
-        buf.append(_resultSetHoldability);
-        buf.append(", columnIndexes=");
-        buf.append(Arrays.toString(_columnIndexes));
-        buf.append(", columnNames=");
-        buf.append(Arrays.toString(_columnNames));
-        return buf.toString();
+        super(sql, null, columnNames);
     }
 }
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PooledConnectionImpl.java b/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PooledConnectionImpl.java
index ba48a9a..18c11e3 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PooledConnectionImpl.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PooledConnectionImpl.java
@@ -17,6 +17,7 @@
 
 package org.apache.tomcat.dbcp.dbcp2.cpdsadapter;
 
+import java.sql.CallableStatement;
 import java.sql.Connection;
 import java.sql.PreparedStatement;
 import java.sql.SQLException;
@@ -28,67 +29,69 @@
 import javax.sql.StatementEventListener;
 
 import org.apache.tomcat.dbcp.dbcp2.DelegatingConnection;
+import org.apache.tomcat.dbcp.dbcp2.DelegatingPreparedStatement;
+import org.apache.tomcat.dbcp.dbcp2.PStmtKey;
+import org.apache.tomcat.dbcp.dbcp2.PoolableCallableStatement;
 import org.apache.tomcat.dbcp.dbcp2.PoolablePreparedStatement;
+import org.apache.tomcat.dbcp.dbcp2.PoolingConnection.StatementType;
 import org.apache.tomcat.dbcp.pool2.KeyedObjectPool;
 import org.apache.tomcat.dbcp.pool2.KeyedPooledObjectFactory;
 import org.apache.tomcat.dbcp.pool2.PooledObject;
 import org.apache.tomcat.dbcp.pool2.impl.DefaultPooledObject;
 
 /**
- * Implementation of PooledConnection that is returned by
- * PooledConnectionDataSource.
+ * Implementation of PooledConnection that is returned by PooledConnectionDataSource.
  *
- * @author John D. McNally
  * @since 2.0
  */
 class PooledConnectionImpl
-        implements PooledConnection, KeyedPooledObjectFactory<PStmtKeyCPDS, PoolablePreparedStatement<PStmtKeyCPDS>> {
+        implements PooledConnection, KeyedPooledObjectFactory<PStmtKey, DelegatingPreparedStatement> {
 
-    private static final String CLOSED
-            = "Attempted to use PooledConnection after closed() was called.";
+    private static final String CLOSED = "Attempted to use PooledConnection after closed() was called.";
 
     /**
      * The JDBC database connection that represents the physical db connection.
      */
-    private Connection connection = null;
+    private Connection connection;
 
     /**
-     * A DelegatingConnection used to create a PoolablePreparedStatementStub
+     * A DelegatingConnection used to create a PoolablePreparedStatementStub.
      */
     private final DelegatingConnection<?> delegatingConnection;
 
     /**
      * The JDBC database logical connection.
      */
-    private Connection logicalConnection = null;
+    private Connection logicalConnection;
 
     /**
-     * ConnectionEventListeners
+     * ConnectionEventListeners.
      */
     private final Vector<ConnectionEventListener> eventListeners;
 
     /**
-     * StatementEventListeners
+     * StatementEventListeners.
      */
-    private final Vector<StatementEventListener> statementEventListeners =
-            new Vector<>();
+    private final Vector<StatementEventListener> statementEventListeners = new Vector<>();
 
     /**
-     * flag set to true, once close() is called.
+     * Flag set to true, once {@link #close()} is called.
      */
-    private boolean isClosed;
+    private boolean closed;
 
     /** My pool of {@link PreparedStatement}s. */
-    private KeyedObjectPool<PStmtKeyCPDS, PoolablePreparedStatement<PStmtKeyCPDS>> pstmtPool = null;
+    private KeyedObjectPool<PStmtKey, DelegatingPreparedStatement> pStmtPool;
 
     /**
-     * Controls access to the underlying connection
+     * Controls access to the underlying connection.
      */
-    private boolean accessToUnderlyingConnectionAllowed = false;
+    private boolean accessToUnderlyingConnectionAllowed;
 
     /**
-     * Wrap the real connection.
-     * @param connection the connection to be wrapped
+     * Wraps the real connection.
+     *
+     * @param connection
+     *            the connection to be wrapped.
      */
     PooledConnectionImpl(final Connection connection) {
         this.connection = connection;
@@ -98,12 +101,21 @@
             this.delegatingConnection = new DelegatingConnection<>(connection);
         }
         eventListeners = new Vector<>();
-        isClosed = false;
+        closed = false;
     }
 
-    public void setStatementPool(
-            final KeyedObjectPool<PStmtKeyCPDS, PoolablePreparedStatement<PStmtKeyCPDS>> statementPool) {
-        pstmtPool = statementPool;
+    /**
+     * My {@link KeyedPooledObjectFactory} method for activating {@link PreparedStatement}s.
+     *
+     * @param key
+     *            Ignored.
+     * @param pooledObject
+     *            Ignored.
+     */
+    @Override
+    public void activateObject(final PStmtKey key, final PooledObject<DelegatingPreparedStatement> pooledObject)
+            throws Exception {
+        pooledObject.getObject().activate();
     }
 
     /**
@@ -126,22 +138,31 @@
     /* JDBC_4_ANT_KEY_END */
 
     /**
-     * Closes the physical connection and marks this
-     * <code>PooledConnection</code> so that it may not be used
-     * to generate any more logical <code>Connection</code>s.
+     * Throws an SQLException, if isClosed is true
+     */
+    private void assertOpen() throws SQLException {
+        if (closed) {
+            throw new SQLException(CLOSED);
+        }
+    }
+
+    /**
+     * Closes the physical connection and marks this <code>PooledConnection</code> so that it may not be used to
+     * generate any more logical <code>Connection</code>s.
      *
-     * @throws SQLException if an error occurs or the connection is already closed
+     * @throws SQLException
+     *             Thrown when an error occurs or the connection is already closed.
      */
     @Override
     public void close() throws SQLException {
         assertOpen();
-        isClosed = true;
+        closed = true;
         try {
-            if (pstmtPool != null) {
+            if (pStmtPool != null) {
                 try {
-                    pstmtPool.close();
+                    pStmtPool.close();
                 } finally {
-                    pstmtPool = null;
+                    pStmtPool = null;
                 }
             }
         } catch (final RuntimeException e) {
@@ -158,56 +179,93 @@
     }
 
     /**
-     * Throws an SQLException, if isClosed is true
+     * Creates a {@link PooledConnectionImpl.PStmtKey} for the given arguments.
      */
-    private void assertOpen() throws SQLException {
-        if (isClosed) {
-            throw new SQLException(CLOSED);
-        }
+    protected PStmtKey createKey(final String sql) {
+        return new PStmtKey(normalizeSQL(sql), getCatalogOrNull());
     }
 
     /**
-     * Returns a JDBC connection.
+     * Creates a {@link PooledConnectionImpl.PStmtKey} for the given arguments.
+     */
+    protected PStmtKey createKey(final String sql, final int autoGeneratedKeys) {
+        return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), autoGeneratedKeys);
+    }
+
+    /**
+     * Creates a {@link PooledConnectionImpl.PStmtKey} for the given arguments.
+     */
+    protected PStmtKey createKey(final String sql, final int columnIndexes[]) {
+        return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), columnIndexes);
+    }
+
+    /**
+     * Creates a {@link PooledConnectionImpl.PStmtKey} for the given arguments.
+     */
+    protected PStmtKey createKey(final String sql, final int resultSetType, final int resultSetConcurrency) {
+        return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), resultSetType, resultSetConcurrency);
+    }
+
+    /**
+     * Creates a {@link PooledConnectionImpl.PStmtKey} for the given arguments.
+     */
+    protected PStmtKey createKey(final String sql, final int resultSetType, final int resultSetConcurrency,
+            final int resultSetHoldability) {
+        return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), resultSetType, resultSetConcurrency,
+                resultSetHoldability);
+    }
+
+    /**
+     * Creates a {@link PooledConnectionImpl.PStmtKey} for the given arguments.
      *
-     * @return The database connection.
-     * @throws SQLException if the connection is not open or the previous logical connection is still open
+     * @since 2.4.0
      */
-    @Override
-    public Connection getConnection() throws SQLException {
-        assertOpen();
-        // make sure the last connection is marked as closed
-        if (logicalConnection != null && !logicalConnection.isClosed()) {
-            // should notify pool of error so the pooled connection can
-            // be removed !FIXME!
-            throw new SQLException("PooledConnection was reused, without "
-                    + "its previous Connection being closed.");
-        }
-
-        // the spec requires that this return a new Connection instance.
-        logicalConnection = new ConnectionImpl(
-                this, connection, isAccessToUnderlyingConnectionAllowed());
-        return logicalConnection;
+    protected PStmtKey createKey(final String sql, final int resultSetType, final int resultSetConcurrency,
+            final int resultSetHoldability, final StatementType statementType) {
+        return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), resultSetType, resultSetConcurrency,
+                resultSetHoldability, statementType);
     }
 
     /**
-     * {@inheritDoc}
+     * Creates a {@link PooledConnectionImpl.PStmtKey} for the given arguments.
+     *
+     * @since 2.4.0
      */
-    @Override
-    public void removeConnectionEventListener(
-            final ConnectionEventListener listener) {
-        eventListeners.remove(listener);
+    protected PStmtKey createKey(final String sql, final int resultSetType, final int resultSetConcurrency,
+            final StatementType statementType) {
+        return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), resultSetType, resultSetConcurrency, statementType);
     }
 
-    /* JDBC_4_ANT_KEY_BEGIN */
-    @Override
-    public void removeStatementEventListener(final StatementEventListener listener) {
-        statementEventListeners.remove(listener);
-    }
-    /* JDBC_4_ANT_KEY_END */
-
     /**
-     * Closes the physical connection and checks that the logical connection
-     * was closed as well.
+     * Creates a {@link PooledConnectionImpl.PStmtKey} for the given arguments.
+     */
+    protected PStmtKey createKey(final String sql, final StatementType statementType) {
+        return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), statementType);
+    }
+
+    /**
+     * Creates a {@link PooledConnectionImpl.PStmtKey} for the given arguments.
+     */
+    protected PStmtKey createKey(final String sql, final String columnNames[]) {
+        return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), columnNames);
+    }
+
+    /**
+     * My {@link KeyedPooledObjectFactory} method for destroying {@link PreparedStatement}s.
+     *
+     * @param key
+     *            ignored
+     * @param pooledObject
+     *            the wrapped {@link PreparedStatement} to be destroyed.
+     */
+    @Override
+    public void destroyObject(final PStmtKey key, final PooledObject<DelegatingPreparedStatement> pooledObject)
+            throws Exception {
+        pooledObject.getObject().getInnermostDelegate().close();
+    }
+
+    /**
+     * Closes the physical connection and checks that the logical connection was closed as well.
      */
     @Override
     protected void finalize() throws Throwable {
@@ -216,285 +274,43 @@
         try {
             connection.close();
         } catch (final Exception ignored) {
+            // ignore
         }
 
         // make sure the last connection is marked as closed
         if (logicalConnection != null && !logicalConnection.isClosed()) {
-            throw new SQLException("PooledConnection was gc'ed, without"
-                    + "its last Connection being closed.");
+            throw new SQLException("PooledConnection was gc'ed, without its last Connection being closed.");
         }
     }
 
-    /**
-     * sends a connectionClosed event.
-     */
-    void notifyListeners() {
-        final ConnectionEvent event = new ConnectionEvent(this);
-        final Object[] listeners = eventListeners.toArray();
-        for (final Object listener : listeners) {
-            ((ConnectionEventListener) listener).connectionClosed(event);
-        }
-    }
-
-    // -------------------------------------------------------------------
-    // The following code implements a PreparedStatement pool
-
-    /**
-     * Create or obtain a {@link PreparedStatement} from my pool.
-     * @param sql the SQL statement
-     * @return a {@link PoolablePreparedStatement}
-     */
-    PreparedStatement prepareStatement(final String sql) throws SQLException {
-        if (pstmtPool == null) {
-            return connection.prepareStatement(sql);
-        }
+    private String getCatalogOrNull() {
         try {
-            return pstmtPool.borrowObject(createKey(sql));
-        } catch (final RuntimeException e) {
-            throw e;
-        } catch (final Exception e) {
-            throw new SQLException("Borrow prepareStatement from pool failed", e);
+            return connection == null ? null : connection.getCatalog();
+        } catch (final SQLException e) {
+            return null;
         }
     }
 
     /**
-     * Create or obtain a {@link PreparedStatement} from my pool.
-     * @param sql a <code>String</code> object that is the SQL statement to
-     *            be sent to the database; may contain one or more '?' IN
-     *            parameters
-     * @param resultSetType a result set type; one of
-     *         <code>ResultSet.TYPE_FORWARD_ONLY</code>,
-     *         <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
-     *         <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
-     * @param resultSetConcurrency a concurrency type; one of
-     *         <code>ResultSet.CONCUR_READ_ONLY</code> or
-     *         <code>ResultSet.CONCUR_UPDATABLE</code>
+     * Returns a JDBC connection.
      *
-     * @return a {@link PoolablePreparedStatement}
-     * @see Connection#prepareStatement(String, int, int)
-     */
-    PreparedStatement prepareStatement(final String sql, final int resultSetType,
-                                       final int resultSetConcurrency)
-            throws SQLException {
-        if (pstmtPool == null) {
-            return connection.prepareStatement(sql, resultSetType, resultSetConcurrency);
-        }
-        try {
-            return pstmtPool.borrowObject(
-                    createKey(sql,resultSetType,resultSetConcurrency));
-        } catch (final RuntimeException e) {
-            throw e;
-        } catch (final Exception e) {
-            throw new SQLException("Borrow prepareStatement from pool failed", e);
-        }
-    }
-
-    /**
-     * Create or obtain a {@link PreparedStatement} from my pool.
-     * @param sql an SQL statement that may contain one or more '?' IN
-     *        parameter placeholders
-     * @param autoGeneratedKeys a flag indicating whether auto-generated keys
-     *        should be returned; one of
-     *        <code>Statement.RETURN_GENERATED_KEYS</code> or
-     *        <code>Statement.NO_GENERATED_KEYS</code>
-     * @return a {@link PoolablePreparedStatement}
-     * @see Connection#prepareStatement(String, int)
-     */
-    PreparedStatement prepareStatement(final String sql, final int autoGeneratedKeys)
-            throws SQLException {
-        if (pstmtPool == null) {
-            return connection.prepareStatement(sql, autoGeneratedKeys);
-        }
-        try {
-            return pstmtPool.borrowObject(createKey(sql,autoGeneratedKeys));
-        } catch (final RuntimeException e) {
-            throw e;
-        } catch (final Exception e) {
-            throw new SQLException("Borrow prepareStatement from pool failed", e);
-        }
-    }
-
-    PreparedStatement prepareStatement(final String sql, final int resultSetType,
-            final int resultSetConcurrency, final int resultSetHoldability)
-    throws SQLException {
-        if (pstmtPool == null) {
-            return connection.prepareStatement(sql, resultSetType,
-                    resultSetConcurrency, resultSetHoldability);
-        }
-        try {
-            return pstmtPool.borrowObject(createKey(sql, resultSetType,
-                    resultSetConcurrency, resultSetHoldability));
-        } catch (final RuntimeException e) {
-            throw e;
-        } catch (final Exception e) {
-            throw new SQLException("Borrow prepareStatement from pool failed", e);
-        }
-    }
-
-    PreparedStatement prepareStatement(final String sql, final int columnIndexes[])
-    throws SQLException {
-        if (pstmtPool == null) {
-            return connection.prepareStatement(sql, columnIndexes);
-        }
-        try {
-            return pstmtPool.borrowObject(createKey(sql, columnIndexes));
-        } catch (final RuntimeException e) {
-            throw e;
-        } catch (final Exception e) {
-            throw new SQLException("Borrow prepareStatement from pool failed", e);
-        }
-    }
-
-    PreparedStatement prepareStatement(final String sql, final String columnNames[])
-    throws SQLException {
-        if (pstmtPool == null) {
-            return connection.prepareStatement(sql, columnNames);
-        }
-        try {
-            return pstmtPool.borrowObject(createKey(sql, columnNames));
-        } catch (final RuntimeException e) {
-            throw e;
-        } catch (final Exception e) {
-            throw new SQLException("Borrow prepareStatement from pool failed", e);
-        }
-    }
-
-    /**
-     * Create a {@link PooledConnectionImpl.PStmtKey} for the given arguments.
-     */
-    protected PStmtKeyCPDS createKey(final String sql, final int autoGeneratedKeys) {
-        return new PStmtKeyCPDS(normalizeSQL(sql), autoGeneratedKeys);
-    }
-
-    /**
-     * Create a {@link PooledConnectionImpl.PStmtKey} for the given arguments.
-     */
-    protected PStmtKeyCPDS createKey(final String sql, final int resultSetType,
-            final int resultSetConcurrency, final int resultSetHoldability) {
-        return new PStmtKeyCPDS(normalizeSQL(sql), resultSetType,
-                resultSetConcurrency, resultSetHoldability);
-    }
-
-    /**
-     * Create a {@link PooledConnectionImpl.PStmtKey} for the given arguments.
-     */
-    protected PStmtKeyCPDS createKey(final String sql, final int columnIndexes[]) {
-        return new PStmtKeyCPDS(normalizeSQL(sql), columnIndexes);
-    }
-
-    /**
-     * Create a {@link PooledConnectionImpl.PStmtKey} for the given arguments.
-     */
-    protected PStmtKeyCPDS createKey(final String sql, final String columnNames[]) {
-        return new PStmtKeyCPDS(normalizeSQL(sql), columnNames);
-    }
-
-    /**
-     * Create a {@link PooledConnectionImpl.PStmtKey} for the given arguments.
-     */
-    protected PStmtKeyCPDS createKey(final String sql, final int resultSetType,
-                               final int resultSetConcurrency) {
-        return new PStmtKeyCPDS(normalizeSQL(sql), resultSetType,
-                            resultSetConcurrency);
-    }
-
-    /**
-     * Create a {@link PooledConnectionImpl.PStmtKey} for the given arguments.
-     */
-    protected PStmtKeyCPDS createKey(final String sql) {
-        return new PStmtKeyCPDS(normalizeSQL(sql));
-    }
-
-    /**
-     * Normalize the given SQL statement, producing a
-     * canonical form that is semantically equivalent to the original.
-     */
-    protected String normalizeSQL(final String sql) {
-        return sql.trim();
-    }
-
-    /**
-     * My {@link KeyedPooledObjectFactory} method for creating
-     * {@link PreparedStatement}s.
-     * @param key the key for the {@link PreparedStatement} to be created
+     * @return The database connection.
+     * @throws SQLException
+     *             if the connection is not open or the previous logical connection is still open
      */
     @Override
-    public PooledObject<PoolablePreparedStatement<PStmtKeyCPDS>> makeObject(final PStmtKeyCPDS key) throws Exception {
-        if (null == key) {
-            throw new IllegalArgumentException();
+    public Connection getConnection() throws SQLException {
+        assertOpen();
+        // make sure the last connection is marked as closed
+        if (logicalConnection != null && !logicalConnection.isClosed()) {
+            // should notify pool of error so the pooled connection can
+            // be removed !FIXME!
+            throw new SQLException("PooledConnection was reused, without its previous Connection being closed.");
         }
-        // _openPstmts++;
-        if (null == key.getResultSetType()
-                && null == key.getResultSetConcurrency()) {
-            if (null == key.getAutoGeneratedKeys()) {
-                return new DefaultPooledObject<>(new PoolablePreparedStatement<>(
-                        connection.prepareStatement(key.getSql()),
-                        key, pstmtPool, delegatingConnection));
-            }
-            return new DefaultPooledObject<>(new PoolablePreparedStatement<>(
-                            connection.prepareStatement(key.getSql(),
-                                    key.getAutoGeneratedKeys().intValue()),
-                            key, pstmtPool, delegatingConnection));
-        }
-        return new DefaultPooledObject<>(new PoolablePreparedStatement<>(
-                connection.prepareStatement(key.getSql(),
-                        key.getResultSetType().intValue(),
-                        key.getResultSetConcurrency().intValue()),
-                        key, pstmtPool, delegatingConnection));
-    }
 
-    /**
-     * My {@link KeyedPooledObjectFactory} method for destroying
-     * {@link PreparedStatement}s.
-     * @param key ignored
-     * @param p the wrapped {@link PreparedStatement} to be destroyed.
-     */
-    @Override
-    public void destroyObject(final PStmtKeyCPDS key,
-            final PooledObject<PoolablePreparedStatement<PStmtKeyCPDS>> p)
-            throws Exception {
-        p.getObject().getInnermostDelegate().close();
-    }
-
-    /**
-     * My {@link KeyedPooledObjectFactory} method for validating
-     * {@link PreparedStatement}s.
-     * @param key ignored
-     * @param p ignored
-     * @return {@code true}
-     */
-    @Override
-    public boolean validateObject(final PStmtKeyCPDS key,
-            final PooledObject<PoolablePreparedStatement<PStmtKeyCPDS>> p) {
-        return true;
-    }
-
-    /**
-     * My {@link KeyedPooledObjectFactory} method for activating
-     * {@link PreparedStatement}s.
-     * @param key ignored
-     * @param p ignored
-     */
-    @Override
-    public void activateObject(final PStmtKeyCPDS key,
-            final PooledObject<PoolablePreparedStatement<PStmtKeyCPDS>> p)
-            throws Exception {
-        p.getObject().activate();
-    }
-
-    /**
-     * My {@link KeyedPooledObjectFactory} method for passivating
-     * {@link PreparedStatement}s.  Currently invokes {@link PreparedStatement#clearParameters}.
-     * @param key ignored
-     * @param p a wrapped {@link PreparedStatement}
-     */
-    @Override
-    public void passivateObject(final PStmtKeyCPDS key,
-            final PooledObject<PoolablePreparedStatement<PStmtKeyCPDS>> p)
-            throws Exception {
-        final PoolablePreparedStatement<PStmtKeyCPDS> ppss = p.getObject();
-        ppss.clearParameters();
-        ppss.passivate();
+        // the spec requires that this return a new Connection instance.
+        logicalConnection = new ConnectionImpl(this, connection, isAccessToUnderlyingConnectionAllowed());
+        return logicalConnection;
     }
 
     /**
@@ -507,13 +323,317 @@
     }
 
     /**
-     * Sets the value of the accessToUnderlyingConnectionAllowed property.
-     * It controls if the PoolGuard allows access to the underlying connection.
-     * (Default: false)
+     * My {@link KeyedPooledObjectFactory} method for creating {@link PreparedStatement}s.
      *
-     * @param allow Access to the underlying connection is granted when true.
+     * @param key
+     *            The key for the {@link PreparedStatement} to be created.
+     */
+    @SuppressWarnings("resource")
+    @Override
+    public PooledObject<DelegatingPreparedStatement> makeObject(final PStmtKey key) throws Exception {
+        if (null == key) {
+            throw new IllegalArgumentException("Prepared statement key is null or invalid.");
+        }
+        if (key.getStmtType() == StatementType.PREPARED_STATEMENT) {
+            final PreparedStatement statement = (PreparedStatement) key.createStatement(connection);
+            @SuppressWarnings({"rawtypes", "unchecked" }) // Unable to find way to avoid this
+            final PoolablePreparedStatement pps = new PoolablePreparedStatement(statement, key, pStmtPool,
+                    delegatingConnection);
+            return new DefaultPooledObject<DelegatingPreparedStatement>(pps);
+        }
+        final CallableStatement statement = (CallableStatement) key.createStatement(connection);
+        @SuppressWarnings("unchecked")
+        final PoolableCallableStatement pcs = new PoolableCallableStatement(statement, key, pStmtPool,
+                (DelegatingConnection<Connection>) delegatingConnection);
+        return new DefaultPooledObject<DelegatingPreparedStatement>(pcs);
+    }
+
+    /**
+     * Normalizes the given SQL statement, producing a canonical form that is semantically equivalent to the original.
+     */
+    protected String normalizeSQL(final String sql) {
+        return sql.trim();
+    }
+
+    /**
+     * Sends a connectionClosed event.
+     */
+    void notifyListeners() {
+        final ConnectionEvent event = new ConnectionEvent(this);
+        final Object[] listeners = eventListeners.toArray();
+        for (final Object listener : listeners) {
+            ((ConnectionEventListener) listener).connectionClosed(event);
+        }
+    }
+
+    /**
+     * My {@link KeyedPooledObjectFactory} method for passivating {@link PreparedStatement}s. Currently invokes
+     * {@link PreparedStatement#clearParameters}.
+     *
+     * @param key
+     *            ignored
+     * @param pooledObject
+     *            a wrapped {@link PreparedStatement}
+     */
+    @Override
+    public void passivateObject(final PStmtKey key, final PooledObject<DelegatingPreparedStatement> pooledObject)
+            throws Exception {
+        @SuppressWarnings("resource")
+        final DelegatingPreparedStatement dps = pooledObject.getObject();
+        dps.clearParameters();
+        dps.passivate();
+    }
+
+    /**
+     * Creates or obtains a {@link CallableStatement} from my pool.
+     *
+     * @param sql
+     *            an SQL statement that may contain one or more '?' parameter placeholders. Typically this statement is
+     *            specified using JDBC call escape syntax.
+     * @return a default <code>CallableStatement</code> object containing the pre-compiled SQL statement.
+     * @exception SQLException
+     *                Thrown if a database access error occurs or this method is called on a closed connection.
+     * @since 2.4.0
+     */
+    CallableStatement prepareCall(final String sql) throws SQLException {
+        if (pStmtPool == null) {
+            return connection.prepareCall(sql);
+        }
+        try {
+            return (CallableStatement) pStmtPool.borrowObject(createKey(sql, StatementType.CALLABLE_STATEMENT));
+        } catch (final RuntimeException e) {
+            throw e;
+        } catch (final Exception e) {
+            throw new SQLException("Borrow prepareCall from pool failed", e);
+        }
+    }
+
+    /**
+     * Creates or obtains a {@link CallableStatement} from my pool.
+     *
+     * @param sql
+     *            a <code>String</code> object that is the SQL statement to be sent to the database; may contain on or
+     *            more '?' parameters.
+     * @param resultSetType
+     *            a result set type; one of <code>ResultSet.TYPE_FORWARD_ONLY</code>,
+     *            <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>.
+     * @param resultSetConcurrency
+     *            a concurrency type; one of <code>ResultSet.CONCUR_READ_ONLY</code> or
+     *            <code>ResultSet.CONCUR_UPDATABLE</code>.
+     * @return a <code>CallableStatement</code> object containing the pre-compiled SQL statement that will produce
+     *         <code>ResultSet</code> objects with the given type and concurrency.
+     * @throws SQLException
+     *             Thrown if a database access error occurs, this method is called on a closed connection or the given
+     *             parameters are not <code>ResultSet</code> constants indicating type and concurrency.
+     * @since 2.4.0
+     */
+    CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency)
+            throws SQLException {
+        if (pStmtPool == null) {
+            return connection.prepareCall(sql, resultSetType, resultSetConcurrency);
+        }
+        try {
+            return (CallableStatement) pStmtPool.borrowObject(
+                    createKey(sql, resultSetType, resultSetConcurrency, StatementType.CALLABLE_STATEMENT));
+        } catch (final RuntimeException e) {
+            throw e;
+        } catch (final Exception e) {
+            throw new SQLException("Borrow prepareCall from pool failed", e);
+        }
+    }
+
+    /**
+     * Creates or obtains a {@link CallableStatement} from my pool.
+     *
+     * @param sql
+     *            a <code>String</code> object that is the SQL statement to be sent to the database; may contain on or
+     *            more '?' parameters.
+     * @param resultSetType
+     *            one of the following <code>ResultSet</code> constants: <code>ResultSet.TYPE_FORWARD_ONLY</code>,
+     *            <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>.
+     * @param resultSetConcurrency
+     *            one of the following <code>ResultSet</code> constants: <code>ResultSet.CONCUR_READ_ONLY</code> or
+     *            <code>ResultSet.CONCUR_UPDATABLE</code>.
+     * @param resultSetHoldability
+     *            one of the following <code>ResultSet</code> constants: <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code>
+     *            or <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>.
+     * @return a new <code>CallableStatement</code> object, containing the pre-compiled SQL statement, that will
+     *         generate <code>ResultSet</code> objects with the given type, concurrency, and holdability.
+     * @throws SQLException
+     *             Thrown if a database access error occurs, this method is called on a closed connection or the given
+     *             parameters are not <code>ResultSet</code> constants indicating type, concurrency, and holdability.
+     * @since 2.4.0
+     */
+    CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency,
+            final int resultSetHoldability) throws SQLException {
+        if (pStmtPool == null) {
+            return connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
+        }
+        try {
+            return (CallableStatement) pStmtPool.borrowObject(createKey(sql, resultSetType, resultSetConcurrency,
+                    resultSetHoldability, StatementType.CALLABLE_STATEMENT));
+        } catch (final RuntimeException e) {
+            throw e;
+        } catch (final Exception e) {
+            throw new SQLException("Borrow prepareCall from pool failed", e);
+        }
+    }
+
+    /**
+     * Creates or obtains a {@link PreparedStatement} from my pool.
+     *
+     * @param sql
+     *            the SQL statement.
+     * @return a {@link PoolablePreparedStatement}
+     */
+    PreparedStatement prepareStatement(final String sql) throws SQLException {
+        if (pStmtPool == null) {
+            return connection.prepareStatement(sql);
+        }
+        try {
+            return pStmtPool.borrowObject(createKey(sql));
+        } catch (final RuntimeException e) {
+            throw e;
+        } catch (final Exception e) {
+            throw new SQLException("Borrow prepareStatement from pool failed", e);
+        }
+    }
+
+    /**
+     * Creates or obtains a {@link PreparedStatement} from my pool.
+     *
+     * @param sql
+     *            an SQL statement that may contain one or more '?' IN parameter placeholders.
+     * @param autoGeneratedKeys
+     *            a flag indicating whether auto-generated keys should be returned; one of
+     *            <code>Statement.RETURN_GENERATED_KEYS</code> or <code>Statement.NO_GENERATED_KEYS</code>.
+     * @return a {@link PoolablePreparedStatement}
+     * @see Connection#prepareStatement(String, int)
+     */
+    PreparedStatement prepareStatement(final String sql, final int autoGeneratedKeys) throws SQLException {
+        if (pStmtPool == null) {
+            return connection.prepareStatement(sql, autoGeneratedKeys);
+        }
+        try {
+            return pStmtPool.borrowObject(createKey(sql, autoGeneratedKeys));
+        } catch (final RuntimeException e) {
+            throw e;
+        } catch (final Exception e) {
+            throw new SQLException("Borrow prepareStatement from pool failed", e);
+        }
+    }
+
+    PreparedStatement prepareStatement(final String sql, final int columnIndexes[]) throws SQLException {
+        if (pStmtPool == null) {
+            return connection.prepareStatement(sql, columnIndexes);
+        }
+        try {
+            return pStmtPool.borrowObject(createKey(sql, columnIndexes));
+        } catch (final RuntimeException e) {
+            throw e;
+        } catch (final Exception e) {
+            throw new SQLException("Borrow prepareStatement from pool failed", e);
+        }
+    }
+
+    /**
+     * Creates or obtains a {@link PreparedStatement} from my pool.
+     *
+     * @param sql
+     *            a <code>String</code> object that is the SQL statement to be sent to the database; may contain one or
+     *            more '?' IN parameters.
+     * @param resultSetType
+     *            a result set type; one of <code>ResultSet.TYPE_FORWARD_ONLY</code>,
+     *            <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>.
+     * @param resultSetConcurrency
+     *            a concurrency type; one of <code>ResultSet.CONCUR_READ_ONLY</code> or
+     *            <code>ResultSet.CONCUR_UPDATABLE</code>.
+     *
+     * @return a {@link PoolablePreparedStatement}.
+     * @see Connection#prepareStatement(String, int, int)
+     */
+    PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency)
+            throws SQLException {
+        if (pStmtPool == null) {
+            return connection.prepareStatement(sql, resultSetType, resultSetConcurrency);
+        }
+        try {
+            return pStmtPool.borrowObject(createKey(sql, resultSetType, resultSetConcurrency));
+        } catch (final RuntimeException e) {
+            throw e;
+        } catch (final Exception e) {
+            throw new SQLException("Borrow prepareStatement from pool failed", e);
+        }
+    }
+
+    PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency,
+            final int resultSetHoldability) throws SQLException {
+        if (pStmtPool == null) {
+            return connection.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
+        }
+        try {
+            return pStmtPool.borrowObject(createKey(sql, resultSetType, resultSetConcurrency, resultSetHoldability));
+        } catch (final RuntimeException e) {
+            throw e;
+        } catch (final Exception e) {
+            throw new SQLException("Borrow prepareStatement from pool failed", e);
+        }
+    }
+
+    PreparedStatement prepareStatement(final String sql, final String columnNames[]) throws SQLException {
+        if (pStmtPool == null) {
+            return connection.prepareStatement(sql, columnNames);
+        }
+        try {
+            return pStmtPool.borrowObject(createKey(sql, columnNames));
+        } catch (final RuntimeException e) {
+            throw e;
+        } catch (final Exception e) {
+            throw new SQLException("Borrow prepareStatement from pool failed", e);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void removeConnectionEventListener(final ConnectionEventListener listener) {
+        eventListeners.remove(listener);
+    }
+
+    /* JDBC_4_ANT_KEY_BEGIN */
+    @Override
+    public void removeStatementEventListener(final StatementEventListener listener) {
+        statementEventListeners.remove(listener);
+    }
+    /* JDBC_4_ANT_KEY_END */
+
+    /**
+     * Sets the value of the accessToUnderlyingConnectionAllowed property. It controls if the PoolGuard allows access to
+     * the underlying connection. (Default: false.)
+     *
+     * @param allow
+     *            Access to the underlying connection is granted when true.
      */
     public synchronized void setAccessToUnderlyingConnectionAllowed(final boolean allow) {
         this.accessToUnderlyingConnectionAllowed = allow;
     }
+
+    public void setStatementPool(final KeyedObjectPool<PStmtKey, DelegatingPreparedStatement> statementPool) {
+        pStmtPool = statementPool;
+    }
+
+    /**
+     * My {@link KeyedPooledObjectFactory} method for validating {@link PreparedStatement}s.
+     *
+     * @param key
+     *            Ignored.
+     * @param pooledObject
+     *            Ignored.
+     * @return {@code true}
+     */
+    @Override
+    public boolean validateObject(final PStmtKey key, final PooledObject<DelegatingPreparedStatement> pooledObject) {
+        return true;
+    }
 }
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/datasources/CPDSConnectionFactory.java b/java/org/apache/tomcat/dbcp/dbcp2/datasources/CPDSConnectionFactory.java
index dec69b0..bc42266 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/datasources/CPDSConnectionFactory.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/datasources/CPDSConnectionFactory.java
@@ -40,67 +40,86 @@
  * A {@link PooledObjectFactory} that creates
  * {@link org.apache.tomcat.dbcp.dbcp2.PoolableConnection PoolableConnection}s.
  *
- * @author John D. McNally
  * @since 2.0
  */
 class CPDSConnectionFactory
-        implements PooledObjectFactory<PooledConnectionAndInfo>,
-        ConnectionEventListener, PooledConnectionManager {
+        implements PooledObjectFactory<PooledConnectionAndInfo>, ConnectionEventListener, PooledConnectionManager {
 
-    private static final String NO_KEY_MESSAGE
-            = "close() was called on a Connection, but "
-            + "I have no record of the underlying PooledConnection.";
+    private static final String NO_KEY_MESSAGE = "close() was called on a Connection, but I have no record of the underlying PooledConnection.";
 
-    private final ConnectionPoolDataSource _cpds;
-    private final String _validationQuery;
-    private final int _validationQueryTimeout;
-    private final boolean _rollbackAfterValidation;
-    private ObjectPool<PooledConnectionAndInfo> _pool;
-    private final String _username;
-    private String _password = null;
+    private final ConnectionPoolDataSource cpds;
+    private final String validationQuery;
+    private final int validationQueryTimeoutSeconds;
+    private final boolean rollbackAfterValidation;
+    private ObjectPool<PooledConnectionAndInfo> pool;
+    private final String userName;
+    private char[] userPassword;
     private long maxConnLifetimeMillis = -1;
 
-
     /**
-     * Map of PooledConnections for which close events are ignored.
-     * Connections are muted when they are being validated.
+     * Map of PooledConnections for which close events are ignored. Connections are muted when they are being validated.
      */
-    private final Set<PooledConnection> validatingSet =
-            Collections.newSetFromMap(new ConcurrentHashMap<PooledConnection,Boolean>());
+    private final Set<PooledConnection> validatingSet = Collections
+            .newSetFromMap(new ConcurrentHashMap<PooledConnection, Boolean>());
 
     /**
      * Map of PooledConnectionAndInfo instances
      */
-    private final Map<PooledConnection, PooledConnectionAndInfo> pcMap =
-        new ConcurrentHashMap<>();
+    private final Map<PooledConnection, PooledConnectionAndInfo> pcMap = new ConcurrentHashMap<>();
 
     /**
-     * Create a new {@code PoolableConnectionFactory}.
+     * Creates a new {@code PoolableConnectionFactory}.
      *
-     * @param cpds the ConnectionPoolDataSource from which to obtain
-     * PooledConnection's
-     * @param validationQuery a query to use to {@link #validateObject
-     * validate} {@link Connection}s. Should return at least one row.
-     * May be {@code null} in which case {@link Connection#isValid(int)} will
-     * be used to validate connections.
-     * @param validationQueryTimeout Timeout in seconds before validation fails
-     * @param rollbackAfterValidation whether a rollback should be issued
-     * after {@link #validateObject validating} {@link Connection}s.
-     * @param username
-     * @param password
+     * @param cpds
+     *            the ConnectionPoolDataSource from which to obtain PooledConnection's
+     * @param validationQuery
+     *            a query to use to {@link #validateObject validate} {@link Connection}s. Should return at least one
+     *            row. May be {@code null} in which case {@link Connection#isValid(int)} will be used to validate
+     *            connections.
+     * @param validationQueryTimeoutSeconds
+     *            Timeout in seconds before validation fails
+     * @param rollbackAfterValidation
+     *            whether a rollback should be issued after {@link #validateObject validating} {@link Connection}s.
+     * @param userName
+     *            The user name to use to create connections
+     * @param userPassword
+     *            The password to use to create connections
+     * @since 2.4.0
      */
-    public CPDSConnectionFactory(final ConnectionPoolDataSource cpds,
-                                 final String validationQuery,
-                                 final int validationQueryTimeout,
-                                 final boolean rollbackAfterValidation,
-                                 final String username,
-                                 final String password) {
-        _cpds = cpds;
-        _validationQuery = validationQuery;
-        _validationQueryTimeout = validationQueryTimeout;
-        _username = username;
-        _password = password;
-        _rollbackAfterValidation = rollbackAfterValidation;
+    public CPDSConnectionFactory(final ConnectionPoolDataSource cpds, final String validationQuery,
+            final int validationQueryTimeoutSeconds, final boolean rollbackAfterValidation, final String userName,
+            final char[] userPassword) {
+        this.cpds = cpds;
+        this.validationQuery = validationQuery;
+        this.validationQueryTimeoutSeconds = validationQueryTimeoutSeconds;
+        this.userName = userName;
+        this.userPassword = userPassword;
+        this.rollbackAfterValidation = rollbackAfterValidation;
+    }
+
+    /**
+     * Creates a new {@code PoolableConnectionFactory}.
+     *
+     * @param cpds
+     *            the ConnectionPoolDataSource from which to obtain PooledConnection's
+     * @param validationQuery
+     *            a query to use to {@link #validateObject validate} {@link Connection}s. Should return at least one
+     *            row. May be {@code null} in which case {@link Connection#isValid(int)} will be used to validate
+     *            connections.
+     * @param validationQueryTimeoutSeconds
+     *            Timeout in seconds before validation fails
+     * @param rollbackAfterValidation
+     *            whether a rollback should be issued after {@link #validateObject validating} {@link Connection}s.
+     * @param userName
+     *            The user name to use to create connections
+     * @param userPassword
+     *            The password to use to create connections
+     */
+    public CPDSConnectionFactory(final ConnectionPoolDataSource cpds, final String validationQuery,
+            final int validationQueryTimeoutSeconds, final boolean rollbackAfterValidation, final String userName,
+            final String userPassword) {
+        this(cpds, validationQuery, validationQueryTimeoutSeconds, rollbackAfterValidation, userName,
+                Utils.toCharArray(userPassword));
     }
 
     /**
@@ -109,16 +128,16 @@
      * @return ObjectPool managing pooled connections
      */
     public ObjectPool<PooledConnectionAndInfo> getPool() {
-        return _pool;
+        return pool;
     }
 
     /**
      *
-     * @param pool the {@link ObjectPool} in which to pool those {@link
-     * Connection}s
+     * @param pool
+     *            the {@link ObjectPool} in which to pool those {@link Connection}s
      */
     public void setPool(final ObjectPool<PooledConnectionAndInfo> pool) {
-        this._pool = pool;
+        this.pool = pool;
     }
 
     @Override
@@ -126,10 +145,10 @@
         PooledConnectionAndInfo pci;
         try {
             PooledConnection pc = null;
-            if (_username == null) {
-                pc = _cpds.getPooledConnection();
+            if (userName == null) {
+                pc = cpds.getPooledConnection();
             } else {
-                pc = _cpds.getPooledConnection(_username, _password);
+                pc = cpds.getPooledConnection(userName, Utils.toString(userPassword));
             }
 
             if (pc == null) {
@@ -139,7 +158,7 @@
             // should we add this object as a listener or the pool.
             // consider the validateObject method in decision
             pc.addConnectionEventListener(this);
-            pci = new PooledConnectionAndInfo(pc, _username, _password);
+            pci = new PooledConnectionAndInfo(pc, userName, userPassword);
             pcMap.put(pc, pci);
         } catch (final SQLException e) {
             throw new RuntimeException(e.getMessage());
@@ -155,7 +174,7 @@
         doDestroyObject(p.getObject());
     }
 
-    private void doDestroyObject(final PooledConnectionAndInfo pci) throws Exception{
+    private void doDestroyObject(final PooledConnectionAndInfo pci) throws Exception {
         final PooledConnection pc = pci.getPooledConnection();
         pc.removeConnectionEventListener(this);
         pcMap.remove(pc);
@@ -173,14 +192,14 @@
         final PooledConnection pconn = p.getObject().getPooledConnection();
         Connection conn = null;
         validatingSet.add(pconn);
-        if (null == _validationQuery) {
-            int timeout = _validationQueryTimeout;
-            if (timeout < 0) {
-                timeout = 0;
+        if (null == validationQuery) {
+            int timeoutSeconds = validationQueryTimeoutSeconds;
+            if (timeoutSeconds < 0) {
+                timeoutSeconds = 0;
             }
             try {
                 conn = pconn.getConnection();
-                valid = conn.isValid(timeout);
+                valid = conn.isValid(timeoutSeconds);
             } catch (final SQLException e) {
                 valid = false;
             } finally {
@@ -198,13 +217,13 @@
             try {
                 conn = pconn.getConnection();
                 stmt = conn.createStatement();
-                rset = stmt.executeQuery(_validationQuery);
+                rset = stmt.executeQuery(validationQuery);
                 if (rset.next()) {
                     valid = true;
                 } else {
                     valid = false;
                 }
-                if (_rollbackAfterValidation) {
+                if (rollbackAfterValidation) {
                     conn.rollback();
                 }
             } catch (final Exception e) {
@@ -220,14 +239,12 @@
     }
 
     @Override
-    public void passivateObject(final PooledObject<PooledConnectionAndInfo> p)
-            throws Exception {
+    public void passivateObject(final PooledObject<PooledConnectionAndInfo> p) throws Exception {
         validateLifetime(p);
     }
 
     @Override
-    public void activateObject(final PooledObject<PooledConnectionAndInfo> p)
-            throws Exception {
+    public void activateObject(final PooledObject<PooledConnectionAndInfo> p) throws Exception {
         validateLifetime(p);
     }
 
@@ -236,10 +253,9 @@
     // ***********************************************************************
 
     /**
-     * This will be called if the Connection returned by the getConnection
-     * method came from a PooledConnection, and the user calls the close()
-     * method of this connection object. What we need to do here is to
-     * release this PooledConnection from our pool...
+     * This will be called if the Connection returned by the getConnection method came from a PooledConnection, and the
+     * user calls the close() method of this connection object. What we need to do here is to release this
+     * PooledConnection from our pool...
      */
     @Override
     public void connectionClosed(final ConnectionEvent event) {
@@ -253,16 +269,14 @@
             }
 
             try {
-                _pool.returnObject(pci);
+                pool.returnObject(pci);
             } catch (final Exception e) {
-                System.err.println("CLOSING DOWN CONNECTION AS IT COULD "
-                        + "NOT BE RETURNED TO THE POOL");
+                System.err.println("CLOSING DOWN CONNECTION AS IT COULD " + "NOT BE RETURNED TO THE POOL");
                 pc.removeConnectionEventListener(this);
                 try {
                     doDestroyObject(pci);
                 } catch (final Exception e2) {
-                    System.err.println("EXCEPTION WHILE DESTROYING OBJECT "
-                            + pci);
+                    System.err.println("EXCEPTION WHILE DESTROYING OBJECT " + pci);
                     e2.printStackTrace();
                 }
             }
@@ -270,16 +284,13 @@
     }
 
     /**
-     * If a fatal error occurs, close the underlying physical connection so as
-     * not to be returned in the future
+     * If a fatal error occurs, close the underlying physical connection so as not to be returned in the future
      */
     @Override
     public void connectionErrorOccurred(final ConnectionEvent event) {
-        final PooledConnection pc = (PooledConnection)event.getSource();
+        final PooledConnection pc = (PooledConnection) event.getSource();
         if (null != event.getSQLException()) {
-            System.err.println(
-                    "CLOSING DOWN CONNECTION DUE TO INTERNAL ERROR ("
-                    + event.getSQLException() + ")");
+            System.err.println("CLOSING DOWN CONNECTION DUE TO INTERNAL ERROR (" + event.getSQLException() + ")");
         }
         pc.removeConnectionEventListener(this);
 
@@ -288,7 +299,7 @@
             throw new IllegalStateException(NO_KEY_MESSAGE);
         }
         try {
-            _pool.invalidateObject(pci);
+            pool.invalidateObject(pci);
         } catch (final Exception e) {
             System.err.println("EXCEPTION WHILE DESTROYING OBJECT " + pci);
             e.printStackTrace();
@@ -300,10 +311,9 @@
     // ***********************************************************************
 
     /**
-     * Invalidates the PooledConnection in the pool.  The CPDSConnectionFactory
-     * closes the connection and pool counters are updated appropriately.
-     * Also closes the pool.  This ensures that all idle connections are closed
-     * and connections that are checked out are closed on return.
+     * Invalidates the PooledConnection in the pool. The CPDSConnectionFactory closes the connection and pool counters
+     * are updated appropriately. Also closes the pool. This ensures that all idle connections are closed and
+     * connections that are checked out are closed on return.
      */
     @Override
     public void invalidate(final PooledConnection pc) throws SQLException {
@@ -312,8 +322,8 @@
             throw new IllegalStateException(NO_KEY_MESSAGE);
         }
         try {
-            _pool.invalidateObject(pci);  // Destroy instance and update pool counters
-            _pool.close();  // Clear any other instances in this pool and kill others as they come back
+            pool.invalidateObject(pci); // Destroy instance and update pool counters
+            pool.close(); // Clear any other instances in this pool and kill others as they come back
         } catch (final Exception ex) {
             throw new SQLException("Error invalidating connection", ex);
         }
@@ -322,49 +332,58 @@
     /**
      * Sets the database password used when creating new connections.
      *
-     * @param password new password
+     * @param userPassword
+     *            new password
      */
-    @Override
-    public synchronized void setPassword(final String password) {
-        _password = password;
+    public synchronized void setPassword(final char[] userPassword) {
+        this.userPassword = userPassword;
     }
 
     /**
-     * Sets the maximum lifetime in milliseconds of a connection after which the
-     * connection will always fail activation, passivation and validation. A
-     * value of zero or less indicates an infinite lifetime. The default value
-     * is -1.
+     * Sets the database password used when creating new connections.
+     *
+     * @param userPassword
+     *            new password
+     */
+    @Override
+    public synchronized void setPassword(final String userPassword) {
+        this.userPassword = Utils.toCharArray(userPassword);
+    }
+
+    /**
+     * Sets the maximum lifetime in milliseconds of a connection after which the connection will always fail activation,
+     * passivation and validation.
+     *
+     * @param maxConnLifetimeMillis
+     *            A value of zero or less indicates an infinite lifetime. The default value is -1.
      */
     public void setMaxConnLifetimeMillis(final long maxConnLifetimeMillis) {
         this.maxConnLifetimeMillis = maxConnLifetimeMillis;
     }
 
     /**
-     * Verifies that the username matches the user whose connections are being managed by this
-     * factory and closes the pool if this is the case; otherwise does nothing.
+     * Verifies that the user name matches the user whose connections are being managed by this factory and closes the
+     * pool if this is the case; otherwise does nothing.
      */
     @Override
-    public void closePool(final String username) throws SQLException {
+    public void closePool(final String userName) throws SQLException {
         synchronized (this) {
-            if (username == null || !username.equals(_username)) {
+            if (userName == null || !userName.equals(this.userName)) {
                 return;
             }
         }
         try {
-            _pool.close();
+            pool.close();
         } catch (final Exception ex) {
             throw new SQLException("Error closing connection pool", ex);
         }
     }
 
-    private void validateLifetime(final PooledObject<PooledConnectionAndInfo> p)
-            throws Exception {
+    private void validateLifetime(final PooledObject<PooledConnectionAndInfo> p) throws Exception {
         if (maxConnLifetimeMillis > 0) {
             final long lifetime = System.currentTimeMillis() - p.getCreateTime();
             if (lifetime > maxConnLifetimeMillis) {
-                throw new Exception(Utils.getMessage(
-                        "connectionFactory.lifetimeExceeded",
-                        Long.valueOf(lifetime),
+                throw new Exception(Utils.getMessage("connectionFactory.lifetimeExceeded", Long.valueOf(lifetime),
                         Long.valueOf(maxConnLifetimeMillis)));
             }
         }
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSource.java b/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSource.java
index 9f114bc..444ec1d 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSource.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSource.java
@@ -39,132 +39,104 @@
 import org.apache.tomcat.dbcp.pool2.impl.GenericKeyedObjectPoolConfig;
 
 /**
- * <p>The base class for <code>SharedPoolDataSource</code> and
- * <code>PerUserPoolDataSource</code>.  Many of the configuration properties
- * are shared and defined here.  This class is declared public in order
- * to allow particular usage with commons-beanutils; do not make direct
- * use of it outside of <em>commons-dbcp2</em>.
+ * <p>
+ * The base class for <code>SharedPoolDataSource</code> and <code>PerUserPoolDataSource</code>. Many of the
+ * configuration properties are shared and defined here. This class is declared public in order to allow particular
+ * usage with commons-beanutils; do not make direct use of it outside of <em>commons-dbcp2</em>.
  * </p>
  *
  * <p>
- * A J2EE container will normally provide some method of initializing the
- * <code>DataSource</code> whose attributes are presented
- * as bean getters/setters and then deploying it via JNDI.  It is then
- * available to an application as a source of pooled logical connections to
- * the database.  The pool needs a source of physical connections.  This
- * source is in the form of a <code>ConnectionPoolDataSource</code> that
- * can be specified via the {@link #setDataSourceName(String)} used to
- * lookup the source via JNDI.
+ * A J2EE container will normally provide some method of initializing the <code>DataSource</code> whose attributes are
+ * presented as bean getters/setters and then deploying it via JNDI. It is then available to an application as a source
+ * of pooled logical connections to the database. The pool needs a source of physical connections. This source is in the
+ * form of a <code>ConnectionPoolDataSource</code> that can be specified via the {@link #setDataSourceName(String)} used
+ * to lookup the source via JNDI.
  * </p>
  *
  * <p>
- * Although normally used within a JNDI environment, A DataSource
- * can be instantiated and initialized as any bean.  In this case the
- * <code>ConnectionPoolDataSource</code> will likely be instantiated in
- * a similar manner.  This class allows the physical source of connections
- * to be attached directly to this pool using the
+ * Although normally used within a JNDI environment, A DataSource can be instantiated and initialized as any bean. In
+ * this case the <code>ConnectionPoolDataSource</code> will likely be instantiated in a similar manner. This class
+ * allows the physical source of connections to be attached directly to this pool using the
  * {@link #setConnectionPoolDataSource(ConnectionPoolDataSource)} method.
  * </p>
  *
  * <p>
- * The dbcp package contains an adapter,
- * {@link org.apache.tomcat.dbcp.dbcp2.cpdsadapter.DriverAdapterCPDS},
- * that can be used to allow the use of <code>DataSource</code>'s based on this
- * class with JDBC driver implementations that do not supply a
- * <code>ConnectionPoolDataSource</code>, but still
- * provide a {@link java.sql.Driver} implementation.
+ * The dbcp package contains an adapter, {@link org.apache.tomcat.dbcp.dbcp2.cpdsadapter.DriverAdapterCPDS}, that can be
+ * used to allow the use of <code>DataSource</code>'s based on this class with JDBC driver implementations that do not
+ * supply a <code>ConnectionPoolDataSource</code>, but still provide a {@link java.sql.Driver} implementation.
  * </p>
  *
  * <p>
- * The <a href="package-summary.html">package documentation</a> contains an
- * example using Apache Tomcat and JNDI and it also contains a non-JNDI example.
+ * The <a href="package-summary.html">package documentation</a> contains an example using Apache Tomcat and JNDI and it
+ * also contains a non-JNDI example.
  * </p>
  *
- * @author John D. McNally
  * @since 2.0
  */
-public abstract class InstanceKeyDataSource
-        implements DataSource, Referenceable, Serializable, AutoCloseable {
+public abstract class InstanceKeyDataSource implements DataSource, Referenceable, Serializable, AutoCloseable {
 
     private static final long serialVersionUID = -6819270431752240878L;
 
-    private static final String GET_CONNECTION_CALLED
-            = "A Connection was already requested from this source, "
+    private static final String GET_CONNECTION_CALLED = "A Connection was already requested from this source, "
             + "further initialization is not allowed.";
-    private static final String BAD_TRANSACTION_ISOLATION
-        = "The requested TransactionIsolation level is invalid.";
+    private static final String BAD_TRANSACTION_ISOLATION = "The requested TransactionIsolation level is invalid.";
 
     /**
-    * Internal constant to indicate the level is not set.
-    */
+     * Internal constant to indicate the level is not set.
+     */
     protected static final int UNKNOWN_TRANSACTIONISOLATION = -1;
 
     /** Guards property setters - once true, setters throw IllegalStateException */
-    private volatile boolean getConnectionCalled = false;
+    private volatile boolean getConnectionCalled;
 
     /** Underlying source of PooledConnections */
-    private ConnectionPoolDataSource dataSource = null;
+    private ConnectionPoolDataSource dataSource;
 
     /** DataSource Name used to find the ConnectionPoolDataSource */
-    private String dataSourceName = null;
+    private String dataSourceName;
 
     /** Description */
-    private String description = null;
+    private String description;
 
     /** Environment that may be used to set up a jndi initial context. */
-    private Properties jndiEnvironment = null;
+    private Properties jndiEnvironment;
 
     /** Login TimeOut in seconds */
-    private int loginTimeout = 0;
+    private int loginTimeout;
 
     /** Log stream */
-    private PrintWriter logWriter = null;
+    private PrintWriter logWriter;
 
     /** Instance key */
-    private String instanceKey = null;
+    private String instanceKey;
 
     // Pool properties
-    private boolean defaultBlockWhenExhausted =
-            BaseObjectPoolConfig.DEFAULT_BLOCK_WHEN_EXHAUSTED;
-    private String defaultEvictionPolicyClassName =
-            BaseObjectPoolConfig.DEFAULT_EVICTION_POLICY_CLASS_NAME;
+    private boolean defaultBlockWhenExhausted = BaseObjectPoolConfig.DEFAULT_BLOCK_WHEN_EXHAUSTED;
+    private String defaultEvictionPolicyClassName = BaseObjectPoolConfig.DEFAULT_EVICTION_POLICY_CLASS_NAME;
     private boolean defaultLifo = BaseObjectPoolConfig.DEFAULT_LIFO;
-    private int defaultMaxIdle =
-            GenericKeyedObjectPoolConfig.DEFAULT_MAX_IDLE_PER_KEY;
-    private int defaultMaxTotal =
-            GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL;
-    private long defaultMaxWaitMillis =
-            BaseObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS;
-    private long defaultMinEvictableIdleTimeMillis =
-            BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
-    private int defaultMinIdle =
-            GenericKeyedObjectPoolConfig.DEFAULT_MIN_IDLE_PER_KEY;
-    private int defaultNumTestsPerEvictionRun =
-            BaseObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
-    private long defaultSoftMinEvictableIdleTimeMillis =
-            BaseObjectPoolConfig.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
-    private boolean defaultTestOnCreate =
-            BaseObjectPoolConfig.DEFAULT_TEST_ON_CREATE;
-    private boolean defaultTestOnBorrow =
-            BaseObjectPoolConfig.DEFAULT_TEST_ON_BORROW;
-    private boolean defaultTestOnReturn =
-            BaseObjectPoolConfig.DEFAULT_TEST_ON_RETURN;
-    private boolean defaultTestWhileIdle =
-            BaseObjectPoolConfig.DEFAULT_TEST_WHILE_IDLE;
-    private long defaultTimeBetweenEvictionRunsMillis =
-            BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
+    private int defaultMaxIdle = GenericKeyedObjectPoolConfig.DEFAULT_MAX_IDLE_PER_KEY;
+    private int defaultMaxTotal = GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL;
+    private long defaultMaxWaitMillis = BaseObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS;
+    private long defaultMinEvictableIdleTimeMillis = BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
+    private int defaultMinIdle = GenericKeyedObjectPoolConfig.DEFAULT_MIN_IDLE_PER_KEY;
+    private int defaultNumTestsPerEvictionRun = BaseObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
+    private long defaultSoftMinEvictableIdleTimeMillis = BaseObjectPoolConfig.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
+    private boolean defaultTestOnCreate = BaseObjectPoolConfig.DEFAULT_TEST_ON_CREATE;
+    private boolean defaultTestOnBorrow = BaseObjectPoolConfig.DEFAULT_TEST_ON_BORROW;
+    private boolean defaultTestOnReturn = BaseObjectPoolConfig.DEFAULT_TEST_ON_RETURN;
+    private boolean defaultTestWhileIdle = BaseObjectPoolConfig.DEFAULT_TEST_WHILE_IDLE;
+    private long defaultTimeBetweenEvictionRunsMillis = BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
 
     // Connection factory properties
-    private String validationQuery = null;
-    private int validationQueryTimeout = -1;
-    private boolean rollbackAfterValidation = false;
+    private String validationQuery;
+    private int validationQueryTimeoutSeconds = -1;
+    private boolean rollbackAfterValidation;
     private long maxConnLifetimeMillis = -1;
 
     // Connection properties
-    private Boolean defaultAutoCommit = null;
+    private Boolean defaultAutoCommit;
     private int defaultTransactionIsolation = UNKNOWN_TRANSACTIONISOLATION;
-    private Boolean defaultReadOnly = null;
-
+    private Boolean defaultReadOnly;
 
     /**
      * Default no-arg constructor for Serialization
@@ -173,18 +145,16 @@
     }
 
     /**
-     * Throws an IllegalStateException, if a PooledConnection has already
-     * been requested.
+     * Throws an IllegalStateException, if a PooledConnection has already been requested.
      */
-    protected void assertInitializationAllowed()
-        throws IllegalStateException {
+    protected void assertInitializationAllowed() throws IllegalStateException {
         if (getConnectionCalled) {
             throw new IllegalStateException(GET_CONNECTION_CALLED);
         }
     }
 
     /**
-     * Close the connection pool being maintained by this datasource.
+     * Closes the connection pool being maintained by this datasource.
      */
     @Override
     public abstract void close() throws Exception;
@@ -208,23 +178,25 @@
         throw new SQLFeatureNotSupportedException();
     }
 
-
     // -------------------------------------------------------------------
     // Properties
 
     /**
-     * Gets the default value for
-     * {@link GenericKeyedObjectPoolConfig#getBlockWhenExhausted()} for each per
-     * user pool.
+     * Gets the default value for {@link GenericKeyedObjectPoolConfig#getBlockWhenExhausted()} for each per user pool.
+     *
+     * @return The default value for {@link GenericKeyedObjectPoolConfig#getBlockWhenExhausted()} for each per user
+     *         pool.
      */
     public boolean getDefaultBlockWhenExhausted() {
         return this.defaultBlockWhenExhausted;
     }
 
     /**
-     * Sets the default value for
-     * {@link GenericKeyedObjectPoolConfig#getBlockWhenExhausted()} for each per
-     * user pool.
+     * Sets the default value for {@link GenericKeyedObjectPoolConfig#getBlockWhenExhausted()} for each per user pool.
+     *
+     * @param blockWhenExhausted
+     *            The default value for {@link GenericKeyedObjectPoolConfig#getBlockWhenExhausted()} for each per user
+     *            pool.
      */
     public void setDefaultBlockWhenExhausted(final boolean blockWhenExhausted) {
         assertInitializationAllowed();
@@ -232,36 +204,43 @@
     }
 
     /**
-     * Gets the default value for
-     * {@link GenericKeyedObjectPoolConfig#getEvictionPolicyClassName()} for
-     * each per user pool.
+     * Gets the default value for {@link GenericKeyedObjectPoolConfig#getEvictionPolicyClassName()} for each per user
+     * pool.
+     *
+     * @return The default value for {@link GenericKeyedObjectPoolConfig#getEvictionPolicyClassName()} for each per user
+     *         pool.
      */
     public String getDefaultEvictionPolicyClassName() {
         return this.defaultEvictionPolicyClassName;
     }
 
     /**
-     * Sets the default value for
-     * {@link GenericKeyedObjectPoolConfig#getEvictionPolicyClassName()} for
-     * each per user pool.
+     * Sets the default value for {@link GenericKeyedObjectPoolConfig#getEvictionPolicyClassName()} for each per user
+     * pool.
+     *
+     * @param evictionPolicyClassName
+     *            The default value for {@link GenericKeyedObjectPoolConfig#getEvictionPolicyClassName()} for each per
+     *            user pool.
      */
-    public void setDefaultEvictionPolicyClassName(
-            final String evictionPolicyClassName) {
+    public void setDefaultEvictionPolicyClassName(final String evictionPolicyClassName) {
         assertInitializationAllowed();
         this.defaultEvictionPolicyClassName = evictionPolicyClassName;
     }
 
     /**
-     * Gets the default value for
-     * {@link GenericKeyedObjectPoolConfig#getLifo()} for each per user pool.
+     * Gets the default value for {@link GenericKeyedObjectPoolConfig#getLifo()} for each per user pool.
+     *
+     * @return The default value for {@link GenericKeyedObjectPoolConfig#getLifo()} for each per user pool.
      */
     public boolean getDefaultLifo() {
         return this.defaultLifo;
     }
 
     /**
-     * Sets the default value for
-     * {@link GenericKeyedObjectPoolConfig#getLifo()} for each per user pool.
+     * Sets the default value for {@link GenericKeyedObjectPoolConfig#getLifo()} for each per user pool.
+     *
+     * @param lifo
+     *            The default value for {@link GenericKeyedObjectPoolConfig#getLifo()} for each per user pool.
      */
     public void setDefaultLifo(final boolean lifo) {
         assertInitializationAllowed();
@@ -269,18 +248,19 @@
     }
 
     /**
-     * Gets the default value for
-     * {@link GenericKeyedObjectPoolConfig#getMaxIdlePerKey()} for each per user
-     * pool.
+     * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMaxIdlePerKey()} for each per user pool.
+     *
+     * @return The default value for {@link GenericKeyedObjectPoolConfig#getMaxIdlePerKey()} for each per user pool.
      */
     public int getDefaultMaxIdle() {
         return this.defaultMaxIdle;
     }
 
     /**
-     * Sets the default value for
-     * {@link GenericKeyedObjectPoolConfig#getMaxIdlePerKey()} for each per user
-     * pool.
+     * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMaxIdlePerKey()} for each per user pool.
+     *
+     * @param maxIdle
+     *            The default value for {@link GenericKeyedObjectPoolConfig#getMaxIdlePerKey()} for each per user pool.
      */
     public void setDefaultMaxIdle(final int maxIdle) {
         assertInitializationAllowed();
@@ -288,18 +268,19 @@
     }
 
     /**
-     * Gets the default value for
-     * {@link GenericKeyedObjectPoolConfig#getMaxTotalPerKey()} for each per
-     * user pool.
+     * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMaxTotalPerKey()} for each per user pool.
+     *
+     * @return The default value for {@link GenericKeyedObjectPoolConfig#getMaxTotalPerKey()} for each per user pool.
      */
     public int getDefaultMaxTotal() {
         return this.defaultMaxTotal;
     }
 
     /**
-     * Sets the default value for
-     * {@link GenericKeyedObjectPoolConfig#getMaxTotalPerKey()} for each per
-     * user pool.
+     * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMaxTotalPerKey()} for each per user pool.
+     *
+     * @param maxTotal
+     *            The default value for {@link GenericKeyedObjectPoolConfig#getMaxTotalPerKey()} for each per user pool.
      */
     public void setDefaultMaxTotal(final int maxTotal) {
         assertInitializationAllowed();
@@ -307,18 +288,19 @@
     }
 
     /**
-     * Gets the default value for
-     * {@link GenericKeyedObjectPoolConfig#getMaxWaitMillis()} for each per user
-     * pool.
+     * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitMillis()} for each per user pool.
+     *
+     * @return The default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitMillis()} for each per user pool.
      */
     public long getDefaultMaxWaitMillis() {
         return this.defaultMaxWaitMillis;
     }
 
     /**
-     * Sets the default value for
-     * {@link GenericKeyedObjectPoolConfig#getMaxWaitMillis()} for each per user
-     * pool.
+     * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitMillis()} for each per user pool.
+     *
+     * @param maxWaitMillis
+     *            The default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitMillis()} for each per user pool.
      */
     public void setDefaultMaxWaitMillis(final long maxWaitMillis) {
         assertInitializationAllowed();
@@ -326,38 +308,43 @@
     }
 
     /**
-     * Gets the default value for
-     * {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleTimeMillis()} for
-     * each per user pool.
+     * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleTimeMillis()} for each per user
+     * pool.
+     *
+     * @return The default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleTimeMillis()} for each per
+     *         user pool.
      */
     public long getDefaultMinEvictableIdleTimeMillis() {
         return this.defaultMinEvictableIdleTimeMillis;
     }
 
     /**
-     * Sets the default value for
-     * {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleTimeMillis()} for
-     * each per user pool.
+     * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleTimeMillis()} for each per user
+     * pool.
+     *
+     * @param minEvictableIdleTimeMillis
+     *            The default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleTimeMillis()} for each
+     *            per user pool.
      */
-    public void setDefaultMinEvictableIdleTimeMillis(
-            final long minEvictableIdleTimeMillis) {
+    public void setDefaultMinEvictableIdleTimeMillis(final long minEvictableIdleTimeMillis) {
         assertInitializationAllowed();
         this.defaultMinEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
     }
 
     /**
-     * Gets the default value for
-     * {@link GenericKeyedObjectPoolConfig#getMinIdlePerKey()} for each per user
-     * pool.
+     * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMinIdlePerKey()} for each per user pool.
+     *
+     * @return The default value for {@link GenericKeyedObjectPoolConfig#getMinIdlePerKey()} for each per user pool.
      */
     public int getDefaultMinIdle() {
         return this.defaultMinIdle;
     }
 
     /**
-     * Sets the default value for
-     * {@link GenericKeyedObjectPoolConfig#getMinIdlePerKey()} for each per user
-     * pool.
+     * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMinIdlePerKey()} for each per user pool.
+     *
+     * @param minIdle
+     *            The default value for {@link GenericKeyedObjectPoolConfig#getMinIdlePerKey()} for each per user pool.
      */
     public void setDefaultMinIdle(final int minIdle) {
         assertInitializationAllowed();
@@ -365,18 +352,23 @@
     }
 
     /**
-     * Gets the default value for
-     * {@link GenericKeyedObjectPoolConfig#getNumTestsPerEvictionRun()} for each
-     * per user pool.
+     * Gets the default value for {@link GenericKeyedObjectPoolConfig#getNumTestsPerEvictionRun()} for each per user
+     * pool.
+     *
+     * @return The default value for {@link GenericKeyedObjectPoolConfig#getNumTestsPerEvictionRun()} for each per user
+     *         pool.
      */
     public int getDefaultNumTestsPerEvictionRun() {
         return this.defaultNumTestsPerEvictionRun;
     }
 
     /**
-     * Sets the default value for
-     * {@link GenericKeyedObjectPoolConfig#getNumTestsPerEvictionRun()} for each
-     * per user pool.
+     * Sets the default value for {@link GenericKeyedObjectPoolConfig#getNumTestsPerEvictionRun()} for each per user
+     * pool.
+     *
+     * @param numTestsPerEvictionRun
+     *            The default value for {@link GenericKeyedObjectPoolConfig#getNumTestsPerEvictionRun()} for each per
+     *            user pool.
      */
     public void setDefaultNumTestsPerEvictionRun(final int numTestsPerEvictionRun) {
         assertInitializationAllowed();
@@ -384,35 +376,47 @@
     }
 
     /**
-     * Gets the default value for
-     * {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each
-     * per user pool.
+     * Gets the default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+     * GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool.
+     *
+     * @return The default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+     *         GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool.
      */
     public long getDefaultSoftMinEvictableIdleTimeMillis() {
         return this.defaultSoftMinEvictableIdleTimeMillis;
     }
 
     /**
-     * Sets the default value for
-     * {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool.
+     * Sets the default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+     * GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool.
+     *
+     * @param softMinEvictableIdleTimeMillis
+     *            The default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+     *            GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool.
      */
-    public void setDefaultSoftMinEvictableIdleTimeMillis(
-            final long softMinEvictableIdleTimeMillis) {
+    public void setDefaultSoftMinEvictableIdleTimeMillis(final long softMinEvictableIdleTimeMillis) {
         assertInitializationAllowed();
         this.defaultSoftMinEvictableIdleTimeMillis = softMinEvictableIdleTimeMillis;
     }
 
     /**
-     * Gets the default value for
-     * {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool GenericObjectPool#getTestOnCreate()} for each per user pool.
+     * Gets the default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+     * GenericObjectPool#getTestOnCreate()} for each per user pool.
+     *
+     * @return The default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+     *         GenericObjectPool#getTestOnCreate()} for each per user pool.
      */
     public boolean getDefaultTestOnCreate() {
         return this.defaultTestOnCreate;
     }
 
     /**
-     * Sets the default value for
-     * {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool GenericObjectPool#getTestOnCreate()} for each per user pool.
+     * Sets the default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+     * GenericObjectPool#getTestOnCreate()} for each per user pool.
+     *
+     * @param testOnCreate
+     *            The default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+     *            GenericObjectPool#getTestOnCreate()} for each per user pool.
      */
     public void setDefaultTestOnCreate(final boolean testOnCreate) {
         assertInitializationAllowed();
@@ -420,16 +424,23 @@
     }
 
     /**
-     * Gets the default value for
-     * {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool GenericObjectPool#getTestOnBorrow()} for each per user pool.
+     * Gets the default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+     * GenericObjectPool#getTestOnBorrow()} for each per user pool.
+     *
+     * @return The default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+     *         GenericObjectPool#getTestOnBorrow()} for each per user pool.
      */
     public boolean getDefaultTestOnBorrow() {
         return this.defaultTestOnBorrow;
     }
 
     /**
-     * Sets the default value for
-     * {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool GenericObjectPool#getTestOnBorrow()} for each per user pool.
+     * Sets the default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+     * GenericObjectPool#getTestOnBorrow()} for each per user pool.
+     *
+     * @param testOnBorrow
+     *            The default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+     *            GenericObjectPool#getTestOnBorrow()} for each per user pool.
      */
     public void setDefaultTestOnBorrow(final boolean testOnBorrow) {
         assertInitializationAllowed();
@@ -437,16 +448,23 @@
     }
 
     /**
-     * Gets the default value for
-     * {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool GenericObjectPool#getTestOnReturn()} for each per user pool.
+     * Gets the default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+     * GenericObjectPool#getTestOnReturn()} for each per user pool.
+     *
+     * @return The default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+     *         GenericObjectPool#getTestOnReturn()} for each per user pool.
      */
     public boolean getDefaultTestOnReturn() {
         return this.defaultTestOnReturn;
     }
 
     /**
-     * Sets the default value for
-     * {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool GenericObjectPool#getTestOnReturn()} for each per user pool.
+     * Sets the default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+     * GenericObjectPool#getTestOnReturn()} for each per user pool.
+     *
+     * @param testOnReturn
+     *            The default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+     *            GenericObjectPool#getTestOnReturn()} for each per user pool.
      */
     public void setDefaultTestOnReturn(final boolean testOnReturn) {
         assertInitializationAllowed();
@@ -454,16 +472,23 @@
     }
 
     /**
-     * Gets the default value for
-     * {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool GenericObjectPool#getTestWhileIdle()} for each per user pool.
+     * Gets the default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+     * GenericObjectPool#getTestWhileIdle()} for each per user pool.
+     *
+     * @return The default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+     *         GenericObjectPool#getTestWhileIdle()} for each per user pool.
      */
     public boolean getDefaultTestWhileIdle() {
         return this.defaultTestWhileIdle;
     }
 
     /**
-     * Sets the default value for
-     * {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool GenericObjectPool#getTestWhileIdle()} for each per user pool.
+     * Sets the default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+     * GenericObjectPool#getTestWhileIdle()} for each per user pool.
+     *
+     * @param testWhileIdle
+     *            The default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+     *            GenericObjectPool#getTestWhileIdle()} for each per user pool.
      */
     public void setDefaultTestWhileIdle(final boolean testWhileIdle) {
         assertInitializationAllowed();
@@ -471,28 +496,32 @@
     }
 
     /**
-     * Gets the default value for
-     * {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool GenericObjectPool#getTimeBetweenEvictionRunsMillis ()} for each
-     * per user pool.
+     * Gets the default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+     * GenericObjectPool#getTimeBetweenEvictionRunsMillis ()} for each per user pool.
+     *
+     * @return The default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+     *         GenericObjectPool#getTimeBetweenEvictionRunsMillis ()} for each per user pool.
      */
-    public long getDefaultTimeBetweenEvictionRunsMillis () {
-        return this.defaultTimeBetweenEvictionRunsMillis ;
+    public long getDefaultTimeBetweenEvictionRunsMillis() {
+        return this.defaultTimeBetweenEvictionRunsMillis;
     }
 
     /**
-     * Sets the default value for
-     * {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool GenericObjectPool#getTimeBetweenEvictionRunsMillis ()} for each
-     * per user pool.
+     * Sets the default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+     * GenericObjectPool#getTimeBetweenEvictionRunsMillis ()} for each per user pool.
+     *
+     * @param timeBetweenEvictionRunsMillis
+     *            The default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+     *            GenericObjectPool#getTimeBetweenEvictionRunsMillis ()} for each per user pool.
      */
-    public void setDefaultTimeBetweenEvictionRunsMillis (
-            final long timeBetweenEvictionRunsMillis ) {
+    public void setDefaultTimeBetweenEvictionRunsMillis(final long timeBetweenEvictionRunsMillis) {
         assertInitializationAllowed();
-        this.defaultTimeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis ;
+        this.defaultTimeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
     }
 
     /**
-     * Get the value of connectionPoolDataSource.  This method will return
-     * null, if the backing datasource is being accessed via jndi.
+     * Gets the value of connectionPoolDataSource. This method will return null, if the backing datasource is being
+     * accessed via jndi.
      *
      * @return value of connectionPoolDataSource.
      */
@@ -501,30 +530,27 @@
     }
 
     /**
-     * Set the backend ConnectionPoolDataSource.  This property should not be
-     * set if using jndi to access the datasource.
+     * Sets the backend ConnectionPoolDataSource. This property should not be set if using jndi to access the
+     * datasource.
      *
-     * @param v  Value to assign to connectionPoolDataSource.
+     * @param v
+     *            Value to assign to connectionPoolDataSource.
      */
     public void setConnectionPoolDataSource(final ConnectionPoolDataSource v) {
         assertInitializationAllowed();
         if (dataSourceName != null) {
-            throw new IllegalStateException(
-                "Cannot set the DataSource, if JNDI is used.");
+            throw new IllegalStateException("Cannot set the DataSource, if JNDI is used.");
         }
-        if (dataSource != null)
-        {
-            throw new IllegalStateException(
-                "The CPDS has already been set. It cannot be altered.");
+        if (dataSource != null) {
+            throw new IllegalStateException("The CPDS has already been set. It cannot be altered.");
         }
         dataSource = v;
         instanceKey = InstanceKeyDataSourceFactory.registerNewInstance(this);
     }
 
     /**
-     * Get the name of the ConnectionPoolDataSource which backs this pool.
-     * This name is used to look up the datasource from a jndi service
-     * provider.
+     * Gets the name of the ConnectionPoolDataSource which backs this pool. This name is used to look up the datasource
+     * from a jndi service provider.
      *
      * @return value of dataSourceName.
      */
@@ -533,35 +559,29 @@
     }
 
     /**
-     * Set the name of the ConnectionPoolDataSource which backs this pool.
-     * This name is used to look up the datasource from a jndi service
-     * provider.
+     * Sets the name of the ConnectionPoolDataSource which backs this pool. This name is used to look up the datasource
+     * from a jndi service provider.
      *
-     * @param v  Value to assign to dataSourceName.
+     * @param v
+     *            Value to assign to dataSourceName.
      */
     public void setDataSourceName(final String v) {
         assertInitializationAllowed();
         if (dataSource != null) {
-            throw new IllegalStateException(
-                "Cannot set the JNDI name for the DataSource, if already " +
-                "set using setConnectionPoolDataSource.");
+            throw new IllegalStateException("Cannot set the JNDI name for the DataSource, if already "
+                    + "set using setConnectionPoolDataSource.");
         }
-        if (dataSourceName != null)
-        {
-            throw new IllegalStateException(
-                "The DataSourceName has already been set. " +
-                "It cannot be altered.");
+        if (dataSourceName != null) {
+            throw new IllegalStateException("The DataSourceName has already been set. " + "It cannot be altered.");
         }
         this.dataSourceName = v;
         instanceKey = InstanceKeyDataSourceFactory.registerNewInstance(this);
     }
 
     /**
-     * Get the value of defaultAutoCommit, which defines the state of
-     * connections handed out from this pool.  The value can be changed
-     * on the Connection using Connection.setAutoCommit(boolean).
-     * The default is <code>null</code> which will use the default value for the
-     * drive.
+     * Gets the value of defaultAutoCommit, which defines the state of connections handed out from this pool. The value
+     * can be changed on the Connection using Connection.setAutoCommit(boolean). The default is <code>null</code> which
+     * will use the default value for the drive.
      *
      * @return value of defaultAutoCommit.
      */
@@ -570,13 +590,12 @@
     }
 
     /**
-     * Set the value of defaultAutoCommit, which defines the state of
-     * connections handed out from this pool.  The value can be changed
-     * on the Connection using Connection.setAutoCommit(boolean).
-     * The default is <code>null</code> which will use the default value for the
-     * drive.
+     * Sets the value of defaultAutoCommit, which defines the state of connections handed out from this pool. The value
+     * can be changed on the Connection using Connection.setAutoCommit(boolean). The default is <code>null</code> which
+     * will use the default value for the drive.
      *
-     * @param v  Value to assign to defaultAutoCommit.
+     * @param v
+     *            Value to assign to defaultAutoCommit.
      */
     public void setDefaultAutoCommit(final Boolean v) {
         assertInitializationAllowed();
@@ -584,11 +603,9 @@
     }
 
     /**
-     * Get the value of defaultReadOnly, which defines the state of
-     * connections handed out from this pool.  The value can be changed
-     * on the Connection using Connection.setReadOnly(boolean).
-     * The default is <code>null</code> which will use the default value for the
-     * drive.
+     * Gets the value of defaultReadOnly, which defines the state of connections handed out from this pool. The value
+     * can be changed on the Connection using Connection.setReadOnly(boolean). The default is <code>null</code> which
+     * will use the default value for the drive.
      *
      * @return value of defaultReadOnly.
      */
@@ -597,13 +614,12 @@
     }
 
     /**
-     * Set the value of defaultReadOnly, which defines the state of
-     * connections handed out from this pool.  The value can be changed
-     * on the Connection using Connection.setReadOnly(boolean).
-     * The default is <code>null</code> which will use the default value for the
-     * drive.
+     * Sets the value of defaultReadOnly, which defines the state of connections handed out from this pool. The value
+     * can be changed on the Connection using Connection.setReadOnly(boolean). The default is <code>null</code> which
+     * will use the default value for the drive.
      *
-     * @param v  Value to assign to defaultReadOnly.
+     * @param v
+     *            Value to assign to defaultReadOnly.
      */
     public void setDefaultReadOnly(final Boolean v) {
         assertInitializationAllowed();
@@ -611,10 +627,9 @@
     }
 
     /**
-     * Get the value of defaultTransactionIsolation, which defines the state of
-     * connections handed out from this pool.  The value can be changed
-     * on the Connection using Connection.setTransactionIsolation(int).
-     * If this method returns -1, the default is JDBC driver dependent.
+     * Gets the value of defaultTransactionIsolation, which defines the state of connections handed out from this pool.
+     * The value can be changed on the Connection using Connection.setTransactionIsolation(int). If this method returns
+     * -1, the default is JDBC driver dependent.
      *
      * @return value of defaultTransactionIsolation.
      */
@@ -623,12 +638,12 @@
     }
 
     /**
-     * Set the value of defaultTransactionIsolation, which defines the state of
-     * connections handed out from this pool.  The value can be changed
-     * on the Connection using Connection.setTransactionIsolation(int).
-     * The default is JDBC driver dependent.
+     * Sets the value of defaultTransactionIsolation, which defines the state of connections handed out from this pool.
+     * The value can be changed on the Connection using Connection.setTransactionIsolation(int). The default is JDBC
+     * driver dependent.
      *
-     * @param v  Value to assign to defaultTransactionIsolation
+     * @param v
+     *            Value to assign to defaultTransactionIsolation
      */
     public void setDefaultTransactionIsolation(final int v) {
         assertInitializationAllowed();
@@ -646,9 +661,8 @@
     }
 
     /**
-     * Get the description.  This property is defined by JDBC as for use with
-     * GUI (or other) tools that might deploy the datasource.  It serves no
-     * internal purpose.
+     * Gets the description. This property is defined by JDBC as for use with GUI (or other) tools that might deploy the
+     * datasource. It serves no internal purpose.
      *
      * @return value of description.
      */
@@ -657,11 +671,11 @@
     }
 
     /**
-     * Set the description.  This property is defined by JDBC as for use with
-     * GUI (or other) tools that might deploy the datasource.  It serves no
-     * internal purpose.
+     * Sets the description. This property is defined by JDBC as for use with GUI (or other) tools that might deploy the
+     * datasource. It serves no internal purpose.
      *
-     * @param v  Value to assign to description.
+     * @param v
+     *            Value to assign to description.
      */
     public void setDescription(final String v) {
         this.description = v;
@@ -672,10 +686,11 @@
     }
 
     /**
-     * Get the value of jndiEnvironment which is used when instantiating
-     * a jndi InitialContext.  This InitialContext is used to locate the
-     * backend ConnectionPoolDataSource.
+     * Gets the value of jndiEnvironment which is used when instantiating a JNDI InitialContext. This InitialContext is
+     * used to locate the backend ConnectionPoolDataSource.
      *
+     * @param key
+     *            JNDI environment key.
      * @return value of jndiEnvironment.
      */
     public String getJndiEnvironment(final String key) {
@@ -687,12 +702,13 @@
     }
 
     /**
-     * Sets the value of the given JNDI environment property to be used when
-     * instantiating a JNDI InitialContext. This InitialContext is used to
-     * locate the backend ConnectionPoolDataSource.
+     * Sets the value of the given JNDI environment property to be used when instantiating a JNDI InitialContext. This
+     * InitialContext is used to locate the backend ConnectionPoolDataSource.
      *
-     * @param key the JNDI environment property to set.
-     * @param value the value assigned to specified JNDI environment property.
+     * @param key
+     *            the JNDI environment property to set.
+     * @param value
+     *            the value assigned to specified JNDI environment property.
      */
     public void setJndiEnvironment(final String key, final String value) {
         if (jndiEnvironment == null) {
@@ -702,12 +718,11 @@
     }
 
     /**
-     * Sets the JNDI environment to be used when instantiating a JNDI
-     * InitialContext. This InitialContext is used to locate the backend
-     * ConnectionPoolDataSource.
+     * Sets the JNDI environment to be used when instantiating a JNDI InitialContext. This InitialContext is used to
+     * locate the backend ConnectionPoolDataSource.
      *
-     * @param properties the JNDI environment property to set which will
-     *                   overwrite any current settings
+     * @param properties
+     *            the JNDI environment property to set which will overwrite any current settings
      */
     void setJndiEnvironment(final Properties properties) {
         if (jndiEnvironment == null) {
@@ -719,7 +734,8 @@
     }
 
     /**
-     * Get the value of loginTimeout.
+     * Gets the value of loginTimeout.
+     *
      * @return value of loginTimeout.
      */
     @Override
@@ -728,8 +744,10 @@
     }
 
     /**
-     * Set the value of loginTimeout.
-     * @param v  Value to assign to loginTimeout.
+     * Sets the value of loginTimeout.
+     *
+     * @param v
+     *            Value to assign to loginTimeout.
      */
     @Override
     public void setLoginTimeout(final int v) {
@@ -737,21 +755,23 @@
     }
 
     /**
-     * Get the value of logWriter.
+     * Gets the value of logWriter.
+     *
      * @return value of logWriter.
      */
     @Override
     public PrintWriter getLogWriter() {
         if (logWriter == null) {
-            logWriter = new PrintWriter(
-                    new OutputStreamWriter(System.out, StandardCharsets.UTF_8));
+            logWriter = new PrintWriter(new OutputStreamWriter(System.out, StandardCharsets.UTF_8));
         }
         return logWriter;
     }
 
     /**
-     * Set the value of logWriter.
-     * @param v  Value to assign to logWriter.
+     * Sets the value of logWriter.
+     *
+     * @param v
+     *            Value to assign to logWriter.
      */
     @Override
     public void setLogWriter(final PrintWriter v) {
@@ -759,22 +779,25 @@
     }
 
     /**
-     * The SQL query that will be used to validate connections from this pool
-     * before returning them to the caller.  If specified, this query
-     * <strong>MUST</strong> be an SQL SELECT statement that returns at least
-     * one row. If not specified, {@link Connection#isValid(int)} will be used
-     * to validate connections.
+     * Gets the SQL query that will be used to validate connections from this pool before returning them to the caller.
+     * If specified, this query <strong>MUST</strong> be an SQL SELECT statement that returns at least one row. If not
+     * specified, {@link Connection#isValid(int)} will be used to validate connections.
+     *
+     * @return The SQL query that will be used to validate connections from this pool before returning them to the
+     *         caller.
      */
     public String getValidationQuery() {
         return this.validationQuery;
     }
 
     /**
-     * The SQL query that will be used to validate connections from this pool
-     * before returning them to the caller.  If specified, this query
-     * <strong>MUST</strong> be an SQL SELECT statement that returns at least
-     * one row. If not specified, connections will be validated using
-     * {@link Connection#isValid(int)}.
+     * Sets the SQL query that will be used to validate connections from this pool before returning them to the caller.
+     * If specified, this query <strong>MUST</strong> be an SQL SELECT statement that returns at least one row. If not
+     * specified, connections will be validated using {@link Connection#isValid(int)}.
+     *
+     * @param validationQuery
+     *            The SQL query that will be used to validate connections from this pool before returning them to the
+     *            caller.
      */
     public void setValidationQuery(final String validationQuery) {
         assertInitializationAllowed();
@@ -783,40 +806,40 @@
 
     /**
      * Returns the timeout in seconds before the validation query fails.
+     *
+     * @return The timeout in seconds before the validation query fails.
      */
     public int getValidationQueryTimeout() {
-        return validationQueryTimeout;
+        return validationQueryTimeoutSeconds;
     }
 
     /**
      * Sets the timeout in seconds before the validation query fails.
      *
-     * @param validationQueryTimeout    The new timeout in seconds
+     * @param validationQueryTimeoutSeconds
+     *            The new timeout in seconds
      */
-    public void setValidationQueryTimeout(final int validationQueryTimeout) {
-        this.validationQueryTimeout = validationQueryTimeout;
+    public void setValidationQueryTimeout(final int validationQueryTimeoutSeconds) {
+        this.validationQueryTimeoutSeconds = validationQueryTimeoutSeconds;
     }
 
     /**
-     * Whether a rollback will be issued after executing the SQL query
-     * that will be used to validate connections from this pool
-     * before returning them to the caller.
+     * Whether a rollback will be issued after executing the SQL query that will be used to validate connections from
+     * this pool before returning them to the caller.
      *
-     * @return true if a rollback will be issued after executing the
-     * validation query
+     * @return true if a rollback will be issued after executing the validation query
      */
     public boolean isRollbackAfterValidation() {
         return this.rollbackAfterValidation;
     }
 
     /**
-     * Whether a rollback will be issued after executing the SQL query
-     * that will be used to validate connections from this pool
-     * before returning them to the caller. Default behavior is NOT
-     * to issue a rollback. The setting will only have an effect
-     * if a validation query is set
+     * Whether a rollback will be issued after executing the SQL query that will be used to validate connections from
+     * this pool before returning them to the caller. Default behavior is NOT to issue a rollback. The setting will only
+     * have an effect if a validation query is set
      *
-     * @param rollbackAfterValidation new property value
+     * @param rollbackAfterValidation
+     *            new property value
      */
     public void setRollbackAfterValidation(final boolean rollbackAfterValidation) {
         assertInitializationAllowed();
@@ -824,21 +847,30 @@
     }
 
     /**
-     * Returns the maximum permitted lifetime of a connection in milliseconds. A
-     * value of zero or less indicates an infinite lifetime.
+     * Returns the maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an
+     * infinite lifetime.
+     *
+     * @return The maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an
+     *         infinite lifetime.
      */
     public long getMaxConnLifetimeMillis() {
         return maxConnLifetimeMillis;
     }
 
     /**
-     * <p>Sets the maximum permitted lifetime of a connection in
-     * milliseconds. A value of zero or less indicates an infinite lifetime.</p>
      * <p>
-     * Note: this method currently has no effect once the pool has been
-     * initialized.  The pool is initialized the first time one of the
-     * following methods is invoked: <code>getConnection, setLogwriter,
-     * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
+     * Sets the maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an
+     * infinite lifetime.
+     * </p>
+     * <p>
+     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
+     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+     * </p>
+     *
+     * @param maxConnLifetimeMillis
+     *            The maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an
+     *            infinite lifetime.
      */
     public void setMaxConnLifetimeMillis(final long maxConnLifetimeMillis) {
         this.maxConnLifetimeMillis = maxConnLifetimeMillis;
@@ -851,7 +883,7 @@
     // DataSource implementation
 
     /**
-     * Attempt to establish a database connection.
+     * Attempts to establish a database connection.
      */
     @Override
     public Connection getConnection() throws SQLException {
@@ -859,29 +891,26 @@
     }
 
     /**
-     * Attempt to retrieve a database connection using {@link #getPooledConnectionAndInfo(String, String)}
-     * with the provided username and password.  The password on the {@link PooledConnectionAndInfo}
-     * instance returned by <code>getPooledConnectionAndInfo</code> is compared to the <code>password</code>
-     * parameter.  If the comparison fails, a database connection using the supplied username and password
-     * is attempted.  If the connection attempt fails, an SQLException is thrown, indicating that the given password
-     * did not match the password used to create the pooled connection.  If the connection attempt succeeds, this
-     * means that the database password has been changed.  In this case, the <code>PooledConnectionAndInfo</code>
-     * instance retrieved with the old password is destroyed and the <code>getPooledConnectionAndInfo</code> is
-     * repeatedly invoked until a <code>PooledConnectionAndInfo</code> instance with the new password is returned.
-     *
+     * Attempts to retrieve a database connection using {@link #getPooledConnectionAndInfo(String, String)} with the
+     * provided user name and password. The password on the {@link PooledConnectionAndInfo} instance returned by
+     * <code>getPooledConnectionAndInfo</code> is compared to the <code>password</code> parameter. If the comparison
+     * fails, a database connection using the supplied user name and password is attempted. If the connection attempt
+     * fails, an SQLException is thrown, indicating that the given password did not match the password used to create
+     * the pooled connection. If the connection attempt succeeds, this means that the database password has been
+     * changed. In this case, the <code>PooledConnectionAndInfo</code> instance retrieved with the old password is
+     * destroyed and the <code>getPooledConnectionAndInfo</code> is repeatedly invoked until a
+     * <code>PooledConnectionAndInfo</code> instance with the new password is returned.
      */
     @Override
-    public Connection getConnection(final String username, final String password)
-            throws SQLException {
+    public Connection getConnection(final String userName, final String userPassword) throws SQLException {
         if (instanceKey == null) {
             throw new SQLException("Must set the ConnectionPoolDataSource "
-                    + "through setDataSourceName or setConnectionPoolDataSource"
-                    + " before calling getConnection.");
+                    + "through setDataSourceName or setConnectionPoolDataSource" + " before calling getConnection.");
         }
         getConnectionCalled = true;
         PooledConnectionAndInfo info = null;
         try {
-            info = getPooledConnectionAndInfo(username, password);
+            info = getPooledConnectionAndInfo(userName, userPassword);
         } catch (final NoSuchElementException e) {
             closeDueToException(info);
             throw new SQLException("Cannot borrow connection from pool", e);
@@ -896,18 +925,17 @@
             throw new SQLException("Cannot borrow connection from pool", e);
         }
 
-        if (!(null == password ? null == info.getPassword()
-                : password.equals(info.getPassword()))) {  // Password on PooledConnectionAndInfo does not match
+        // Password on PooledConnectionAndInfo does not match
+        if (!(null == userPassword ? null == info.getPassword() : userPassword.equals(info.getPassword()))) {
             try { // See if password has changed by attempting connection
-                testCPDS(username, password);
+                testCPDS(userName, userPassword);
             } catch (final SQLException ex) {
                 // Password has not changed, so refuse client, but return connection to the pool
                 closeDueToException(info);
-                throw new SQLException("Given password did not match password used"
-                                       + " to create the PooledConnection.", ex);
-            } catch (final javax.naming.NamingException ne) {
                 throw new SQLException(
-                        "NamingException encountered connecting to database", ne);
+                        "Given password did not match password used" + " to create the PooledConnection.", ex);
+            } catch (final javax.naming.NamingException ne) {
+                throw new SQLException("NamingException encountered connecting to database", ne);
             }
             /*
              * Password must have changed -> destroy connection and keep retrying until we get a new, good one,
@@ -915,12 +943,14 @@
              */
             final UserPassKey upkey = info.getUserPassKey();
             final PooledConnectionManager manager = getConnectionManager(upkey);
-            manager.invalidate(info.getPooledConnection()); // Destroy and remove from pool
-            manager.setPassword(upkey.getPassword()); // Reset the password on the factory if using CPDSConnectionFactory
+            // Destroy and remove from pool
+            manager.invalidate(info.getPooledConnection());
+            // Reset the password on the factory if using CPDSConnectionFactory
+            manager.setPassword(upkey.getPassword());
             info = null;
             for (int i = 0; i < 10; i++) { // Bound the number of retries - only needed if bad instances return
                 try {
-                    info = getPooledConnectionAndInfo(username, password);
+                    info = getPooledConnectionAndInfo(userName, userPassword);
                 } catch (final NoSuchElementException e) {
                     closeDueToException(info);
                     throw new SQLException("Cannot borrow connection from pool", e);
@@ -934,7 +964,7 @@
                     closeDueToException(info);
                     throw new SQLException("Cannot borrow connection from pool", e);
                 }
-                if (info != null && password != null && password.equals(info.getPassword())) {
+                if (info != null && userPassword != null && userPassword.equals(info.getPassword())) {
                     break;
                 }
                 if (info != null) {
@@ -949,27 +979,23 @@
 
         final Connection con = info.getPooledConnection().getConnection();
         try {
-            setupDefaults(con, username);
+            setupDefaults(con, userName);
             con.clearWarnings();
             return con;
         } catch (final SQLException ex) {
             try {
                 con.close();
             } catch (final Exception exc) {
-                getLogWriter().println(
-                     "ignoring exception during close: " + exc);
+                getLogWriter().println("ignoring exception during close: " + exc);
             }
             throw ex;
         }
     }
 
-    protected abstract PooledConnectionAndInfo
-        getPooledConnectionAndInfo(String username, String password)
-        throws SQLException;
+    protected abstract PooledConnectionAndInfo getPooledConnectionAndInfo(String userName, String userPassword)
+            throws SQLException;
 
-    protected abstract void setupDefaults(Connection con, String username)
-        throws SQLException;
-
+    protected abstract void setupDefaults(Connection connection, String userName) throws SQLException;
 
     private void closeDueToException(final PooledConnectionAndInfo info) {
         if (info != null) {
@@ -977,17 +1003,16 @@
                 info.getPooledConnection().getConnection().close();
             } catch (final Exception e) {
                 // do not throw this exception because we are in the middle
-                // of handling another exception.  But record it because
+                // of handling another exception. But record it because
                 // it potentially leaks connections from the pool.
-                getLogWriter().println("[ERROR] Could not return connection to "
-                    + "pool during exception handling. " + e.getMessage());
+                getLogWriter().println("[ERROR] Could not return connection to " + "pool during exception handling. "
+                        + e.getMessage());
             }
         }
     }
 
-    protected ConnectionPoolDataSource
-        testCPDS(final String username, final String password)
-        throws javax.naming.NamingException, SQLException {
+    protected ConnectionPoolDataSource testCPDS(final String userName, final String userPassword)
+            throws javax.naming.NamingException, SQLException {
         // The source of physical db connections
         ConnectionPoolDataSource cpds = this.dataSource;
         if (cpds == null) {
@@ -1001,33 +1026,27 @@
             if (ds instanceof ConnectionPoolDataSource) {
                 cpds = (ConnectionPoolDataSource) ds;
             } else {
-                throw new SQLException("Illegal configuration: "
-                    + "DataSource " + dataSourceName
-                    + " (" + ds.getClass().getName() + ")"
-                    + " doesn't implement javax.sql.ConnectionPoolDataSource");
+                throw new SQLException("Illegal configuration: " + "DataSource " + dataSourceName + " ("
+                        + ds.getClass().getName() + ")" + " doesn't implement javax.sql.ConnectionPoolDataSource");
             }
         }
 
-        // try to get a connection with the supplied username/password
+        // try to get a connection with the supplied userName/password
         PooledConnection conn = null;
         try {
-            if (username != null) {
-                conn = cpds.getPooledConnection(username, password);
-            }
-            else {
+            if (userName != null) {
+                conn = cpds.getPooledConnection(userName, userPassword);
+            } else {
                 conn = cpds.getPooledConnection();
             }
             if (conn == null) {
-                throw new SQLException(
-                    "Cannot connect using the supplied username/password");
+                throw new SQLException("Cannot connect using the supplied userName/password");
             }
-        }
-        finally {
+        } finally {
             if (conn != null) {
                 try {
                     conn.close();
-                }
-                catch (final SQLException e) {
+                } catch (final SQLException e) {
                     // at least we could connect
                 }
             }
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSourceFactory.java b/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSourceFactory.java
index 99194be..1c60838 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSourceFactory.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSourceFactory.java
@@ -19,8 +19,10 @@
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.ObjectInputStream;
+import java.util.ArrayList;
 import java.util.Hashtable;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Properties;
@@ -32,22 +34,22 @@
 import javax.naming.Reference;
 import javax.naming.spi.ObjectFactory;
 
+import org.apache.tomcat.dbcp.dbcp2.ListException;
+
 /**
- * A JNDI ObjectFactory which creates <code>SharedPoolDataSource</code>s
- * or <code>PerUserPoolDataSource</code>s
+ * A JNDI ObjectFactory which creates <code>SharedPoolDataSource</code>s or <code>PerUserPoolDataSource</code>s
  *
  * @since 2.0
  */
 abstract class InstanceKeyDataSourceFactory implements ObjectFactory {
 
-    private static final Map<String, InstanceKeyDataSource> instanceMap =
-            new ConcurrentHashMap<>();
+    private static final Map<String, InstanceKeyDataSource> instanceMap = new ConcurrentHashMap<>();
 
     static synchronized String registerNewInstance(final InstanceKeyDataSource ds) {
         int max = 0;
-        final Iterator<String> i = instanceMap.keySet().iterator();
-        while (i.hasNext()) {
-            final String s = i.next();
+        final Iterator<String> iterator = instanceMap.keySet().iterator();
+        while (iterator.hasNext()) {
+            final String s = iterator.next();
             if (s != null) {
                 try {
                     max = Math.max(max, Integer.parseInt(s));
@@ -57,8 +59,8 @@
             }
         }
         final String instanceKey = String.valueOf(max + 1);
-        // put a placeholder here for now, so other instances will not
-        // take our key.  we will replace with a pool when ready.
+        // Put a placeholder here for now, so other instances will not
+        // take our key. We will replace with a pool when ready.
         instanceMap.put(instanceKey, ds);
         return instanceKey;
     }
@@ -70,56 +72,70 @@
     }
 
     /**
-     * Close all pools associated with this class.
+     * Closes all pools associated with this class.
+     *
+     * @throws Exception
+     *             a {@link ListException} containing all exceptions thrown by {@link InstanceKeyDataSource#close()}
+     * @see InstanceKeyDataSource#close()
+     * @see ListException
+     * @since 2.4.0 throws a {@link ListException} instead of, in 2.3.0 and before, the first exception thrown by
+     *        {@link InstanceKeyDataSource#close()}.
      */
     public static void closeAll() throws Exception {
-        //Get iterator to loop over all instances of this datasource.
-        final Iterator<Entry<String,InstanceKeyDataSource>> instanceIterator =
-            instanceMap.entrySet().iterator();
+        // Get iterator to loop over all instances of this data source.
+        final List<Throwable> exceptionList = new ArrayList<>(instanceMap.size());
+        final Iterator<Entry<String, InstanceKeyDataSource>> instanceIterator = instanceMap.entrySet().iterator();
         while (instanceIterator.hasNext()) {
-            instanceIterator.next().getValue().close();
+            // Bullet-proof to avoid anything else but problems from InstanceKeyDataSource#close().
+            final Entry<String, InstanceKeyDataSource> next = instanceIterator.next();
+            if (next != null) {
+                @SuppressWarnings("resource")
+                final InstanceKeyDataSource value = next.getValue();
+                if (value != null) {
+                    try {
+                        value.close();
+                    } catch (final Exception e) {
+                        exceptionList.add(e);
+                    }
+                }
+            }
         }
         instanceMap.clear();
+        if (!exceptionList.isEmpty()) {
+            throw new ListException("Could not close all InstanceKeyDataSource instances.", exceptionList);
+        }
     }
 
-
     /**
-     * implements ObjectFactory to create an instance of SharedPoolDataSource
-     * or PerUserPoolDataSource
+     * Implements ObjectFactory to create an instance of SharedPoolDataSource or PerUserPoolDataSource
      */
     @Override
-    public Object getObjectInstance(final Object refObj, final Name name,
-                                    final Context context, final Hashtable<?,?> env)
-        throws IOException, ClassNotFoundException {
+    public Object getObjectInstance(final Object refObj, final Name name, final Context context,
+            final Hashtable<?, ?> env) throws IOException, ClassNotFoundException {
         // The spec says to return null if we can't create an instance
         // of the reference
         Object obj = null;
         if (refObj instanceof Reference) {
             final Reference ref = (Reference) refObj;
             if (isCorrectClass(ref.getClassName())) {
-                final RefAddr ra = ref.get("instanceKey");
-                if (ra != null && ra.getContent() != null) {
+                final RefAddr refAddr = ref.get("instanceKey");
+                if (refAddr != null && refAddr.getContent() != null) {
                     // object was bound to jndi via Referenceable api.
-                    obj = instanceMap.get(ra.getContent());
-                }
-                else
-                {
-                    // tomcat jndi creates a Reference out of server.xml
+                    obj = instanceMap.get(refAddr.getContent());
+                } else {
+                    // Tomcat JNDI creates a Reference out of server.xml
                     // <ResourceParam> configuration and passes it to an
                     // instance of the factory given in server.xml.
                     String key = null;
-                    if (name != null)
-                    {
+                    if (name != null) {
                         key = name.toString();
                         obj = instanceMap.get(key);
                     }
-                    if (obj == null)
-                    {
+                    if (obj == null) {
                         final InstanceKeyDataSource ds = getNewInstance(ref);
                         setCommonProperties(ref, ds);
                         obj = ds;
-                        if (key != null)
-                        {
+                        if (key != null) {
                             instanceMap.put(key, ds);
                         }
                     }
@@ -129,188 +145,161 @@
         return obj;
     }
 
-    private void setCommonProperties(final Reference ref,
-                                     final InstanceKeyDataSource ikds)
-        throws IOException, ClassNotFoundException {
+    private void setCommonProperties(final Reference ref, final InstanceKeyDataSource ikds)
+            throws IOException, ClassNotFoundException {
 
-        RefAddr ra = ref.get("dataSourceName");
-        if (ra != null && ra.getContent() != null) {
-            ikds.setDataSourceName(ra.getContent().toString());
+        RefAddr refAddr = ref.get("dataSourceName");
+        if (refAddr != null && refAddr.getContent() != null) {
+            ikds.setDataSourceName(refAddr.getContent().toString());
         }
 
-        ra = ref.get("description");
-        if (ra != null && ra.getContent() != null) {
-            ikds.setDescription(ra.getContent().toString());
+        refAddr = ref.get("description");
+        if (refAddr != null && refAddr.getContent() != null) {
+            ikds.setDescription(refAddr.getContent().toString());
         }
 
-        ra = ref.get("jndiEnvironment");
-        if (ra != null  && ra.getContent() != null) {
-            final byte[] serialized = (byte[]) ra.getContent();
+        refAddr = ref.get("jndiEnvironment");
+        if (refAddr != null && refAddr.getContent() != null) {
+            final byte[] serialized = (byte[]) refAddr.getContent();
             ikds.setJndiEnvironment((Properties) deserialize(serialized));
         }
 
-        ra = ref.get("loginTimeout");
-        if (ra != null && ra.getContent() != null) {
-            ikds.setLoginTimeout(
-                Integer.parseInt(ra.getContent().toString()));
+        refAddr = ref.get("loginTimeout");
+        if (refAddr != null && refAddr.getContent() != null) {
+            ikds.setLoginTimeout(Integer.parseInt(refAddr.getContent().toString()));
         }
 
         // Pool properties
-        ra = ref.get("blockWhenExhausted");
-        if (ra != null && ra.getContent() != null) {
-            ikds.setDefaultBlockWhenExhausted(Boolean.valueOf(
-                ra.getContent().toString()).booleanValue());
+        refAddr = ref.get("blockWhenExhausted");
+        if (refAddr != null && refAddr.getContent() != null) {
+            ikds.setDefaultBlockWhenExhausted(Boolean.valueOf(refAddr.getContent().toString()).booleanValue());
         }
 
-        ra = ref.get("evictionPolicyClassName");
-        if (ra != null && ra.getContent() != null) {
-            ikds.setDefaultEvictionPolicyClassName(ra.getContent().toString());
+        refAddr = ref.get("evictionPolicyClassName");
+        if (refAddr != null && refAddr.getContent() != null) {
+            ikds.setDefaultEvictionPolicyClassName(refAddr.getContent().toString());
         }
 
         // Pool properties
-        ra = ref.get("lifo");
-        if (ra != null && ra.getContent() != null) {
-            ikds.setDefaultLifo(Boolean.valueOf(
-                ra.getContent().toString()).booleanValue());
+        refAddr = ref.get("lifo");
+        if (refAddr != null && refAddr.getContent() != null) {
+            ikds.setDefaultLifo(Boolean.valueOf(refAddr.getContent().toString()).booleanValue());
         }
 
-        ra = ref.get("maxIdlePerKey");
-        if (ra != null && ra.getContent() != null) {
-            ikds.setDefaultMaxIdle(
-                Integer.parseInt(ra.getContent().toString()));
+        refAddr = ref.get("maxIdlePerKey");
+        if (refAddr != null && refAddr.getContent() != null) {
+            ikds.setDefaultMaxIdle(Integer.parseInt(refAddr.getContent().toString()));
         }
 
-        ra = ref.get("maxTotalPerKey");
-        if (ra != null && ra.getContent() != null) {
-            ikds.setDefaultMaxTotal(
-                Integer.parseInt(ra.getContent().toString()));
+        refAddr = ref.get("maxTotalPerKey");
+        if (refAddr != null && refAddr.getContent() != null) {
+            ikds.setDefaultMaxTotal(Integer.parseInt(refAddr.getContent().toString()));
         }
 
-        ra = ref.get("maxWaitMillis");
-        if (ra != null && ra.getContent() != null) {
-            ikds.setDefaultMaxWaitMillis(
-                Long.parseLong(ra.getContent().toString()));
+        refAddr = ref.get("maxWaitMillis");
+        if (refAddr != null && refAddr.getContent() != null) {
+            ikds.setDefaultMaxWaitMillis(Long.parseLong(refAddr.getContent().toString()));
         }
 
-        ra = ref.get("minEvictableIdleTimeMillis");
-        if (ra != null && ra.getContent() != null) {
-            ikds.setDefaultMinEvictableIdleTimeMillis(
-                Long.parseLong(ra.getContent().toString()));
+        refAddr = ref.get("minEvictableIdleTimeMillis");
+        if (refAddr != null && refAddr.getContent() != null) {
+            ikds.setDefaultMinEvictableIdleTimeMillis(Long.parseLong(refAddr.getContent().toString()));
         }
 
-        ra = ref.get("minIdlePerKey");
-        if (ra != null && ra.getContent() != null) {
-            ikds.setDefaultMinIdle(
-                Integer.parseInt(ra.getContent().toString()));
+        refAddr = ref.get("minIdlePerKey");
+        if (refAddr != null && refAddr.getContent() != null) {
+            ikds.setDefaultMinIdle(Integer.parseInt(refAddr.getContent().toString()));
         }
 
-        ra = ref.get("numTestsPerEvictionRun");
-        if (ra != null && ra.getContent() != null) {
-            ikds.setDefaultNumTestsPerEvictionRun(
-                Integer.parseInt(ra.getContent().toString()));
+        refAddr = ref.get("numTestsPerEvictionRun");
+        if (refAddr != null && refAddr.getContent() != null) {
+            ikds.setDefaultNumTestsPerEvictionRun(Integer.parseInt(refAddr.getContent().toString()));
         }
 
-        ra = ref.get("softMinEvictableIdleTimeMillis");
-        if (ra != null && ra.getContent() != null) {
-            ikds.setDefaultSoftMinEvictableIdleTimeMillis(
-                Long.parseLong(ra.getContent().toString()));
+        refAddr = ref.get("softMinEvictableIdleTimeMillis");
+        if (refAddr != null && refAddr.getContent() != null) {
+            ikds.setDefaultSoftMinEvictableIdleTimeMillis(Long.parseLong(refAddr.getContent().toString()));
         }
 
-        ra = ref.get("testOnCreate");
-        if (ra != null && ra.getContent() != null) {
-            ikds.setDefaultTestOnCreate(Boolean.valueOf(
-                ra.getContent().toString()).booleanValue());
+        refAddr = ref.get("testOnCreate");
+        if (refAddr != null && refAddr.getContent() != null) {
+            ikds.setDefaultTestOnCreate(Boolean.valueOf(refAddr.getContent().toString()).booleanValue());
         }
 
-        ra = ref.get("testOnBorrow");
-        if (ra != null && ra.getContent() != null) {
-            ikds.setDefaultTestOnBorrow(Boolean.valueOf(
-                ra.getContent().toString()).booleanValue());
+        refAddr = ref.get("testOnBorrow");
+        if (refAddr != null && refAddr.getContent() != null) {
+            ikds.setDefaultTestOnBorrow(Boolean.valueOf(refAddr.getContent().toString()).booleanValue());
         }
 
-        ra = ref.get("testOnReturn");
-        if (ra != null && ra.getContent() != null) {
-            ikds.setDefaultTestOnReturn(Boolean.valueOf(
-                ra.getContent().toString()).booleanValue());
+        refAddr = ref.get("testOnReturn");
+        if (refAddr != null && refAddr.getContent() != null) {
+            ikds.setDefaultTestOnReturn(Boolean.valueOf(refAddr.getContent().toString()).booleanValue());
         }
 
-        ra = ref.get("testWhileIdle");
-        if (ra != null && ra.getContent() != null) {
-            ikds.setDefaultTestWhileIdle(Boolean.valueOf(
-                ra.getContent().toString()).booleanValue());
+        refAddr = ref.get("testWhileIdle");
+        if (refAddr != null && refAddr.getContent() != null) {
+            ikds.setDefaultTestWhileIdle(Boolean.valueOf(refAddr.getContent().toString()).booleanValue());
         }
 
-        ra = ref.get("timeBetweenEvictionRunsMillis");
-        if (ra != null && ra.getContent() != null) {
-            ikds.setDefaultTimeBetweenEvictionRunsMillis(
-                Long.parseLong(ra.getContent().toString()));
+        refAddr = ref.get("timeBetweenEvictionRunsMillis");
+        if (refAddr != null && refAddr.getContent() != null) {
+            ikds.setDefaultTimeBetweenEvictionRunsMillis(Long.parseLong(refAddr.getContent().toString()));
         }
 
-
         // Connection factory properties
 
-        ra = ref.get("validationQuery");
-        if (ra != null && ra.getContent() != null) {
-            ikds.setValidationQuery(ra.getContent().toString());
+        refAddr = ref.get("validationQuery");
+        if (refAddr != null && refAddr.getContent() != null) {
+            ikds.setValidationQuery(refAddr.getContent().toString());
         }
 
-        ra = ref.get("validationQueryTimeout");
-        if (ra != null && ra.getContent() != null) {
-            ikds.setValidationQueryTimeout(Integer.parseInt(
-                    ra.getContent().toString()));
+        refAddr = ref.get("validationQueryTimeout");
+        if (refAddr != null && refAddr.getContent() != null) {
+            ikds.setValidationQueryTimeout(Integer.parseInt(refAddr.getContent().toString()));
         }
 
-        ra = ref.get("rollbackAfterValidation");
-        if (ra != null && ra.getContent() != null) {
-            ikds.setRollbackAfterValidation(Boolean.valueOf(
-                ra.getContent().toString()).booleanValue());
+        refAddr = ref.get("rollbackAfterValidation");
+        if (refAddr != null && refAddr.getContent() != null) {
+            ikds.setRollbackAfterValidation(Boolean.valueOf(refAddr.getContent().toString()).booleanValue());
         }
 
-        ra = ref.get("maxConnLifetimeMillis");
-        if (ra != null && ra.getContent() != null) {
-            ikds.setMaxConnLifetimeMillis(
-                Long.parseLong(ra.getContent().toString()));
+        refAddr = ref.get("maxConnLifetimeMillis");
+        if (refAddr != null && refAddr.getContent() != null) {
+            ikds.setMaxConnLifetimeMillis(Long.parseLong(refAddr.getContent().toString()));
         }
 
-
         // Connection properties
 
-        ra = ref.get("defaultAutoCommit");
-        if (ra != null && ra.getContent() != null) {
-            ikds.setDefaultAutoCommit(Boolean.valueOf(ra.getContent().toString()));
+        refAddr = ref.get("defaultAutoCommit");
+        if (refAddr != null && refAddr.getContent() != null) {
+            ikds.setDefaultAutoCommit(Boolean.valueOf(refAddr.getContent().toString()));
         }
 
-        ra = ref.get("defaultTransactionIsolation");
-        if (ra != null && ra.getContent() != null) {
-            ikds.setDefaultTransactionIsolation(
-                Integer.parseInt(ra.getContent().toString()));
+        refAddr = ref.get("defaultTransactionIsolation");
+        if (refAddr != null && refAddr.getContent() != null) {
+            ikds.setDefaultTransactionIsolation(Integer.parseInt(refAddr.getContent().toString()));
         }
 
-        ra = ref.get("defaultReadOnly");
-        if (ra != null && ra.getContent() != null) {
-            ikds.setDefaultReadOnly(Boolean.valueOf(ra.getContent().toString()));
+        refAddr = ref.get("defaultReadOnly");
+        if (refAddr != null && refAddr.getContent() != null) {
+            ikds.setDefaultReadOnly(Boolean.valueOf(refAddr.getContent().toString()));
         }
     }
 
-
     /**
-     * @return true if and only if className is the value returned
-     * from getClass().getName().toString()
+     * @return true if and only if className is the value returned from getClass().getName().toString()
      */
     protected abstract boolean isCorrectClass(String className);
 
     /**
-     * Creates an instance of the subclass and sets any properties
-     * contained in the Reference.
+     * Creates an instance of the subclass and sets any properties contained in the Reference.
      */
-    protected abstract InstanceKeyDataSource getNewInstance(Reference ref)
-        throws IOException, ClassNotFoundException;
+    protected abstract InstanceKeyDataSource getNewInstance(Reference ref) throws IOException, ClassNotFoundException;
 
     /**
-     * used to set some properties saved within a Reference
+     * Sets some properties saved within a Reference
      */
-    protected static final Object deserialize(final byte[] data)
-        throws IOException, ClassNotFoundException {
+    protected static final Object deserialize(final byte[] data) throws IOException, ClassNotFoundException {
         ObjectInputStream in = null;
         try {
             in = new ObjectInputStream(new ByteArrayInputStream(data));
@@ -320,9 +309,9 @@
                 try {
                     in.close();
                 } catch (final IOException ex) {
+                    // ignore
                 }
             }
         }
     }
 }
-
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/datasources/KeyedCPDSConnectionFactory.java b/java/org/apache/tomcat/dbcp/dbcp2/datasources/KeyedCPDSConnectionFactory.java
index 5eec558..3f15b79 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/datasources/KeyedCPDSConnectionFactory.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/datasources/KeyedCPDSConnectionFactory.java
@@ -38,64 +38,59 @@
 import org.apache.tomcat.dbcp.pool2.impl.DefaultPooledObject;
 
 /**
- * A {@link KeyedPooledObjectFactory} that creates
- * {@link org.apache.tomcat.dbcp.dbcp2.PoolableConnection PoolableConnection}s.
+ * A {@link KeyedPooledObjectFactory} that creates {@link org.apache.tomcat.dbcp.dbcp2.PoolableConnection
+ * PoolableConnection}s.
  *
- * @author John D. McNally
  * @since 2.0
  */
-class KeyedCPDSConnectionFactory
-    implements KeyedPooledObjectFactory<UserPassKey,PooledConnectionAndInfo>,
-    ConnectionEventListener, PooledConnectionManager {
+class KeyedCPDSConnectionFactory implements KeyedPooledObjectFactory<UserPassKey, PooledConnectionAndInfo>,
+        ConnectionEventListener, PooledConnectionManager {
 
-    private static final String NO_KEY_MESSAGE
-            = "close() was called on a Connection, but "
+    private static final String NO_KEY_MESSAGE = "close() was called on a Connection, but "
             + "I have no record of the underlying PooledConnection.";
 
-    private final ConnectionPoolDataSource _cpds;
-    private final String _validationQuery;
-    private final int _validationQueryTimeout;
-    private final boolean _rollbackAfterValidation;
-    private KeyedObjectPool<UserPassKey,PooledConnectionAndInfo> _pool;
+    private final ConnectionPoolDataSource cpds;
+    private final String validationQuery;
+    private final int validationQueryTimeoutSeconds;
+    private final boolean rollbackAfterValidation;
+    private KeyedObjectPool<UserPassKey, PooledConnectionAndInfo> pool;
     private long maxConnLifetimeMillis = -1;
 
     /**
-     * Map of PooledConnections for which close events are ignored.
-     * Connections are muted when they are being validated.
+     * Map of PooledConnections for which close events are ignored. Connections are muted when they are being validated.
      */
-    private final Set<PooledConnection> validatingSet =
-            Collections.newSetFromMap(new ConcurrentHashMap<PooledConnection,Boolean>());
+    private final Set<PooledConnection> validatingSet = Collections
+            .newSetFromMap(new ConcurrentHashMap<PooledConnection, Boolean>());
 
     /**
      * Map of PooledConnectionAndInfo instances
      */
-    private final Map<PooledConnection, PooledConnectionAndInfo> pcMap =
-        new ConcurrentHashMap<>();
-
+    private final Map<PooledConnection, PooledConnectionAndInfo> pcMap = new ConcurrentHashMap<>();
 
     /**
      * Create a new {@code KeyedPoolableConnectionFactory}.
-     * @param cpds the ConnectionPoolDataSource from which to obtain
-     * PooledConnections
-     * @param validationQuery a query to use to {@link #validateObject validate}
-     * {@link Connection}s.  Should return at least one row. May be
-     * {@code null} in which case3 {@link Connection#isValid(int)} will be used
-     * to validate connections.
-     * @param rollbackAfterValidation whether a rollback should be issued after
-     * {@link #validateObject validating} {@link Connection}s.
+     *
+     * @param cpds
+     *            the ConnectionPoolDataSource from which to obtain PooledConnections
+     * @param validationQuery
+     *            a query to use to {@link #validateObject validate} {@link Connection}s. Should return at least one
+     *            row. May be {@code null} in which case3 {@link Connection#isValid(int)} will be used to validate
+     *            connections.
+     * @param validationQueryTimeoutSeconds
+     *            The time, in seconds, to allow for the validation query to complete
+     * @param rollbackAfterValidation
+     *            whether a rollback should be issued after {@link #validateObject validating} {@link Connection}s.
      */
-    public KeyedCPDSConnectionFactory(final ConnectionPoolDataSource cpds,
-                                      final String validationQuery,
-                                      final int validationQueryTimeout,
-                                      final boolean rollbackAfterValidation) {
-        _cpds = cpds;
-        _validationQuery = validationQuery;
-        _validationQueryTimeout = validationQueryTimeout;
-        _rollbackAfterValidation = rollbackAfterValidation;
+    public KeyedCPDSConnectionFactory(final ConnectionPoolDataSource cpds, final String validationQuery,
+            final int validationQueryTimeoutSeconds, final boolean rollbackAfterValidation) {
+        this.cpds = cpds;
+        this.validationQuery = validationQuery;
+        this.validationQueryTimeoutSeconds = validationQueryTimeoutSeconds;
+        this.rollbackAfterValidation = rollbackAfterValidation;
     }
 
-    public void setPool(final KeyedObjectPool<UserPassKey,PooledConnectionAndInfo> pool) {
-        this._pool = pool;
+    public void setPool(final KeyedObjectPool<UserPassKey, PooledConnectionAndInfo> pool) {
+        this.pool = pool;
     }
 
     /**
@@ -103,29 +98,30 @@
      *
      * @return KeyedObjectPool managing pooled connections
      */
-    public KeyedObjectPool<UserPassKey,PooledConnectionAndInfo> getPool() {
-        return _pool;
+    public KeyedObjectPool<UserPassKey, PooledConnectionAndInfo> getPool() {
+        return pool;
     }
 
     /**
      * Creates a new {@link PooledConnectionAndInfo} from the given {@link UserPassKey}.
      *
-     * @param upkey {@link UserPassKey} containing user credentials
-     * @throws SQLException if the connection could not be created.
+     * @param upkey
+     *            {@link UserPassKey} containing user credentials
+     * @throws SQLException
+     *             if the connection could not be created.
      * @see org.apache.tomcat.dbcp.pool2.KeyedPooledObjectFactory#makeObject(java.lang.Object)
      */
     @Override
-    public synchronized PooledObject<PooledConnectionAndInfo> makeObject(final UserPassKey upkey)
-            throws Exception {
+    public synchronized PooledObject<PooledConnectionAndInfo> makeObject(final UserPassKey upkey) throws Exception {
         PooledConnectionAndInfo pci = null;
 
         PooledConnection pc = null;
-        final String username = upkey.getUsername();
+        final String userName = upkey.getUsername();
         final String password = upkey.getPassword();
-        if (username == null) {
-            pc = _cpds.getPooledConnection();
+        if (userName == null) {
+            pc = cpds.getPooledConnection();
         } else {
-            pc = _cpds.getPooledConnection(username, password);
+            pc = cpds.getPooledConnection(userName, password);
         }
 
         if (pc == null) {
@@ -135,7 +131,7 @@
         // should we add this object as a listener or the pool.
         // consider the validateObject method in decision
         pc.addConnectionEventListener(this);
-        pci = new PooledConnectionAndInfo(pc, username, password);
+        pci = new PooledConnectionAndInfo(pc, userName, upkey.getPasswordCharArray());
         pcMap.put(pc, pci);
 
         return new DefaultPooledObject<>(pci);
@@ -145,8 +141,7 @@
      * Closes the PooledConnection and stops listening for events from it.
      */
     @Override
-    public void destroyObject(final UserPassKey key, final PooledObject<PooledConnectionAndInfo> p)
-            throws Exception {
+    public void destroyObject(final UserPassKey key, final PooledObject<PooledConnectionAndInfo> p) throws Exception {
         final PooledConnection pc = p.getObject().getPooledConnection();
         pc.removeConnectionEventListener(this);
         pcMap.remove(pc);
@@ -156,31 +151,31 @@
     /**
      * Validates a pooled connection.
      *
-     * @param key ignored
-     * @param p wrapped {@link PooledConnectionAndInfo} containing the
-     *          connection to validate
+     * @param key
+     *            ignored
+     * @param pooledObject
+     *            wrapped {@link PooledConnectionAndInfo} containing the connection to validate
      * @return true if validation succeeds
      */
     @Override
-    public boolean validateObject(final UserPassKey key,
-            final PooledObject<PooledConnectionAndInfo> p) {
+    public boolean validateObject(final UserPassKey key, final PooledObject<PooledConnectionAndInfo> pooledObject) {
         try {
-            validateLifetime(p);
+            validateLifetime(pooledObject);
         } catch (final Exception e) {
             return false;
         }
         boolean valid = false;
-        final PooledConnection pconn = p.getObject().getPooledConnection();
+        final PooledConnection pconn = pooledObject.getObject().getPooledConnection();
         Connection conn = null;
         validatingSet.add(pconn);
-        if (null == _validationQuery) {
-            int timeout = _validationQueryTimeout;
-            if (timeout < 0) {
-                timeout = 0;
+        if (null == validationQuery) {
+            int timeoutSeconds = validationQueryTimeoutSeconds;
+            if (timeoutSeconds < 0) {
+                timeoutSeconds = 0;
             }
             try {
                 conn = pconn.getConnection();
-                valid = conn.isValid(timeout);
+                valid = conn.isValid(timeoutSeconds);
             } catch (final SQLException e) {
                 valid = false;
             } finally {
@@ -198,16 +193,16 @@
             try {
                 conn = pconn.getConnection();
                 stmt = conn.createStatement();
-                rset = stmt.executeQuery(_validationQuery);
+                rset = stmt.executeQuery(validationQuery);
                 if (rset.next()) {
                     valid = true;
                 } else {
                     valid = false;
                 }
-                if (_rollbackAfterValidation) {
+                if (rollbackAfterValidation) {
                     conn.rollback();
                 }
-            } catch(final Exception e) {
+            } catch (final Exception e) {
                 valid = false;
             } finally {
                 Utils.closeQuietly(rset);
@@ -220,14 +215,12 @@
     }
 
     @Override
-    public void passivateObject(final UserPassKey key,
-            final PooledObject<PooledConnectionAndInfo> p) throws Exception {
+    public void passivateObject(final UserPassKey key, final PooledObject<PooledConnectionAndInfo> p) throws Exception {
         validateLifetime(p);
     }
 
     @Override
-    public void activateObject(final UserPassKey key,
-            final PooledObject<PooledConnectionAndInfo> p) throws Exception {
+    public void activateObject(final UserPassKey key, final PooledObject<PooledConnectionAndInfo> p) throws Exception {
         validateLifetime(p);
     }
 
@@ -236,14 +229,13 @@
     // ***********************************************************************
 
     /**
-     * This will be called if the Connection returned by the getConnection
-     * method came from a PooledConnection, and the user calls the close()
-     * method of this connection object. What we need to do here is to
-     * release this PooledConnection from our pool...
+     * This will be called if the Connection returned by the getConnection method came from a PooledConnection, and the
+     * user calls the close() method of this connection object. What we need to do here is to release this
+     * PooledConnection from our pool...
      */
     @Override
     public void connectionClosed(final ConnectionEvent event) {
-        final PooledConnection pc = (PooledConnection)event.getSource();
+        final PooledConnection pc = (PooledConnection) event.getSource();
         // if this event occurred because we were validating, or if this
         // connection has been marked for removal, ignore it
         // otherwise return the connection to the pool.
@@ -253,16 +245,14 @@
                 throw new IllegalStateException(NO_KEY_MESSAGE);
             }
             try {
-                _pool.returnObject(pci.getUserPassKey(), pci);
+                pool.returnObject(pci.getUserPassKey(), pci);
             } catch (final Exception e) {
-                System.err.println("CLOSING DOWN CONNECTION AS IT COULD " +
-                "NOT BE RETURNED TO THE POOL");
+                System.err.println("CLOSING DOWN CONNECTION AS IT COULD " + "NOT BE RETURNED TO THE POOL");
                 pc.removeConnectionEventListener(this);
                 try {
-                    _pool.invalidateObject(pci.getUserPassKey(), pci);
+                    pool.invalidateObject(pci.getUserPassKey(), pci);
                 } catch (final Exception e3) {
-                    System.err.println("EXCEPTION WHILE DESTROYING OBJECT " +
-                            pci);
+                    System.err.println("EXCEPTION WHILE DESTROYING OBJECT " + pci);
                     e3.printStackTrace();
                 }
             }
@@ -270,16 +260,13 @@
     }
 
     /**
-     * If a fatal error occurs, close the underlying physical connection so as
-     * not to be returned in the future
+     * If a fatal error occurs, close the underlying physical connection so as not to be returned in the future
      */
     @Override
     public void connectionErrorOccurred(final ConnectionEvent event) {
-        final PooledConnection pc = (PooledConnection)event.getSource();
+        final PooledConnection pc = (PooledConnection) event.getSource();
         if (null != event.getSQLException()) {
-            System.err
-                .println("CLOSING DOWN CONNECTION DUE TO INTERNAL ERROR (" +
-                         event.getSQLException() + ")");
+            System.err.println("CLOSING DOWN CONNECTION DUE TO INTERNAL ERROR (" + event.getSQLException() + ")");
         }
         pc.removeConnectionEventListener(this);
 
@@ -288,7 +275,7 @@
             throw new IllegalStateException(NO_KEY_MESSAGE);
         }
         try {
-            _pool.invalidateObject(info.getUserPassKey(), info);
+            pool.invalidateObject(info.getUserPassKey(), info);
         } catch (final Exception e) {
             System.err.println("EXCEPTION WHILE DESTROYING OBJECT " + info);
             e.printStackTrace();
@@ -300,11 +287,10 @@
     // ***********************************************************************
 
     /**
-     * Invalidates the PooledConnection in the pool.  The KeyedCPDSConnectionFactory
-     * closes the connection and pool counters are updated appropriately.
-     * Also clears any idle instances associated with the username that was used
-     * to create the PooledConnection.  Connections associated with this user
-     * are not affected and they will not be automatically closed on return to the pool.
+     * Invalidates the PooledConnection in the pool. The KeyedCPDSConnectionFactory closes the connection and pool
+     * counters are updated appropriately. Also clears any idle instances associated with the user name that was used to
+     * create the PooledConnection. Connections associated with this user are not affected and they will not be
+     * automatically closed on return to the pool.
      */
     @Override
     public void invalidate(final PooledConnection pc) throws SQLException {
@@ -314,52 +300,50 @@
         }
         final UserPassKey key = info.getUserPassKey();
         try {
-            _pool.invalidateObject(key, info);  // Destroy and update pool counters
-            _pool.clear(key); // Remove any idle instances with this key
+            pool.invalidateObject(key, info); // Destroy and update pool counters
+            pool.clear(key); // Remove any idle instances with this key
         } catch (final Exception ex) {
             throw new SQLException("Error invalidating connection", ex);
         }
     }
 
     /**
-     * Does nothing.  This factory does not cache user credentials.
+     * Does nothing. This factory does not cache user credentials.
      */
     @Override
     public void setPassword(final String password) {
+        // Does nothing. This factory does not cache user credentials.
     }
 
     /**
-     * Sets the maximum lifetime in milliseconds of a connection after which the
-     * connection will always fail activation, passivation and validation. A
-     * value of zero or less indicates an infinite lifetime. The default value
-     * is -1.
+     * Sets the maximum lifetime in milliseconds of a connection after which the connection will always fail activation,
+     * passivation and validation.
+     *
+     * @param maxConnLifetimeMillis
+     *            A value of zero or less indicates an infinite lifetime. The default value is -1.
      */
     public void setMaxConnLifetimeMillis(final long maxConnLifetimeMillis) {
         this.maxConnLifetimeMillis = maxConnLifetimeMillis;
     }
 
     /**
-     * This implementation does not fully close the KeyedObjectPool, as
-     * this would affect all users.  Instead, it clears the pool associated
-     * with the given user.  This method is not currently used.
+     * This implementation does not fully close the KeyedObjectPool, as this would affect all users. Instead, it clears
+     * the pool associated with the given user. This method is not currently used.
      */
     @Override
-    public void closePool(final String username) throws SQLException {
+    public void closePool(final String userName) throws SQLException {
         try {
-            _pool.clear(new UserPassKey(username, null));
+            pool.clear(new UserPassKey(userName));
         } catch (final Exception ex) {
             throw new SQLException("Error closing connection pool", ex);
         }
     }
 
-    private void validateLifetime(final PooledObject<PooledConnectionAndInfo> p)
-            throws Exception {
+    private void validateLifetime(final PooledObject<PooledConnectionAndInfo> p) throws Exception {
         if (maxConnLifetimeMillis > 0) {
             final long lifetime = System.currentTimeMillis() - p.getCreateTime();
             if (lifetime > maxConnLifetimeMillis) {
-                throw new Exception(Utils.getMessage(
-                        "connectionFactory.lifetimeExceeded",
-                        Long.valueOf(lifetime),
+                throw new Exception(Utils.getMessage("connectionFactory.lifetimeExceeded", Long.valueOf(lifetime),
                         Long.valueOf(maxConnLifetimeMillis)));
             }
         }
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/datasources/PerUserPoolDataSource.java b/java/org/apache/tomcat/dbcp/dbcp2/datasources/PerUserPoolDataSource.java
index d6dd0e2..fd5a7ef 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/datasources/PerUserPoolDataSource.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/datasources/PerUserPoolDataSource.java
@@ -36,94 +36,167 @@
 import org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool;
 
 /**
- * <p>A pooling <code>DataSource</code> appropriate for deployment within
- * J2EE environment.  There are many configuration options, most of which are
- * defined in the parent class.  This datasource uses individual pools per
- * user, and some properties can be set specifically for a given user, if the
- * deployment environment can support initialization of mapped properties.
- * So for example, a pool of admin or write-access Connections can be
- * guaranteed a certain number of connections, separate from a maximum
- * set for users with read-only connections.</p>
+ * <p>
+ * A pooling <code>DataSource</code> appropriate for deployment within J2EE environment. There are many configuration
+ * options, most of which are defined in the parent class. This datasource uses individual pools per user, and some
+ * properties can be set specifically for a given user, if the deployment environment can support initialization of
+ * mapped properties. So for example, a pool of admin or write-access Connections can be guaranteed a certain number of
+ * connections, separate from a maximum set for users with read-only connections.
+ * </p>
  *
- * <p>User passwords can be changed without re-initializing the datasource.
- * When a <code>getConnection(username, password)</code> request is processed
- * with a password that is different from those used to create connections in
- * the pool associated with <code>username</code>, an attempt is made to create
- * a new connection using the supplied password and if this succeeds, the
- * existing pool is cleared and a new pool is created for connections using the
- * new password.</p>
+ * <p>
+ * User passwords can be changed without re-initializing the datasource. When a
+ * <code>getConnection(userName, password)</code> request is processed with a password that is different from those used
+ * to create connections in the pool associated with <code>userName</code>, an attempt is made to create a new
+ * connection using the supplied password and if this succeeds, the existing pool is cleared and a new pool is created
+ * for connections using the new password.
+ * </p>
  *
- * @author John D. McNally
  * @since 2.0
  */
 public class PerUserPoolDataSource extends InstanceKeyDataSource {
 
     private static final long serialVersionUID = 7872747993848065028L;
 
-    private static final Log log =
-            LogFactory.getLog(PerUserPoolDataSource.class);
+    private static final Log log = LogFactory.getLog(PerUserPoolDataSource.class);
 
     // Per user pool properties
-    private Map<String,Boolean> perUserBlockWhenExhausted = null;
-    private Map<String,String> perUserEvictionPolicyClassName = null;
-    private Map<String,Boolean> perUserLifo = null;
-    private Map<String,Integer> perUserMaxIdle = null;
-    private Map<String,Integer> perUserMaxTotal = null;
-    private Map<String,Long> perUserMaxWaitMillis = null;
-    private Map<String,Long> perUserMinEvictableIdleTimeMillis = null;
-    private Map<String,Integer> perUserMinIdle = null;
-    private Map<String,Integer> perUserNumTestsPerEvictionRun = null;
-    private Map<String,Long> perUserSoftMinEvictableIdleTimeMillis = null;
-    private Map<String,Boolean> perUserTestOnCreate = null;
-    private Map<String,Boolean> perUserTestOnBorrow = null;
-    private Map<String,Boolean> perUserTestOnReturn = null;
-    private Map<String,Boolean> perUserTestWhileIdle = null;
-    private Map<String,Long> perUserTimeBetweenEvictionRunsMillis = null;
+    private Map<String, Boolean> perUserBlockWhenExhausted;
+    private Map<String, String> perUserEvictionPolicyClassName;
+    private Map<String, Boolean> perUserLifo;
+    private Map<String, Integer> perUserMaxIdle;
+    private Map<String, Integer> perUserMaxTotal;
+    private Map<String, Long> perUserMaxWaitMillis;
+    private Map<String, Long> perUserMinEvictableIdleTimeMillis;
+    private Map<String, Integer> perUserMinIdle;
+    private Map<String, Integer> perUserNumTestsPerEvictionRun;
+    private Map<String, Long> perUserSoftMinEvictableIdleTimeMillis;
+    private Map<String, Boolean> perUserTestOnCreate;
+    private Map<String, Boolean> perUserTestOnBorrow;
+    private Map<String, Boolean> perUserTestOnReturn;
+    private Map<String, Boolean> perUserTestWhileIdle;
+    private Map<String, Long> perUserTimeBetweenEvictionRunsMillis;
 
     // Per user connection properties
-    private Map<String,Boolean> perUserDefaultAutoCommit = null;
-    private Map<String,Integer> perUserDefaultTransactionIsolation = null;
-    private Map<String,Boolean> perUserDefaultReadOnly = null;
+    private Map<String, Boolean> perUserDefaultAutoCommit;
+    private Map<String, Integer> perUserDefaultTransactionIsolation;
+    private Map<String, Boolean> perUserDefaultReadOnly;
 
     /**
-     * Map to keep track of Pools for a given user
+     * Map to keep track of Pools for a given user.
      */
-    private transient Map<PoolKey, PooledConnectionManager> managers =
-            new HashMap<>();
+    private transient Map<PoolKey, PooledConnectionManager> managers = new HashMap<>();
 
     /**
-     * Default no-arg constructor for Serialization
+     * Default no-arg constructor for Serialization.
      */
     public PerUserPoolDataSource() {
     }
 
     /**
-     * Close pool(s) being maintained by this datasource.
+     * Clears pool(s) maintained by this data source.
+     *
+     * @see org.apache.tomcat.dbcp.pool2.ObjectPool#clear()
+     * @since 2.3.0
      */
-    @Override
-    public void close() {
+    public void clear() {
         for (final PooledConnectionManager manager : managers.values()) {
             try {
-              ((CPDSConnectionFactory) manager).getPool().close();
+                getCPDSConnectionFactoryPool(manager).clear();
             } catch (final Exception closePoolException) {
-                    //ignore and try to close others.
+                // ignore and try to close others.
             }
         }
         InstanceKeyDataSourceFactory.removeInstance(getInstanceKey());
     }
 
-    // -------------------------------------------------------------------
-    // Properties
+    /**
+     * Closes pool(s) maintained by this data source.
+     *
+     * @see org.apache.tomcat.dbcp.pool2.ObjectPool#close()
+     */
+    @Override
+    public void close() {
+        for (final PooledConnectionManager manager : managers.values()) {
+            try {
+                getCPDSConnectionFactoryPool(manager).close();
+            } catch (final Exception closePoolException) {
+                // ignore and try to close others.
+            }
+        }
+        InstanceKeyDataSourceFactory.removeInstance(getInstanceKey());
+    }
+
+    private HashMap<String, Boolean> createMap() {
+        // Should there be a default size different than what this ctor provides?
+        return new HashMap<>();
+    }
+
+    @Override
+    protected PooledConnectionManager getConnectionManager(final UserPassKey upKey) {
+        return managers.get(getPoolKey(upKey.getUsername()));
+    }
+
+    private ObjectPool<PooledConnectionAndInfo> getCPDSConnectionFactoryPool(final PooledConnectionManager manager) {
+        return ((CPDSConnectionFactory) manager).getPool();
+    }
 
     /**
-     * Gets the user specific value for
-     * {@link GenericObjectPool#getBlockWhenExhausted()} for the
-     * specified user's pool or the default if no user specific value is defined.
+     * Gets the number of active connections in the default pool.
+     *
+     * @return The number of active connections in the default pool.
      */
-    public boolean getPerUserBlockWhenExhausted(final String key) {
+    public int getNumActive() {
+        return getNumActive(null);
+    }
+
+    /**
+     * Gets the number of active connections in the pool for a given user.
+     *
+     * @param userName
+     *            The user name key.
+     * @return The user specific value.
+     */
+    @SuppressWarnings("resource")
+    public int getNumActive(final String userName) {
+        final ObjectPool<PooledConnectionAndInfo> pool = getPool(getPoolKey(userName));
+        return pool == null ? 0 : pool.getNumActive();
+    }
+
+    /**
+     * Gets the number of idle connections in the default pool.
+     *
+     * @return The number of idle connections in the default pool.
+     */
+    public int getNumIdle() {
+        return getNumIdle(null);
+    }
+
+    /**
+     * Gets the number of idle connections in the pool for a given user.
+     *
+     * @param userName
+     *            The user name key.
+     * @return The user specific value.
+     */
+    @SuppressWarnings("resource")
+    public int getNumIdle(final String userName) {
+        final ObjectPool<PooledConnectionAndInfo> pool = getPool(getPoolKey(userName));
+        return pool == null ? 0 : pool.getNumIdle();
+    }
+
+    /**
+     * Gets the user specific value for {@link GenericObjectPool#getBlockWhenExhausted()} for the specified user's pool
+     * or the default if no user specific value is defined.
+     *
+     * @param userName
+     *            The user name key.
+     * @return The user specific value.
+     */
+    public boolean getPerUserBlockWhenExhausted(final String userName) {
         Boolean value = null;
         if (perUserBlockWhenExhausted != null) {
-            value = perUserBlockWhenExhausted.get(key);
+            value = perUserBlockWhenExhausted.get(userName);
         }
         if (value == null) {
             return getDefaultBlockWhenExhausted();
@@ -132,40 +205,63 @@
     }
 
     /**
-     * Sets a user specific value for
-     * {@link GenericObjectPool#getBlockWhenExhausted()} for the specified
-     * user's pool.
+     * Gets the user specific default value for {@link Connection#setAutoCommit(boolean)} for the specified user's pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @return The user specific value.
      */
-    public void setPerUserBlockWhenExhausted(final String username,
-            final Boolean value) {
-        assertInitializationAllowed();
-        if (perUserBlockWhenExhausted == null) {
-            perUserBlockWhenExhausted = new HashMap<>();
+    public Boolean getPerUserDefaultAutoCommit(final String userName) {
+        Boolean value = null;
+        if (perUserDefaultAutoCommit != null) {
+            value = perUserDefaultAutoCommit.get(userName);
         }
-        perUserBlockWhenExhausted.put(username, value);
+        return value;
     }
 
-    void setPerUserBlockWhenExhausted(
-            final Map<String,Boolean> userDefaultBlockWhenExhausted) {
-        assertInitializationAllowed();
-        if (perUserBlockWhenExhausted == null) {
-            perUserBlockWhenExhausted = new HashMap<>();
-        } else {
-            perUserBlockWhenExhausted.clear();
-        }
-        perUserBlockWhenExhausted.putAll(userDefaultBlockWhenExhausted);
-    }
-
-
     /**
-     * Gets the user specific value for
-     * {@link GenericObjectPool#getEvictionPolicyClassName()} for the
-     * specified user's pool or the default if no user specific value is defined.
+     * Gets the user specific default value for {@link Connection#setReadOnly(boolean)} for the specified user's pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @return The user specific value.
      */
-    public String getPerUserEvictionPolicyClassName(final String key) {
+    public Boolean getPerUserDefaultReadOnly(final String userName) {
+        Boolean value = null;
+        if (perUserDefaultReadOnly != null) {
+            value = perUserDefaultReadOnly.get(userName);
+        }
+        return value;
+    }
+
+    /**
+     * Gets the user specific default value for {@link Connection#setTransactionIsolation(int)} for the specified user's
+     * pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @return The user specific value.
+     */
+    public Integer getPerUserDefaultTransactionIsolation(final String userName) {
+        Integer value = null;
+        if (perUserDefaultTransactionIsolation != null) {
+            value = perUserDefaultTransactionIsolation.get(userName);
+        }
+        return value;
+    }
+
+    /**
+     * Gets the user specific value for {@link GenericObjectPool#getEvictionPolicyClassName()} for the specified user's
+     * pool or the default if no user specific value is defined.
+     *
+     * @param userName
+     *            The user name key.
+     * @return The user specific value.
+     */
+    public String getPerUserEvictionPolicyClassName(final String userName) {
         String value = null;
         if (perUserEvictionPolicyClassName != null) {
-            value = perUserEvictionPolicyClassName.get(key);
+            value = perUserEvictionPolicyClassName.get(userName);
         }
         if (value == null) {
             return getDefaultEvictionPolicyClassName();
@@ -174,40 +270,17 @@
     }
 
     /**
-     * Sets a user specific value for
-     * {@link GenericObjectPool#getEvictionPolicyClassName()} for the specified
-     * user's pool.
+     * Gets the user specific value for {@link GenericObjectPool#getLifo()} for the specified user's pool or the default
+     * if no user specific value is defined.
+     *
+     * @param userName
+     *            The user name key.
+     * @return The user specific value.
      */
-    public void setPerUserEvictionPolicyClassName(final String username,
-            final String value) {
-        assertInitializationAllowed();
-        if (perUserEvictionPolicyClassName == null) {
-            perUserEvictionPolicyClassName = new HashMap<>();
-        }
-        perUserEvictionPolicyClassName.put(username, value);
-    }
-
-    void setPerUserEvictionPolicyClassName(
-            final Map<String,String> userDefaultEvictionPolicyClassName) {
-        assertInitializationAllowed();
-        if (perUserEvictionPolicyClassName == null) {
-            perUserEvictionPolicyClassName = new HashMap<>();
-        } else {
-            perUserEvictionPolicyClassName.clear();
-        }
-        perUserEvictionPolicyClassName.putAll(userDefaultEvictionPolicyClassName);
-    }
-
-
-    /**
-     * Gets the user specific value for {@link GenericObjectPool#getLifo()} for
-     * the specified user's pool or the default if no user specific value is
-     * defined.
-     */
-    public boolean getPerUserLifo(final String key) {
+    public boolean getPerUserLifo(final String userName) {
         Boolean value = null;
         if (perUserLifo != null) {
-            value = perUserLifo.get(key);
+            value = perUserLifo.get(userName);
         }
         if (value == null) {
             return getDefaultLifo();
@@ -216,38 +289,17 @@
     }
 
     /**
-     * Sets a user specific value for
-     * {@link GenericObjectPool#getLifo()} for the specified
-     * user's pool.
+     * Gets the user specific value for {@link GenericObjectPool#getMaxIdle()} for the specified user's pool or the
+     * default if no user specific value is defined.
+     *
+     * @param userName
+     *            The user name key.
+     * @return The user specific value.
      */
-    public void setPerUserLifo(final String username, final Boolean value) {
-        assertInitializationAllowed();
-        if (perUserLifo == null) {
-            perUserLifo = new HashMap<>();
-        }
-        perUserLifo.put(username, value);
-    }
-
-    void setPerUserLifo(final Map<String,Boolean> userDefaultLifo) {
-        assertInitializationAllowed();
-        if (perUserLifo == null) {
-            perUserLifo = new HashMap<>();
-        } else {
-            perUserLifo.clear();
-        }
-        perUserLifo.putAll(userDefaultLifo);
-    }
-
-
-    /**
-     * Gets the user specific value for
-     * {@link GenericObjectPool#getMaxIdle()} for the
-     * specified user's pool or the default if no user specific value is defined.
-     */
-    public int getPerUserMaxIdle(final String key) {
+    public int getPerUserMaxIdle(final String userName) {
         Integer value = null;
         if (perUserMaxIdle != null) {
-            value = perUserMaxIdle.get(key);
+            value = perUserMaxIdle.get(userName);
         }
         if (value == null) {
             return getDefaultMaxIdle();
@@ -256,38 +308,17 @@
     }
 
     /**
-     * Sets a user specific value for
-     * {@link GenericObjectPool#getMaxIdle()} for the specified
-     * user's pool.
+     * Gets the user specific value for {@link GenericObjectPool#getMaxTotal()} for the specified user's pool or the
+     * default if no user specific value is defined.
+     *
+     * @param userName
+     *            The user name key.
+     * @return The user specific value.
      */
-    public void setPerUserMaxIdle(final String username, final Integer value) {
-        assertInitializationAllowed();
-        if (perUserMaxIdle == null) {
-            perUserMaxIdle = new HashMap<>();
-        }
-        perUserMaxIdle.put(username, value);
-    }
-
-    void setPerUserMaxIdle(final Map<String,Integer> userDefaultMaxIdle) {
-        assertInitializationAllowed();
-        if (perUserMaxIdle == null) {
-            perUserMaxIdle = new HashMap<>();
-        } else {
-            perUserMaxIdle.clear();
-        }
-        perUserMaxIdle.putAll(userDefaultMaxIdle);
-    }
-
-
-    /**
-     * Gets the user specific value for
-     * {@link GenericObjectPool#getMaxTotal()} for the
-     * specified user's pool or the default if no user specific value is defined.
-     */
-    public int getPerUserMaxTotal(final String key) {
+    public int getPerUserMaxTotal(final String userName) {
         Integer value = null;
         if (perUserMaxTotal != null) {
-            value = perUserMaxTotal.get(key);
+            value = perUserMaxTotal.get(userName);
         }
         if (value == null) {
             return getDefaultMaxTotal();
@@ -296,38 +327,17 @@
     }
 
     /**
-     * Sets a user specific value for
-     * {@link GenericObjectPool#getMaxTotal()} for the specified
-     * user's pool.
+     * Gets the user specific value for {@link GenericObjectPool#getMaxWaitMillis()} for the specified user's pool or
+     * the default if no user specific value is defined.
+     *
+     * @param userName
+     *            The user name key.
+     * @return The user specific value.
      */
-    public void setPerUserMaxTotal(final String username, final Integer value) {
-        assertInitializationAllowed();
-        if (perUserMaxTotal == null) {
-            perUserMaxTotal = new HashMap<>();
-        }
-        perUserMaxTotal.put(username, value);
-    }
-
-    void setPerUserMaxTotal(final Map<String,Integer> userDefaultMaxTotal) {
-        assertInitializationAllowed();
-        if (perUserMaxTotal == null) {
-            perUserMaxTotal = new HashMap<>();
-        } else {
-            perUserMaxTotal.clear();
-        }
-        perUserMaxTotal.putAll(userDefaultMaxTotal);
-    }
-
-
-    /**
-     * Gets the user specific value for
-     * {@link GenericObjectPool#getMaxWaitMillis()} for the
-     * specified user's pool or the default if no user specific value is defined.
-     */
-    public long getPerUserMaxWaitMillis(final String key) {
+    public long getPerUserMaxWaitMillis(final String userName) {
         Long value = null;
         if (perUserMaxWaitMillis != null) {
-            value = perUserMaxWaitMillis.get(key);
+            value = perUserMaxWaitMillis.get(userName);
         }
         if (value == null) {
             return getDefaultMaxWaitMillis();
@@ -336,39 +346,17 @@
     }
 
     /**
-     * Sets a user specific value for
-     * {@link GenericObjectPool#getMaxWaitMillis()} for the specified
-     * user's pool.
+     * Gets the user specific value for {@link GenericObjectPool#getMinEvictableIdleTimeMillis()} for the specified
+     * user's pool or the default if no user specific value is defined.
+     *
+     * @param userName
+     *            The user name key.
+     * @return The user specific value.
      */
-    public void setPerUserMaxWaitMillis(final String username, final Long value) {
-        assertInitializationAllowed();
-        if (perUserMaxWaitMillis == null) {
-            perUserMaxWaitMillis = new HashMap<>();
-        }
-        perUserMaxWaitMillis.put(username, value);
-    }
-
-    void setPerUserMaxWaitMillis(
-            final Map<String,Long> userDefaultMaxWaitMillis) {
-        assertInitializationAllowed();
-        if (perUserMaxWaitMillis == null) {
-            perUserMaxWaitMillis = new HashMap<>();
-        } else {
-            perUserMaxWaitMillis.clear();
-        }
-        perUserMaxWaitMillis.putAll(userDefaultMaxWaitMillis);
-    }
-
-
-    /**
-     * Gets the user specific value for
-     * {@link GenericObjectPool#getMinEvictableIdleTimeMillis()} for the
-     * specified user's pool or the default if no user specific value is defined.
-     */
-    public long getPerUserMinEvictableIdleTimeMillis(final String key) {
+    public long getPerUserMinEvictableIdleTimeMillis(final String userName) {
         Long value = null;
         if (perUserMinEvictableIdleTimeMillis != null) {
-            value = perUserMinEvictableIdleTimeMillis.get(key);
+            value = perUserMinEvictableIdleTimeMillis.get(userName);
         }
         if (value == null) {
             return getDefaultMinEvictableIdleTimeMillis();
@@ -377,41 +365,17 @@
     }
 
     /**
-     * Sets a user specific value for
-     * {@link GenericObjectPool#getMinEvictableIdleTimeMillis()} for the
-     * specified user's pool.
+     * Gets the user specific value for {@link GenericObjectPool#getMinIdle()} for the specified user's pool or the
+     * default if no user specific value is defined.
+     *
+     * @param userName
+     *            The user name key.
+     * @return The user specific value.
      */
-    public void setPerUserMinEvictableIdleTimeMillis(final String username,
-            final Long value) {
-        assertInitializationAllowed();
-        if (perUserMinEvictableIdleTimeMillis == null) {
-            perUserMinEvictableIdleTimeMillis = new HashMap<>();
-        }
-        perUserMinEvictableIdleTimeMillis.put(username, value);
-    }
-
-    void setPerUserMinEvictableIdleTimeMillis(
-            final Map<String,Long> userDefaultMinEvictableIdleTimeMillis) {
-        assertInitializationAllowed();
-        if (perUserMinEvictableIdleTimeMillis == null) {
-            perUserMinEvictableIdleTimeMillis = new HashMap<>();
-        } else {
-            perUserMinEvictableIdleTimeMillis.clear();
-        }
-        perUserMinEvictableIdleTimeMillis.putAll(
-                userDefaultMinEvictableIdleTimeMillis);
-    }
-
-
-    /**
-     * Gets the user specific value for
-     * {@link GenericObjectPool#getMinIdle()} for the
-     * specified user's pool or the default if no user specific value is defined.
-     */
-    public int getPerUserMinIdle(final String key) {
+    public int getPerUserMinIdle(final String userName) {
         Integer value = null;
         if (perUserMinIdle != null) {
-            value = perUserMinIdle.get(key);
+            value = perUserMinIdle.get(userName);
         }
         if (value == null) {
             return getDefaultMinIdle();
@@ -420,38 +384,17 @@
     }
 
     /**
-     * Sets a user specific value for
-     * {@link GenericObjectPool#getMinIdle()} for the specified
-     * user's pool.
+     * Gets the user specific value for {@link GenericObjectPool#getNumTestsPerEvictionRun()} for the specified user's
+     * pool or the default if no user specific value is defined.
+     *
+     * @param userName
+     *            The user name key.
+     * @return The user specific value.
      */
-    public void setPerUserMinIdle(final String username, final Integer value) {
-        assertInitializationAllowed();
-        if (perUserMinIdle == null) {
-            perUserMinIdle = new HashMap<>();
-        }
-        perUserMinIdle.put(username, value);
-    }
-
-    void setPerUserMinIdle(final Map<String,Integer> userDefaultMinIdle) {
-        assertInitializationAllowed();
-        if (perUserMinIdle == null) {
-            perUserMinIdle = new HashMap<>();
-        } else {
-            perUserMinIdle.clear();
-        }
-        perUserMinIdle.putAll(userDefaultMinIdle);
-    }
-
-
-    /**
-     * Gets the user specific value for
-     * {@link GenericObjectPool#getNumTestsPerEvictionRun()} for the
-     * specified user's pool or the default if no user specific value is defined.
-     */
-    public int getPerUserNumTestsPerEvictionRun(final String key) {
+    public int getPerUserNumTestsPerEvictionRun(final String userName) {
         Integer value = null;
         if (perUserNumTestsPerEvictionRun != null) {
-            value = perUserNumTestsPerEvictionRun.get(key);
+            value = perUserNumTestsPerEvictionRun.get(userName);
         }
         if (value == null) {
             return getDefaultNumTestsPerEvictionRun();
@@ -460,40 +403,17 @@
     }
 
     /**
-     * Sets a user specific value for
-     * {@link GenericObjectPool#getNumTestsPerEvictionRun()} for the specified
-     * user's pool.
+     * Gets the user specific value for {@link GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for the specified
+     * user's pool or the default if no user specific value is defined.
+     *
+     * @param userName
+     *            The user name key.
+     * @return The user specific value.
      */
-    public void setPerUserNumTestsPerEvictionRun(final String username,
-            final Integer value) {
-        assertInitializationAllowed();
-        if (perUserNumTestsPerEvictionRun == null) {
-            perUserNumTestsPerEvictionRun = new HashMap<>();
-        }
-        perUserNumTestsPerEvictionRun.put(username, value);
-    }
-
-    void setPerUserNumTestsPerEvictionRun(
-            final Map<String,Integer> userDefaultNumTestsPerEvictionRun) {
-        assertInitializationAllowed();
-        if (perUserNumTestsPerEvictionRun == null) {
-            perUserNumTestsPerEvictionRun = new HashMap<>();
-        } else {
-            perUserNumTestsPerEvictionRun.clear();
-        }
-        perUserNumTestsPerEvictionRun.putAll(userDefaultNumTestsPerEvictionRun);
-    }
-
-
-    /**
-     * Gets the user specific value for
-     * {@link GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for the
-     * specified user's pool or the default if no user specific value is defined.
-     */
-    public long getPerUserSoftMinEvictableIdleTimeMillis(final String key) {
+    public long getPerUserSoftMinEvictableIdleTimeMillis(final String userName) {
         Long value = null;
         if (perUserSoftMinEvictableIdleTimeMillis != null) {
-            value = perUserSoftMinEvictableIdleTimeMillis.get(key);
+            value = perUserSoftMinEvictableIdleTimeMillis.get(userName);
         }
         if (value == null) {
             return getDefaultSoftMinEvictableIdleTimeMillis();
@@ -502,80 +422,17 @@
     }
 
     /**
-     * Sets a user specific value for
-     * {@link GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for the
-     * specified user's pool.
+     * Gets the user specific value for {@link GenericObjectPool#getTestOnBorrow()} for the specified user's pool or the
+     * default if no user specific value is defined.
+     *
+     * @param userName
+     *            The user name key.
+     * @return The user specific value.
      */
-    public void setPerUserSoftMinEvictableIdleTimeMillis(final String username,
-            final Long value) {
-        assertInitializationAllowed();
-        if (perUserSoftMinEvictableIdleTimeMillis == null) {
-            perUserSoftMinEvictableIdleTimeMillis = new HashMap<>();
-        }
-        perUserSoftMinEvictableIdleTimeMillis.put(username, value);
-    }
-
-    void setPerUserSoftMinEvictableIdleTimeMillis(
-            final Map<String,Long> userDefaultSoftMinEvictableIdleTimeMillis) {
-        assertInitializationAllowed();
-        if (perUserSoftMinEvictableIdleTimeMillis == null) {
-            perUserSoftMinEvictableIdleTimeMillis = new HashMap<>();
-        } else {
-            perUserSoftMinEvictableIdleTimeMillis.clear();
-        }
-        perUserSoftMinEvictableIdleTimeMillis.putAll(userDefaultSoftMinEvictableIdleTimeMillis);
-    }
-
-
-    /**
-     * Gets the user specific value for
-     * {@link GenericObjectPool#getTestOnCreate()} for the
-     * specified user's pool or the default if no user specific value is defined.
-     */
-    public boolean getPerUserTestOnCreate(final String key) {
-        Boolean value = null;
-        if (perUserTestOnCreate != null) {
-            value = perUserTestOnCreate.get(key);
-        }
-        if (value == null) {
-            return getDefaultTestOnCreate();
-        }
-        return value.booleanValue();
-    }
-
-    /**
-     * Sets a user specific value for
-     * {@link GenericObjectPool#getTestOnCreate()} for the specified
-     * user's pool.
-     */
-    public void setPerUserTestOnCreate(final String username, final Boolean value) {
-        assertInitializationAllowed();
-        if (perUserTestOnCreate == null) {
-            perUserTestOnCreate = new HashMap<>();
-        }
-        perUserTestOnCreate.put(username, value);
-    }
-
-    void setPerUserTestOnCreate(final Map<String,Boolean> userDefaultTestOnCreate) {
-        assertInitializationAllowed();
-        if (perUserTestOnCreate == null) {
-            perUserTestOnCreate = new HashMap<>();
-        } else {
-            perUserTestOnCreate.clear();
-        }
-        perUserTestOnCreate.putAll(userDefaultTestOnCreate);
-    }
-
-
-    /**
-     * Gets the user specific value for
-     * {@link GenericObjectPool#getTestOnBorrow()} for the
-     * specified user's pool or the default if no user specific value is defined.
-     */
-    public boolean getPerUserTestOnBorrow(final String key) {
+    public boolean getPerUserTestOnBorrow(final String userName) {
         Boolean value = null;
         if (perUserTestOnBorrow != null) {
-            value = perUserTestOnBorrow.get(key);
+            value = perUserTestOnBorrow.get(userName);
         }
         if (value == null) {
             return getDefaultTestOnBorrow();
@@ -584,38 +441,36 @@
     }
 
     /**
-     * Sets a user specific value for
-     * {@link GenericObjectPool#getTestOnBorrow()} for the specified
-     * user's pool.
+     * Gets the user specific value for {@link GenericObjectPool#getTestOnCreate()} for the specified user's pool or the
+     * default if no user specific value is defined.
+     *
+     * @param userName
+     *            The user name key.
+     * @return The user specific value.
      */
-    public void setPerUserTestOnBorrow(final String username, final Boolean value) {
-        assertInitializationAllowed();
-        if (perUserTestOnBorrow == null) {
-            perUserTestOnBorrow = new HashMap<>();
+    public boolean getPerUserTestOnCreate(final String userName) {
+        Boolean value = null;
+        if (perUserTestOnCreate != null) {
+            value = perUserTestOnCreate.get(userName);
         }
-        perUserTestOnBorrow.put(username, value);
-    }
-
-    void setPerUserTestOnBorrow(final Map<String,Boolean> userDefaultTestOnBorrow) {
-        assertInitializationAllowed();
-        if (perUserTestOnBorrow == null) {
-            perUserTestOnBorrow = new HashMap<>();
-        } else {
-            perUserTestOnBorrow.clear();
+        if (value == null) {
+            return getDefaultTestOnCreate();
         }
-        perUserTestOnBorrow.putAll(userDefaultTestOnBorrow);
+        return value.booleanValue();
     }
 
-
     /**
-     * Gets the user specific value for
-     * {@link GenericObjectPool#getTestOnReturn()} for the
-     * specified user's pool or the default if no user specific value is defined.
+     * Gets the user specific value for {@link GenericObjectPool#getTestOnReturn()} for the specified user's pool or the
+     * default if no user specific value is defined.
+     *
+     * @param userName
+     *            The user name key.
+     * @return The user specific value.
      */
-    public boolean getPerUserTestOnReturn(final String key) {
+    public boolean getPerUserTestOnReturn(final String userName) {
         Boolean value = null;
         if (perUserTestOnReturn != null) {
-            value = perUserTestOnReturn.get(key);
+            value = perUserTestOnReturn.get(userName);
         }
         if (value == null) {
             return getDefaultTestOnReturn();
@@ -624,39 +479,17 @@
     }
 
     /**
-     * Sets a user specific value for
-     * {@link GenericObjectPool#getTestOnReturn()} for the specified
-     * user's pool.
+     * Gets the user specific value for {@link GenericObjectPool#getTestWhileIdle()} for the specified user's pool or
+     * the default if no user specific value is defined.
+     *
+     * @param userName
+     *            The user name key.
+     * @return The user specific value.
      */
-    public void setPerUserTestOnReturn(final String username, final Boolean value) {
-        assertInitializationAllowed();
-        if (perUserTestOnReturn == null) {
-            perUserTestOnReturn = new HashMap<>();
-        }
-        perUserTestOnReturn.put(username, value);
-    }
-
-    void setPerUserTestOnReturn(
-            final Map<String,Boolean> userDefaultTestOnReturn) {
-        assertInitializationAllowed();
-        if (perUserTestOnReturn == null) {
-            perUserTestOnReturn = new HashMap<>();
-        } else {
-            perUserTestOnReturn.clear();
-        }
-        perUserTestOnReturn.putAll(userDefaultTestOnReturn);
-    }
-
-
-    /**
-     * Gets the user specific value for
-     * {@link GenericObjectPool#getTestWhileIdle()} for the
-     * specified user's pool or the default if no user specific value is defined.
-     */
-    public boolean getPerUserTestWhileIdle(final String key) {
+    public boolean getPerUserTestWhileIdle(final String userName) {
         Boolean value = null;
         if (perUserTestWhileIdle != null) {
-            value = perUserTestWhileIdle.get(key);
+            value = perUserTestWhileIdle.get(userName);
         }
         if (value == null) {
             return getDefaultTestWhileIdle();
@@ -665,39 +498,17 @@
     }
 
     /**
-     * Sets a user specific value for
-     * {@link GenericObjectPool#getTestWhileIdle()} for the specified
-     * user's pool.
+     * Gets the user specific value for {@link GenericObjectPool#getTimeBetweenEvictionRunsMillis()} for the specified
+     * user's pool or the default if no user specific value is defined.
+     *
+     * @param userName
+     *            The user name key.
+     * @return The user specific value.
      */
-    public void setPerUserTestWhileIdle(final String username, final Boolean value) {
-        assertInitializationAllowed();
-        if (perUserTestWhileIdle == null) {
-            perUserTestWhileIdle = new HashMap<>();
-        }
-        perUserTestWhileIdle.put(username, value);
-    }
-
-    void setPerUserTestWhileIdle(
-            final Map<String,Boolean> userDefaultTestWhileIdle) {
-        assertInitializationAllowed();
-        if (perUserTestWhileIdle == null) {
-            perUserTestWhileIdle = new HashMap<>();
-        } else {
-            perUserTestWhileIdle.clear();
-        }
-        perUserTestWhileIdle.putAll(userDefaultTestWhileIdle);
-    }
-
-
-    /**
-     * Gets the user specific value for
-     * {@link GenericObjectPool#getTimeBetweenEvictionRunsMillis()} for the
-     * specified user's pool or the default if no user specific value is defined.
-     */
-    public long getPerUserTimeBetweenEvictionRunsMillis(final String key) {
+    public long getPerUserTimeBetweenEvictionRunsMillis(final String userName) {
         Long value = null;
         if (perUserTimeBetweenEvictionRunsMillis != null) {
-            value = perUserTimeBetweenEvictionRunsMillis.get(key);
+            value = perUserTimeBetweenEvictionRunsMillis.get(userName);
         }
         if (value == null) {
             return getDefaultTimeBetweenEvictionRunsMillis();
@@ -706,129 +517,229 @@
     }
 
     /**
-     * Sets a user specific value for
-     * {@link GenericObjectPool#getTimeBetweenEvictionRunsMillis ()} for the specified
-     * user's pool.
+     * Returns the object pool associated with the given PoolKey.
+     *
+     * @param poolKey
+     *            PoolKey identifying the pool
+     * @return the GenericObjectPool pooling connections for the userName and datasource specified by the PoolKey
      */
-    public void setPerUserTimeBetweenEvictionRunsMillis(final String username,
-            final Long value) {
-        assertInitializationAllowed();
-        if (perUserTimeBetweenEvictionRunsMillis == null) {
-            perUserTimeBetweenEvictionRunsMillis = new HashMap<>();
-        }
-        perUserTimeBetweenEvictionRunsMillis.put(username, value);
+    private ObjectPool<PooledConnectionAndInfo> getPool(final PoolKey poolKey) {
+        final CPDSConnectionFactory mgr = (CPDSConnectionFactory) managers.get(poolKey);
+        return mgr == null ? null : mgr.getPool();
     }
 
-    void setPerUserTimeBetweenEvictionRunsMillis(
-            final Map<String,Long> userDefaultTimeBetweenEvictionRunsMillis ) {
+    @Override
+    protected PooledConnectionAndInfo getPooledConnectionAndInfo(final String userName, final String password)
+            throws SQLException {
+
+        final PoolKey key = getPoolKey(userName);
+        ObjectPool<PooledConnectionAndInfo> pool;
+        PooledConnectionManager manager;
+        synchronized (this) {
+            manager = managers.get(key);
+            if (manager == null) {
+                try {
+                    registerPool(userName, password);
+                    manager = managers.get(key);
+                } catch (final NamingException e) {
+                    throw new SQLException("RegisterPool failed", e);
+                }
+            }
+            pool = getCPDSConnectionFactoryPool(manager);
+        }
+
+        PooledConnectionAndInfo info = null;
+        try {
+            info = pool.borrowObject();
+        } catch (final NoSuchElementException ex) {
+            throw new SQLException("Could not retrieve connection info from pool", ex);
+        } catch (final Exception e) {
+            // See if failure is due to CPDSConnectionFactory authentication failure
+            try {
+                testCPDS(userName, password);
+            } catch (final Exception ex) {
+                throw new SQLException("Could not retrieve connection info from pool", ex);
+            }
+            // New password works, so kill the old pool, create a new one, and borrow
+            manager.closePool(userName);
+            synchronized (this) {
+                managers.remove(key);
+            }
+            try {
+                registerPool(userName, password);
+                pool = getPool(key);
+            } catch (final NamingException ne) {
+                throw new SQLException("RegisterPool failed", ne);
+            }
+            try {
+                info = pool.borrowObject();
+            } catch (final Exception ex) {
+                throw new SQLException("Could not retrieve connection info from pool", ex);
+            }
+        }
+        return info;
+    }
+
+    /**
+     * Creates a pool key from the provided parameters.
+     *
+     * @param userName
+     *            User name
+     * @return The pool key
+     */
+    private PoolKey getPoolKey(final String userName) {
+        return new PoolKey(getDataSourceName(), userName);
+    }
+
+    /**
+     * Returns a <code>PerUserPoolDataSource</code> {@link Reference}.
+     */
+    @Override
+    public Reference getReference() throws NamingException {
+        final Reference ref = new Reference(getClass().getName(), PerUserPoolDataSourceFactory.class.getName(), null);
+        ref.add(new StringRefAddr("instanceKey", getInstanceKey()));
+        return ref;
+    }
+
+    /**
+     * Supports Serialization interface.
+     *
+     * @param in
+     *            a <code>java.io.ObjectInputStream</code> value
+     * @throws IOException
+     *             if an error occurs
+     * @throws ClassNotFoundException
+     *             if an error occurs
+     */
+    private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
+        try {
+            in.defaultReadObject();
+            final PerUserPoolDataSource oldDS = (PerUserPoolDataSource) new PerUserPoolDataSourceFactory()
+                    .getObjectInstance(getReference(), null, null, null);
+            this.managers = oldDS.managers;
+        } catch (final NamingException e) {
+            throw new IOException("NamingException: " + e);
+        }
+    }
+
+    private synchronized void registerPool(final String userName, final String password)
+            throws NamingException, SQLException {
+
+        final ConnectionPoolDataSource cpds = testCPDS(userName, password);
+
+        // Set up the factory we will use (passing the pool associates
+        // the factory with the pool, so we do not have to do so
+        // explicitly)
+        final CPDSConnectionFactory factory = new CPDSConnectionFactory(cpds, getValidationQuery(),
+                getValidationQueryTimeout(), isRollbackAfterValidation(), userName, password);
+        factory.setMaxConnLifetimeMillis(getMaxConnLifetimeMillis());
+
+        // Create an object pool to contain our PooledConnections
+        final GenericObjectPool<PooledConnectionAndInfo> pool = new GenericObjectPool<>(factory);
+        factory.setPool(pool);
+        pool.setBlockWhenExhausted(getPerUserBlockWhenExhausted(userName));
+        pool.setEvictionPolicyClassName(getPerUserEvictionPolicyClassName(userName));
+        pool.setLifo(getPerUserLifo(userName));
+        pool.setMaxIdle(getPerUserMaxIdle(userName));
+        pool.setMaxTotal(getPerUserMaxTotal(userName));
+        pool.setMaxWaitMillis(getPerUserMaxWaitMillis(userName));
+        pool.setMinEvictableIdleTimeMillis(getPerUserMinEvictableIdleTimeMillis(userName));
+        pool.setMinIdle(getPerUserMinIdle(userName));
+        pool.setNumTestsPerEvictionRun(getPerUserNumTestsPerEvictionRun(userName));
+        pool.setSoftMinEvictableIdleTimeMillis(getPerUserSoftMinEvictableIdleTimeMillis(userName));
+        pool.setTestOnCreate(getPerUserTestOnCreate(userName));
+        pool.setTestOnBorrow(getPerUserTestOnBorrow(userName));
+        pool.setTestOnReturn(getPerUserTestOnReturn(userName));
+        pool.setTestWhileIdle(getPerUserTestWhileIdle(userName));
+        pool.setTimeBetweenEvictionRunsMillis(getPerUserTimeBetweenEvictionRunsMillis(userName));
+
+        pool.setSwallowedExceptionListener(new SwallowedExceptionLogger(log));
+
+        final Object old = managers.put(getPoolKey(userName), factory);
+        if (old != null) {
+            throw new IllegalStateException("Pool already contains an entry for this user/password: " + userName);
+        }
+    }
+
+    void setPerUserBlockWhenExhausted(final Map<String, Boolean> userDefaultBlockWhenExhausted) {
         assertInitializationAllowed();
-        if (perUserTimeBetweenEvictionRunsMillis == null) {
-            perUserTimeBetweenEvictionRunsMillis = new HashMap<>();
+        if (perUserBlockWhenExhausted == null) {
+            perUserBlockWhenExhausted = createMap();
         } else {
-            perUserTimeBetweenEvictionRunsMillis.clear();
+            perUserBlockWhenExhausted.clear();
         }
-        perUserTimeBetweenEvictionRunsMillis.putAll(
-                userDefaultTimeBetweenEvictionRunsMillis );
-    }
-
-
-    /**
-     * Gets the user specific default value for
-     * {@link Connection#setAutoCommit(boolean)} for the specified user's pool.
-     */
-    public Boolean getPerUserDefaultAutoCommit(final String key) {
-        Boolean value = null;
-        if (perUserDefaultAutoCommit != null) {
-            value = perUserDefaultAutoCommit.get(key);
-        }
-        return value;
+        perUserBlockWhenExhausted.putAll(userDefaultBlockWhenExhausted);
     }
 
     /**
-     * Sets a user specific default value for
-     * {@link Connection#setAutoCommit(boolean)} for the specified user's pool.
+     * Sets a user specific value for {@link GenericObjectPool#getBlockWhenExhausted()} for the specified user's pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @param value
+     *            The user specific value.
      */
-    public void setPerUserDefaultAutoCommit(final String username, final Boolean value) {
+    public void setPerUserBlockWhenExhausted(final String userName, final Boolean value) {
         assertInitializationAllowed();
-        if (perUserDefaultAutoCommit == null) {
-            perUserDefaultAutoCommit = new HashMap<>();
+        if (perUserBlockWhenExhausted == null) {
+            perUserBlockWhenExhausted = createMap();
         }
-        perUserDefaultAutoCommit.put(username, value);
+        perUserBlockWhenExhausted.put(userName, value);
     }
 
-    void setPerUserDefaultAutoCommit(final Map<String,Boolean> userDefaultAutoCommit) {
+    void setPerUserDefaultAutoCommit(final Map<String, Boolean> userDefaultAutoCommit) {
         assertInitializationAllowed();
         if (perUserDefaultAutoCommit == null) {
-            perUserDefaultAutoCommit = new HashMap<>();
+            perUserDefaultAutoCommit = createMap();
         } else {
             perUserDefaultAutoCommit.clear();
         }
         perUserDefaultAutoCommit.putAll(userDefaultAutoCommit);
     }
 
-
     /**
-     * Gets the user specific default value for
-     * {@link Connection#setReadOnly(boolean)} for the specified user's pool.
+     * Sets a user specific default value for {@link Connection#setAutoCommit(boolean)} for the specified user's pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @param value
+     *            The user specific value.
      */
-    public Boolean getPerUserDefaultReadOnly(final String key) {
-        Boolean value = null;
-        if (perUserDefaultReadOnly != null) {
-            value = perUserDefaultReadOnly.get(key);
+    public void setPerUserDefaultAutoCommit(final String userName, final Boolean value) {
+        assertInitializationAllowed();
+        if (perUserDefaultAutoCommit == null) {
+            perUserDefaultAutoCommit = createMap();
         }
-        return value;
+        perUserDefaultAutoCommit.put(userName, value);
     }
 
-    /**
-     * Sets a user specific default value for
-     * {@link Connection#setReadOnly(boolean)} for the specified user's pool.
-     */
-    public void setPerUserDefaultReadOnly(final String username, final Boolean value) {
+    void setPerUserDefaultReadOnly(final Map<String, Boolean> userDefaultReadOnly) {
         assertInitializationAllowed();
         if (perUserDefaultReadOnly == null) {
-            perUserDefaultReadOnly = new HashMap<>();
-        }
-        perUserDefaultReadOnly.put(username, value);
-    }
-
-    void setPerUserDefaultReadOnly(final Map<String,Boolean> userDefaultReadOnly) {
-        assertInitializationAllowed();
-        if (perUserDefaultReadOnly == null) {
-            perUserDefaultReadOnly = new HashMap<>();
+            perUserDefaultReadOnly = createMap();
         } else {
             perUserDefaultReadOnly.clear();
         }
         perUserDefaultReadOnly.putAll(userDefaultReadOnly);
     }
 
-
     /**
-     * Gets the user specific default value for
-     * {@link Connection#setTransactionIsolation(int)} for the specified user's pool.
+     * Sets a user specific default value for {@link Connection#setReadOnly(boolean)} for the specified user's pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @param value
+     *            The user specific value.
      */
-    public Integer getPerUserDefaultTransactionIsolation(final String key) {
-        Integer value = null;
-        if (perUserDefaultTransactionIsolation != null) {
-            value = perUserDefaultTransactionIsolation.get(key);
-        }
-        return value;
-    }
-
-    /**
-     * Sets a user specific default value for
-     * {@link Connection#setTransactionIsolation(int)} for the specified user's pool.
-     */
-    public void setPerUserDefaultTransactionIsolation(final String username,
-            final Integer value) {
+    public void setPerUserDefaultReadOnly(final String userName, final Boolean value) {
         assertInitializationAllowed();
-        if (perUserDefaultTransactionIsolation == null) {
-            perUserDefaultTransactionIsolation = new HashMap<>();
+        if (perUserDefaultReadOnly == null) {
+            perUserDefaultReadOnly = createMap();
         }
-        perUserDefaultTransactionIsolation.put(username, value);
+        perUserDefaultReadOnly.put(userName, value);
     }
 
-    void setPerUserDefaultTransactionIsolation(
-            final Map<String,Integer> userDefaultTransactionIsolation) {
+    void setPerUserDefaultTransactionIsolation(final Map<String, Integer> userDefaultTransactionIsolation) {
         assertInitializationAllowed();
         if (perUserDefaultTransactionIsolation == null) {
             perUserDefaultTransactionIsolation = new HashMap<>();
@@ -838,133 +749,419 @@
         perUserDefaultTransactionIsolation.putAll(userDefaultTransactionIsolation);
     }
 
-
-    // ----------------------------------------------------------------------
-    // Instrumentation Methods
-
     /**
-     * Get the number of active connections in the default pool.
+     * Sets a user specific default value for {@link Connection#setTransactionIsolation(int)} for the specified user's
+     * pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @param value
+     *            The user specific value.
      */
-    public int getNumActive() {
-        return getNumActive(null);
+    public void setPerUserDefaultTransactionIsolation(final String userName, final Integer value) {
+        assertInitializationAllowed();
+        if (perUserDefaultTransactionIsolation == null) {
+            perUserDefaultTransactionIsolation = new HashMap<>();
+        }
+        perUserDefaultTransactionIsolation.put(userName, value);
+    }
+
+    void setPerUserEvictionPolicyClassName(final Map<String, String> userDefaultEvictionPolicyClassName) {
+        assertInitializationAllowed();
+        if (perUserEvictionPolicyClassName == null) {
+            perUserEvictionPolicyClassName = new HashMap<>();
+        } else {
+            perUserEvictionPolicyClassName.clear();
+        }
+        perUserEvictionPolicyClassName.putAll(userDefaultEvictionPolicyClassName);
     }
 
     /**
-     * Get the number of active connections in the pool for a given user.
+     * Sets a user specific value for {@link GenericObjectPool#getEvictionPolicyClassName()} for the specified user's
+     * pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @param value
+     *            The user specific value.
      */
-    public int getNumActive(final String username) {
-        final ObjectPool<PooledConnectionAndInfo> pool =
-            getPool(getPoolKey(username));
-        return pool == null ? 0 : pool.getNumActive();
+    public void setPerUserEvictionPolicyClassName(final String userName, final String value) {
+        assertInitializationAllowed();
+        if (perUserEvictionPolicyClassName == null) {
+            perUserEvictionPolicyClassName = new HashMap<>();
+        }
+        perUserEvictionPolicyClassName.put(userName, value);
+    }
+
+    void setPerUserLifo(final Map<String, Boolean> userDefaultLifo) {
+        assertInitializationAllowed();
+        if (perUserLifo == null) {
+            perUserLifo = createMap();
+        } else {
+            perUserLifo.clear();
+        }
+        perUserLifo.putAll(userDefaultLifo);
     }
 
     /**
-     * Get the number of idle connections in the default pool.
+     * Sets a user specific value for {@link GenericObjectPool#getLifo()} for the specified user's pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @param value
+     *            The user specific value.
      */
-    public int getNumIdle() {
-        return getNumIdle(null);
+    public void setPerUserLifo(final String userName, final Boolean value) {
+        assertInitializationAllowed();
+        if (perUserLifo == null) {
+            perUserLifo = createMap();
+        }
+        perUserLifo.put(userName, value);
+    }
+
+    void setPerUserMaxIdle(final Map<String, Integer> userDefaultMaxIdle) {
+        assertInitializationAllowed();
+        if (perUserMaxIdle == null) {
+            perUserMaxIdle = new HashMap<>();
+        } else {
+            perUserMaxIdle.clear();
+        }
+        perUserMaxIdle.putAll(userDefaultMaxIdle);
     }
 
     /**
-     * Get the number of idle connections in the pool for a given user.
+     * Sets a user specific value for {@link GenericObjectPool#getMaxIdle()} for the specified user's pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @param value
+     *            The user specific value.
      */
-    public int getNumIdle(final String username) {
-        final ObjectPool<PooledConnectionAndInfo> pool =
-            getPool(getPoolKey(username));
-        return pool == null ? 0 : pool.getNumIdle();
+    public void setPerUserMaxIdle(final String userName, final Integer value) {
+        assertInitializationAllowed();
+        if (perUserMaxIdle == null) {
+            perUserMaxIdle = new HashMap<>();
+        }
+        perUserMaxIdle.put(userName, value);
     }
 
-
-    // ----------------------------------------------------------------------
-    // Inherited abstract methods
-
-    @Override
-    protected PooledConnectionAndInfo
-        getPooledConnectionAndInfo(final String username, final String password)
-        throws SQLException {
-
-        final PoolKey key = getPoolKey(username);
-        ObjectPool<PooledConnectionAndInfo> pool;
-        PooledConnectionManager manager;
-        synchronized(this) {
-            manager = managers.get(key);
-            if (manager == null) {
-                try {
-                    registerPool(username, password);
-                    manager = managers.get(key);
-                } catch (final NamingException e) {
-                    throw new SQLException("RegisterPool failed", e);
-                }
-            }
-            pool = ((CPDSConnectionFactory) manager).getPool();
+    void setPerUserMaxTotal(final Map<String, Integer> userDefaultMaxTotal) {
+        assertInitializationAllowed();
+        if (perUserMaxTotal == null) {
+            perUserMaxTotal = new HashMap<>();
+        } else {
+            perUserMaxTotal.clear();
         }
+        perUserMaxTotal.putAll(userDefaultMaxTotal);
+    }
 
-        PooledConnectionAndInfo info = null;
-        try {
-            info = pool.borrowObject();
+    /**
+     * Sets a user specific value for {@link GenericObjectPool#getMaxTotal()} for the specified user's pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @param value
+     *            The user specific value.
+     */
+    public void setPerUserMaxTotal(final String userName, final Integer value) {
+        assertInitializationAllowed();
+        if (perUserMaxTotal == null) {
+            perUserMaxTotal = new HashMap<>();
         }
-        catch (final NoSuchElementException ex) {
-            throw new SQLException(
-                    "Could not retrieve connection info from pool", ex);
+        perUserMaxTotal.put(userName, value);
+    }
+
+    void setPerUserMaxWaitMillis(final Map<String, Long> userDefaultMaxWaitMillis) {
+        assertInitializationAllowed();
+        if (perUserMaxWaitMillis == null) {
+            perUserMaxWaitMillis = new HashMap<>();
+        } else {
+            perUserMaxWaitMillis.clear();
         }
-        catch (final Exception e) {
-            // See if failure is due to CPDSConnectionFactory authentication failure
-            try {
-                testCPDS(username, password);
-            } catch (final Exception ex) {
-                throw new SQLException(
-                        "Could not retrieve connection info from pool", ex);
-            }
-            // New password works, so kill the old pool, create a new one, and borrow
-            manager.closePool(username);
-            synchronized (this) {
-                managers.remove(key);
-            }
-            try {
-                registerPool(username, password);
-                pool = getPool(key);
-            } catch (final NamingException ne) {
-                throw new SQLException("RegisterPool failed", ne);
-            }
-            try {
-                info = pool.borrowObject();
-            } catch (final Exception ex) {
-                throw new SQLException(
-                        "Could not retrieve connection info from pool", ex);
-            }
+        perUserMaxWaitMillis.putAll(userDefaultMaxWaitMillis);
+    }
+
+    /**
+     * Sets a user specific value for {@link GenericObjectPool#getMaxWaitMillis()} for the specified user's pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @param value
+     *            The user specific value.
+     */
+    public void setPerUserMaxWaitMillis(final String userName, final Long value) {
+        assertInitializationAllowed();
+        if (perUserMaxWaitMillis == null) {
+            perUserMaxWaitMillis = new HashMap<>();
         }
-        return info;
+        perUserMaxWaitMillis.put(userName, value);
+    }
+
+    void setPerUserMinEvictableIdleTimeMillis(final Map<String, Long> userDefaultMinEvictableIdleTimeMillis) {
+        assertInitializationAllowed();
+        if (perUserMinEvictableIdleTimeMillis == null) {
+            perUserMinEvictableIdleTimeMillis = new HashMap<>();
+        } else {
+            perUserMinEvictableIdleTimeMillis.clear();
+        }
+        perUserMinEvictableIdleTimeMillis.putAll(userDefaultMinEvictableIdleTimeMillis);
+    }
+
+    /**
+     * Sets a user specific value for {@link GenericObjectPool#getMinEvictableIdleTimeMillis()} for the specified user's
+     * pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @param value
+     *            The user specific value.
+     */
+    public void setPerUserMinEvictableIdleTimeMillis(final String userName, final Long value) {
+        assertInitializationAllowed();
+        if (perUserMinEvictableIdleTimeMillis == null) {
+            perUserMinEvictableIdleTimeMillis = new HashMap<>();
+        }
+        perUserMinEvictableIdleTimeMillis.put(userName, value);
+    }
+
+    void setPerUserMinIdle(final Map<String, Integer> userDefaultMinIdle) {
+        assertInitializationAllowed();
+        if (perUserMinIdle == null) {
+            perUserMinIdle = new HashMap<>();
+        } else {
+            perUserMinIdle.clear();
+        }
+        perUserMinIdle.putAll(userDefaultMinIdle);
+    }
+
+    /**
+     * Sets a user specific value for {@link GenericObjectPool#getMinIdle()} for the specified user's pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @param value
+     *            The user specific value.
+     */
+    public void setPerUserMinIdle(final String userName, final Integer value) {
+        assertInitializationAllowed();
+        if (perUserMinIdle == null) {
+            perUserMinIdle = new HashMap<>();
+        }
+        perUserMinIdle.put(userName, value);
+    }
+
+    void setPerUserNumTestsPerEvictionRun(final Map<String, Integer> userDefaultNumTestsPerEvictionRun) {
+        assertInitializationAllowed();
+        if (perUserNumTestsPerEvictionRun == null) {
+            perUserNumTestsPerEvictionRun = new HashMap<>();
+        } else {
+            perUserNumTestsPerEvictionRun.clear();
+        }
+        perUserNumTestsPerEvictionRun.putAll(userDefaultNumTestsPerEvictionRun);
+    }
+
+    /**
+     * Sets a user specific value for {@link GenericObjectPool#getNumTestsPerEvictionRun()} for the specified user's
+     * pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @param value
+     *            The user specific value.
+     */
+    public void setPerUserNumTestsPerEvictionRun(final String userName, final Integer value) {
+        assertInitializationAllowed();
+        if (perUserNumTestsPerEvictionRun == null) {
+            perUserNumTestsPerEvictionRun = new HashMap<>();
+        }
+        perUserNumTestsPerEvictionRun.put(userName, value);
+    }
+
+    void setPerUserSoftMinEvictableIdleTimeMillis(final Map<String, Long> userDefaultSoftMinEvictableIdleTimeMillis) {
+        assertInitializationAllowed();
+        if (perUserSoftMinEvictableIdleTimeMillis == null) {
+            perUserSoftMinEvictableIdleTimeMillis = new HashMap<>();
+        } else {
+            perUserSoftMinEvictableIdleTimeMillis.clear();
+        }
+        perUserSoftMinEvictableIdleTimeMillis.putAll(userDefaultSoftMinEvictableIdleTimeMillis);
+    }
+
+    /**
+     * Sets a user specific value for {@link GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for the specified
+     * user's pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @param value
+     *            The user specific value.
+     */
+    public void setPerUserSoftMinEvictableIdleTimeMillis(final String userName, final Long value) {
+        assertInitializationAllowed();
+        if (perUserSoftMinEvictableIdleTimeMillis == null) {
+            perUserSoftMinEvictableIdleTimeMillis = new HashMap<>();
+        }
+        perUserSoftMinEvictableIdleTimeMillis.put(userName, value);
+    }
+
+    void setPerUserTestOnBorrow(final Map<String, Boolean> userDefaultTestOnBorrow) {
+        assertInitializationAllowed();
+        if (perUserTestOnBorrow == null) {
+            perUserTestOnBorrow = createMap();
+        } else {
+            perUserTestOnBorrow.clear();
+        }
+        perUserTestOnBorrow.putAll(userDefaultTestOnBorrow);
+    }
+
+    /**
+     * Sets a user specific value for {@link GenericObjectPool#getTestOnBorrow()} for the specified user's pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @param value
+     *            The user specific value.
+     */
+    public void setPerUserTestOnBorrow(final String userName, final Boolean value) {
+        assertInitializationAllowed();
+        if (perUserTestOnBorrow == null) {
+            perUserTestOnBorrow = createMap();
+        }
+        perUserTestOnBorrow.put(userName, value);
+    }
+
+    void setPerUserTestOnCreate(final Map<String, Boolean> userDefaultTestOnCreate) {
+        assertInitializationAllowed();
+        if (perUserTestOnCreate == null) {
+            perUserTestOnCreate = createMap();
+        } else {
+            perUserTestOnCreate.clear();
+        }
+        perUserTestOnCreate.putAll(userDefaultTestOnCreate);
+    }
+
+    /**
+     * Sets a user specific value for {@link GenericObjectPool#getTestOnCreate()} for the specified user's pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @param value
+     *            The user specific value.
+     */
+    public void setPerUserTestOnCreate(final String userName, final Boolean value) {
+        assertInitializationAllowed();
+        if (perUserTestOnCreate == null) {
+            perUserTestOnCreate = createMap();
+        }
+        perUserTestOnCreate.put(userName, value);
+    }
+
+    void setPerUserTestOnReturn(final Map<String, Boolean> userDefaultTestOnReturn) {
+        assertInitializationAllowed();
+        if (perUserTestOnReturn == null) {
+            perUserTestOnReturn = createMap();
+        } else {
+            perUserTestOnReturn.clear();
+        }
+        perUserTestOnReturn.putAll(userDefaultTestOnReturn);
+    }
+
+    /**
+     * Sets a user specific value for {@link GenericObjectPool#getTestOnReturn()} for the specified user's pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @param value
+     *            The user specific value.
+     */
+    public void setPerUserTestOnReturn(final String userName, final Boolean value) {
+        assertInitializationAllowed();
+        if (perUserTestOnReturn == null) {
+            perUserTestOnReturn = createMap();
+        }
+        perUserTestOnReturn.put(userName, value);
+    }
+
+    void setPerUserTestWhileIdle(final Map<String, Boolean> userDefaultTestWhileIdle) {
+        assertInitializationAllowed();
+        if (perUserTestWhileIdle == null) {
+            perUserTestWhileIdle = createMap();
+        } else {
+            perUserTestWhileIdle.clear();
+        }
+        perUserTestWhileIdle.putAll(userDefaultTestWhileIdle);
+    }
+
+    /**
+     * Sets a user specific value for {@link GenericObjectPool#getTestWhileIdle()} for the specified user's pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @param value
+     *            The user specific value.
+     */
+    public void setPerUserTestWhileIdle(final String userName, final Boolean value) {
+        assertInitializationAllowed();
+        if (perUserTestWhileIdle == null) {
+            perUserTestWhileIdle = createMap();
+        }
+        perUserTestWhileIdle.put(userName, value);
+    }
+
+    void setPerUserTimeBetweenEvictionRunsMillis(final Map<String, Long> userDefaultTimeBetweenEvictionRunsMillis) {
+        assertInitializationAllowed();
+        if (perUserTimeBetweenEvictionRunsMillis == null) {
+            perUserTimeBetweenEvictionRunsMillis = new HashMap<>();
+        } else {
+            perUserTimeBetweenEvictionRunsMillis.clear();
+        }
+        perUserTimeBetweenEvictionRunsMillis.putAll(userDefaultTimeBetweenEvictionRunsMillis);
+    }
+
+    /**
+     * Sets a user specific value for {@link GenericObjectPool#getTimeBetweenEvictionRunsMillis ()} for the specified
+     * user's pool.
+     *
+     * @param userName
+     *            The user name key.
+     * @param value
+     *            The user specific value.
+     */
+    public void setPerUserTimeBetweenEvictionRunsMillis(final String userName, final Long value) {
+        assertInitializationAllowed();
+        if (perUserTimeBetweenEvictionRunsMillis == null) {
+            perUserTimeBetweenEvictionRunsMillis = new HashMap<>();
+        }
+        perUserTimeBetweenEvictionRunsMillis.put(userName, value);
     }
 
     @Override
-    protected void setupDefaults(final Connection con, final String username)
-        throws SQLException {
+    protected void setupDefaults(final Connection con, final String userName) throws SQLException {
         Boolean defaultAutoCommit = isDefaultAutoCommit();
-        if (username != null) {
-            final Boolean userMax = getPerUserDefaultAutoCommit(username);
+        if (userName != null) {
+            final Boolean userMax = getPerUserDefaultAutoCommit(userName);
             if (userMax != null) {
                 defaultAutoCommit = userMax;
             }
         }
 
         Boolean defaultReadOnly = isDefaultReadOnly();
-        if (username != null) {
-            final Boolean userMax = getPerUserDefaultReadOnly(username);
+        if (userName != null) {
+            final Boolean userMax = getPerUserDefaultReadOnly(userName);
             if (userMax != null) {
                 defaultReadOnly = userMax;
             }
         }
 
         int defaultTransactionIsolation = getDefaultTransactionIsolation();
-        if (username != null) {
-            final Integer userMax = getPerUserDefaultTransactionIsolation(username);
+        if (userName != null) {
+            final Integer userMax = getPerUserDefaultTransactionIsolation(userName);
             if (userMax != null) {
                 defaultTransactionIsolation = userMax.intValue();
             }
         }
 
-        if (defaultAutoCommit != null &&
-                con.getAutoCommit() != defaultAutoCommit.booleanValue()) {
+        if (defaultAutoCommit != null && con.getAutoCommit() != defaultAutoCommit.booleanValue()) {
             con.setAutoCommit(defaultAutoCommit.booleanValue());
         }
 
@@ -972,116 +1169,8 @@
             con.setTransactionIsolation(defaultTransactionIsolation);
         }
 
-        if (defaultReadOnly != null &&
-                con.isReadOnly() != defaultReadOnly.booleanValue()) {
+        if (defaultReadOnly != null && con.isReadOnly() != defaultReadOnly.booleanValue()) {
             con.setReadOnly(defaultReadOnly.booleanValue());
         }
     }
-
-    @Override
-    protected PooledConnectionManager getConnectionManager(final UserPassKey upkey) {
-        return managers.get(getPoolKey(upkey.getUsername()));
-    }
-
-    /**
-     * Returns a <code>PerUserPoolDataSource</code> {@link Reference}.
-     */
-    @Override
-    public Reference getReference() throws NamingException {
-        final Reference ref = new Reference(getClass().getName(),
-                PerUserPoolDataSourceFactory.class.getName(), null);
-        ref.add(new StringRefAddr("instanceKey", getInstanceKey()));
-        return ref;
-    }
-
-    /**
-     * Create a pool key from the provided parameters.
-     *
-     * @param username  User name
-     * @return  The pool key
-     */
-    private PoolKey getPoolKey(final String username) {
-        return new PoolKey(getDataSourceName(), username);
-    }
-
-    private synchronized void registerPool(final String username, final String password)
-            throws NamingException, SQLException {
-
-        final ConnectionPoolDataSource cpds = testCPDS(username, password);
-
-        // Set up the factory we will use (passing the pool associates
-        // the factory with the pool, so we do not have to do so
-        // explicitly)
-        final CPDSConnectionFactory factory = new CPDSConnectionFactory(cpds,
-                getValidationQuery(), getValidationQueryTimeout(),
-                isRollbackAfterValidation(), username, password);
-        factory.setMaxConnLifetimeMillis(getMaxConnLifetimeMillis());
-
-        // Create an object pool to contain our PooledConnections
-        final GenericObjectPool<PooledConnectionAndInfo> pool =
-                new GenericObjectPool<>(factory);
-        factory.setPool(pool);
-        pool.setBlockWhenExhausted(getPerUserBlockWhenExhausted(username));
-        pool.setEvictionPolicyClassName(
-                getPerUserEvictionPolicyClassName(username));
-        pool.setLifo(getPerUserLifo(username));
-        pool.setMaxIdle(getPerUserMaxIdle(username));
-        pool.setMaxTotal(getPerUserMaxTotal(username));
-        pool.setMaxWaitMillis(getPerUserMaxWaitMillis(username));
-        pool.setMinEvictableIdleTimeMillis(
-                getPerUserMinEvictableIdleTimeMillis(username));
-        pool.setMinIdle(getPerUserMinIdle(username));
-        pool.setNumTestsPerEvictionRun(
-                getPerUserNumTestsPerEvictionRun(username));
-        pool.setSoftMinEvictableIdleTimeMillis(
-                getPerUserSoftMinEvictableIdleTimeMillis(username));
-        pool.setTestOnCreate(getPerUserTestOnCreate(username));
-        pool.setTestOnBorrow(getPerUserTestOnBorrow(username));
-        pool.setTestOnReturn(getPerUserTestOnReturn(username));
-        pool.setTestWhileIdle(getPerUserTestWhileIdle(username));
-        pool.setTimeBetweenEvictionRunsMillis(
-                getPerUserTimeBetweenEvictionRunsMillis(username));
-
-        pool.setSwallowedExceptionListener(new SwallowedExceptionLogger(log));
-
-        final Object old = managers.put(getPoolKey(username), factory);
-        if (old != null) {
-            throw new IllegalStateException("Pool already contains an entry for this user/password: " + username);
-        }
-    }
-
-    /**
-     * Supports Serialization interface.
-     *
-     * @param in a <code>java.io.ObjectInputStream</code> value
-     * @throws IOException if an error occurs
-     * @throws ClassNotFoundException if an error occurs
-     */
-    private void readObject(final ObjectInputStream in)
-        throws IOException, ClassNotFoundException {
-        try
-        {
-            in.defaultReadObject();
-            final PerUserPoolDataSource oldDS = (PerUserPoolDataSource)
-                new PerUserPoolDataSourceFactory()
-                    .getObjectInstance(getReference(), null, null, null);
-            this.managers = oldDS.managers;
-        }
-        catch (final NamingException e)
-        {
-            throw new IOException("NamingException: " + e);
-        }
-    }
-
-    /**
-     * Returns the object pool associated with the given PoolKey.
-     *
-     * @param key PoolKey identifying the pool
-     * @return the GenericObjectPool pooling connections for the username and datasource
-     * specified by the PoolKey
-     */
-    private ObjectPool<PooledConnectionAndInfo> getPool(final PoolKey key) {
-        final CPDSConnectionFactory mgr = (CPDSConnectionFactory) managers.get(key);
-        return mgr == null ? null : mgr.getPool();
-    }
 }
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/datasources/PerUserPoolDataSourceFactory.java b/java/org/apache/tomcat/dbcp/dbcp2/datasources/PerUserPoolDataSourceFactory.java
index d45396f..30791a9 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/datasources/PerUserPoolDataSourceFactory.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/datasources/PerUserPoolDataSourceFactory.java
@@ -28,11 +28,8 @@
  *
  * @since 2.0
  */
-public class PerUserPoolDataSourceFactory
-    extends InstanceKeyDataSourceFactory
-{
-    private static final String PER_USER_POOL_CLASSNAME =
-        PerUserPoolDataSource.class.getName();
+public class PerUserPoolDataSourceFactory extends InstanceKeyDataSourceFactory {
+    private static final String PER_USER_POOL_CLASSNAME = PerUserPoolDataSource.class.getName();
 
     @Override
     protected boolean isCorrectClass(final String className) {
@@ -41,69 +38,58 @@
 
     @SuppressWarnings("unchecked") // Avoid warnings on deserialization
     @Override
-    protected InstanceKeyDataSource getNewInstance(final Reference ref)
-        throws IOException, ClassNotFoundException {
-        final PerUserPoolDataSource pupds =  new PerUserPoolDataSource();
+    protected InstanceKeyDataSource getNewInstance(final Reference ref) throws IOException, ClassNotFoundException {
+        final PerUserPoolDataSource pupds = new PerUserPoolDataSource();
         RefAddr ra = ref.get("defaultMaxTotal");
         if (ra != null && ra.getContent() != null) {
-            pupds.setDefaultMaxTotal(
-                Integer.parseInt(ra.getContent().toString()));
+            pupds.setDefaultMaxTotal(Integer.parseInt(ra.getContent().toString()));
         }
 
         ra = ref.get("defaultMaxIdle");
         if (ra != null && ra.getContent() != null) {
-            pupds.setDefaultMaxIdle(
-                Integer.parseInt(ra.getContent().toString()));
+            pupds.setDefaultMaxIdle(Integer.parseInt(ra.getContent().toString()));
         }
 
         ra = ref.get("defaultMaxWaitMillis");
         if (ra != null && ra.getContent() != null) {
-            pupds.setDefaultMaxWaitMillis(
-                Integer.parseInt(ra.getContent().toString()));
+            pupds.setDefaultMaxWaitMillis(Integer.parseInt(ra.getContent().toString()));
         }
 
         ra = ref.get("perUserDefaultAutoCommit");
-        if (ra != null  && ra.getContent() != null) {
+        if (ra != null && ra.getContent() != null) {
             final byte[] serialized = (byte[]) ra.getContent();
-            pupds.setPerUserDefaultAutoCommit(
-                    (Map<String,Boolean>) deserialize(serialized));
+            pupds.setPerUserDefaultAutoCommit((Map<String, Boolean>) deserialize(serialized));
         }
 
         ra = ref.get("perUserDefaultTransactionIsolation");
-        if (ra != null  && ra.getContent() != null) {
+        if (ra != null && ra.getContent() != null) {
             final byte[] serialized = (byte[]) ra.getContent();
-            pupds.setPerUserDefaultTransactionIsolation(
-                    (Map<String,Integer>) deserialize(serialized));
+            pupds.setPerUserDefaultTransactionIsolation((Map<String, Integer>) deserialize(serialized));
         }
 
         ra = ref.get("perUserMaxTotal");
-        if (ra != null  && ra.getContent() != null) {
+        if (ra != null && ra.getContent() != null) {
             final byte[] serialized = (byte[]) ra.getContent();
-            pupds.setPerUserMaxTotal(
-                    (Map<String,Integer>) deserialize(serialized));
+            pupds.setPerUserMaxTotal((Map<String, Integer>) deserialize(serialized));
         }
 
         ra = ref.get("perUserMaxIdle");
-        if (ra != null  && ra.getContent() != null) {
+        if (ra != null && ra.getContent() != null) {
             final byte[] serialized = (byte[]) ra.getContent();
-            pupds.setPerUserMaxIdle(
-                    (Map<String,Integer>) deserialize(serialized));
+            pupds.setPerUserMaxIdle((Map<String, Integer>) deserialize(serialized));
         }
 
         ra = ref.get("perUserMaxWaitMillis");
-        if (ra != null  && ra.getContent() != null) {
+        if (ra != null && ra.getContent() != null) {
             final byte[] serialized = (byte[]) ra.getContent();
-            pupds.setPerUserMaxWaitMillis(
-                    (Map<String,Long>) deserialize(serialized));
+            pupds.setPerUserMaxWaitMillis((Map<String, Long>) deserialize(serialized));
         }
 
         ra = ref.get("perUserDefaultReadOnly");
-        if (ra != null  && ra.getContent() != null) {
+        if (ra != null && ra.getContent() != null) {
             final byte[] serialized = (byte[]) ra.getContent();
-            pupds.setPerUserDefaultReadOnly(
-                    (Map<String,Boolean>) deserialize(serialized));
+            pupds.setPerUserDefaultReadOnly((Map<String, Boolean>) deserialize(serialized));
         }
         return pupds;
     }
 }
-
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/datasources/PoolKey.java b/java/org/apache/tomcat/dbcp/dbcp2/datasources/PoolKey.java
index 8dcf148..f38e04f 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/datasources/PoolKey.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/datasources/PoolKey.java
@@ -25,41 +25,57 @@
 class PoolKey implements Serializable {
     private static final long serialVersionUID = 2252771047542484533L;
 
-    private final String datasourceName;
-    private final String username;
+    private final String dataSourceName;
+    private final String userName;
 
-    PoolKey(final String datasourceName, final String username) {
-        this.datasourceName = datasourceName;
-        this.username = username;
+    PoolKey(final String dataSourceName, final String userName) {
+        this.dataSourceName = dataSourceName;
+        this.userName = userName;
     }
 
     @Override
     public boolean equals(final Object obj) {
-        if (obj instanceof PoolKey) {
-            final PoolKey pk = (PoolKey)obj;
-            return (null == datasourceName ? null == pk.datasourceName : datasourceName.equals(pk.datasourceName)) &&
-                (null == username ? null == pk.username : username.equals(pk.username));
+        if (this == obj) {
+            return true;
         }
-        return false;
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        final PoolKey other = (PoolKey) obj;
+        if (dataSourceName == null) {
+            if (other.dataSourceName != null) {
+                return false;
+            }
+        } else if (!dataSourceName.equals(other.dataSourceName)) {
+            return false;
+        }
+        if (userName == null) {
+            if (other.userName != null) {
+                return false;
+            }
+        } else if (!userName.equals(other.userName)) {
+            return false;
+        }
+        return true;
     }
 
     @Override
     public int hashCode() {
-        int h = 0;
-        if (datasourceName != null) {
-            h += datasourceName.hashCode();
-        }
-        if (username != null) {
-            h = 29 * h + username.hashCode();
-        }
-        return h;
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((dataSourceName == null) ? 0 : dataSourceName.hashCode());
+        result = prime * result + ((userName == null) ? 0 : userName.hashCode());
+        return result;
     }
 
     @Override
     public String toString() {
         final StringBuffer sb = new StringBuffer(50);
         sb.append("PoolKey(");
-        sb.append(username).append(", ").append(datasourceName);
+        sb.append(userName).append(", ").append(dataSourceName);
         sb.append(')');
         return sb.toString();
     }
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/datasources/PooledConnectionAndInfo.java b/java/org/apache/tomcat/dbcp/dbcp2/datasources/PooledConnectionAndInfo.java
index 6475986..1fb1ccf 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/datasources/PooledConnectionAndInfo.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/datasources/PooledConnectionAndInfo.java
@@ -19,23 +19,36 @@
 
 import javax.sql.PooledConnection;
 
+import org.apache.tomcat.dbcp.dbcp2.Utils;
+
 /**
- * Immutable poolable object holding a PooledConnection along with the username and password
- * used to create the connection.
+ * Immutable poolable object holding a PooledConnection along with the user name and password used to create the
+ * connection.
  *
  * @since 2.0
  */
 final class PooledConnectionAndInfo {
     private final PooledConnection pooledConnection;
-    private final String password;
-    private final String username;
-    private final UserPassKey upkey;
+    private final char[] userPassword;
+    private final String userName;
+    private final UserPassKey upKey;
 
-    PooledConnectionAndInfo(final PooledConnection pc, final String username, final String password) {
+    /**
+     * @since 2.4.0
+     */
+    PooledConnectionAndInfo(final PooledConnection pc, final String userName, final char[] userPassword) {
         this.pooledConnection = pc;
-        this.username = username;
-        this.password = password;
-        upkey = new UserPassKey(username, password);
+        this.userName = userName;
+        this.userPassword = userPassword;
+        this.upKey = new UserPassKey(userName, userPassword);
+    }
+
+    /**
+     * @deprecated Since 2.4.0
+     */
+    @Deprecated
+    PooledConnectionAndInfo(final PooledConnection pc, final String userName, final String userPassword) {
+        this(pc, userName, Utils.toCharArray(userPassword));
     }
 
     PooledConnection getPooledConnection() {
@@ -43,22 +56,34 @@
     }
 
     UserPassKey getUserPassKey() {
-        return upkey;
+        return upKey;
     }
 
     /**
-     * Get the value of password.
+     * Gets the value of password.
+     *
      * @return value of password.
      */
     String getPassword() {
-        return password;
+        return Utils.toString(userPassword);
     }
 
     /**
-     * Get the value of username.
-     * @return value of username.
+     * Gets the value of password.
+     *
+     * @return value of password.
+     * @since 2.4.0
+     */
+    char[] getPasswordCharArray() {
+        return userPassword;
+    }
+
+    /**
+     * Gets the value of userName.
+     *
+     * @return value of userName.
      */
     String getUsername() {
-        return username;
+        return userName;
     }
 }
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/datasources/PooledConnectionManager.java b/java/org/apache/tomcat/dbcp/dbcp2/datasources/PooledConnectionManager.java
index b4da094..fc6bff8 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/datasources/PooledConnectionManager.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/datasources/PooledConnectionManager.java
@@ -27,29 +27,41 @@
  * @since 2.0
  */
 interface PooledConnectionManager {
+
     /**
-     * Close the PooledConnection and remove it from the connection pool
-     * to which it belongs, adjusting pool counters.
+     * Closes the PooledConnection and remove it from the connection pool to which it belongs, adjusting pool counters.
      *
-     * @param pc PooledConnection to be invalidated
-     * @throws SQLException if an SQL error occurs closing the connection
+     * @param pc
+     *            PooledConnection to be invalidated
+     * @throws SQLException
+     *             if an SQL error occurs closing the connection
      */
     void invalidate(PooledConnection pc) throws SQLException;
 
+    // /**
+    // * Sets the database password used when creating connections.
+    // *
+    // * @param password password used when authenticating to the database
+    // * @since 3.0.0
+    // */
+    // void setPassword(char[] password);
+
     /**
      * Sets the database password used when creating connections.
      *
-     * @param password password used when authenticating to the database
+     * @param password
+     *            password used when authenticating to the database
      */
     void setPassword(String password);
 
-
     /**
      * Closes the connection pool associated with the given user.
      *
-     * @param username user name
-     * @throws SQLException if an error occurs closing idle connections in the pool
+     * @param userName
+     *            user name
+     * @throws SQLException
+     *             if an error occurs closing idle connections in the pool
      */
-    void closePool(String username) throws SQLException;
+    void closePool(String userName) throws SQLException;
 
 }
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/datasources/SharedPoolDataSource.java b/java/org/apache/tomcat/dbcp/dbcp2/datasources/SharedPoolDataSource.java
index a8286b4..a006f4a 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/datasources/SharedPoolDataSource.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/datasources/SharedPoolDataSource.java
@@ -32,20 +32,20 @@
 import org.apache.tomcat.dbcp.pool2.impl.GenericKeyedObjectPoolConfig;
 
 /**
- * <p>A pooling <code>DataSource</code> appropriate for deployment within
- * J2EE environment.  There are many configuration options, most of which are
- * defined in the parent class. All users (based on username) share a single
- * maximum number of Connections in this datasource.</p>
+ * <p>
+ * A pooling <code>DataSource</code> appropriate for deployment within J2EE environment. There are many configuration
+ * options, most of which are defined in the parent class. All users (based on user name) share a single maximum number
+ * of Connections in this data source.
+ * </p>
  *
- * <p>User passwords can be changed without re-initializing the datasource.
- * When a <code>getConnection(username, password)</code> request is processed
- * with a password that is different from those used to create connections in the
- * pool associated with <code>username</code>, an attempt is made to create a
- * new connection using the supplied password and if this succeeds, idle connections
- * created using the old password are destroyed and new connections are created
- * using the new password.</p>
+ * <p>
+ * User passwords can be changed without re-initializing the data source. When a
+ * <code>getConnection(user name, password)</code> request is processed with a password that is different from those
+ * used to create connections in the pool associated with <code>user name</code>, an attempt is made to create a new
+ * connection using the supplied password and if this succeeds, idle connections created using the old password are
+ * destroyed and new connections are created using the new password.
+ * </p>
  *
- * @author John D. McNally
  * @since 2.0
  */
 public class SharedPoolDataSource extends InstanceKeyDataSource {
@@ -55,18 +55,18 @@
     // Pool properties
     private int maxTotal = GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL;
 
-
-    private transient KeyedObjectPool<UserPassKey,PooledConnectionAndInfo> pool = null;
-    private transient KeyedCPDSConnectionFactory factory = null;
+    private transient KeyedObjectPool<UserPassKey, PooledConnectionAndInfo> pool;
+    private transient KeyedCPDSConnectionFactory factory;
 
     /**
-     * Default no-arg constructor for Serialization
+     * Default no-argument constructor for Serialization
      */
     public SharedPoolDataSource() {
+        // empty.
     }
 
     /**
-     * Close pool being maintained by this datasource.
+     * Closes pool being maintained by this data source.
      */
     @Override
     public void close() throws Exception {
@@ -76,38 +76,45 @@
         InstanceKeyDataSourceFactory.removeInstance(getInstanceKey());
     }
 
-
     // -------------------------------------------------------------------
     // Properties
 
     /**
-     * Set {@link GenericKeyedObjectPool#getMaxTotal()} for this pool.
+     * Gets {@link GenericKeyedObjectPool#getMaxTotal()} for this pool.
+     *
+     * @return {@link GenericKeyedObjectPool#getMaxTotal()} for this pool.
      */
     public int getMaxTotal() {
         return this.maxTotal;
     }
 
     /**
-     * Get {@link GenericKeyedObjectPool#getMaxTotal()} for this pool.
+     * Sets {@link GenericKeyedObjectPool#getMaxTotal()} for this pool.
+     *
+     * @param maxTotal
+     *            {@link GenericKeyedObjectPool#getMaxTotal()} for this pool.
      */
     public void setMaxTotal(final int maxTotal) {
         assertInitializationAllowed();
         this.maxTotal = maxTotal;
     }
 
-
     // ----------------------------------------------------------------------
     // Instrumentation Methods
 
     /**
-     * Get the number of active connections in the pool.
+     * Gets the number of active connections in the pool.
+     *
+     * @return The number of active connections in the pool.
      */
     public int getNumActive() {
         return pool == null ? 0 : pool.getNumActive();
     }
 
     /**
-     * Get the number of idle connections in the pool.
+     * Gets the number of idle connections in the pool.
+     *
+     * @return The number of idle connections in the pool.
      */
     public int getNumIdle() {
         return pool == null ? 0 : pool.getNumIdle();
@@ -117,14 +124,13 @@
     // Inherited abstract methods
 
     @Override
-    protected PooledConnectionAndInfo
-        getPooledConnectionAndInfo(final String username, final String password)
-        throws SQLException {
+    protected PooledConnectionAndInfo getPooledConnectionAndInfo(final String userName, final String userPassword)
+            throws SQLException {
 
-        synchronized(this) {
+        synchronized (this) {
             if (pool == null) {
                 try {
-                    registerPool(username, password);
+                    registerPool(userName, userPassword);
                 } catch (final NamingException e) {
                     throw new SQLException("RegisterPool failed", e);
                 }
@@ -133,20 +139,18 @@
 
         PooledConnectionAndInfo info = null;
 
-        final UserPassKey key = new UserPassKey(username, password);
+        final UserPassKey key = new UserPassKey(userName, userPassword);
 
         try {
             info = pool.borrowObject(key);
-        }
-        catch (final Exception e) {
-            throw new SQLException(
-                    "Could not retrieve connection info from pool", e);
+        } catch (final Exception e) {
+            throw new SQLException("Could not retrieve connection info from pool", e);
         }
         return info;
     }
 
     @Override
-    protected PooledConnectionManager getConnectionManager(final UserPassKey upkey)  {
+    protected PooledConnectionManager getConnectionManager(final UserPassKey upkey) {
         return factory;
     }
 
@@ -155,24 +159,21 @@
      */
     @Override
     public Reference getReference() throws NamingException {
-        final Reference ref = new Reference(getClass().getName(),
-            SharedPoolDataSourceFactory.class.getName(), null);
+        final Reference ref = new Reference(getClass().getName(), SharedPoolDataSourceFactory.class.getName(), null);
         ref.add(new StringRefAddr("instanceKey", getInstanceKey()));
         return ref;
     }
 
-    private void registerPool(final String username, final String password)
-            throws NamingException, SQLException {
+    private void registerPool(final String userName, final String password) throws NamingException, SQLException {
 
-        final ConnectionPoolDataSource cpds = testCPDS(username, password);
+        final ConnectionPoolDataSource cpds = testCPDS(userName, password);
 
         // Create an object pool to contain our PooledConnections
-        factory = new KeyedCPDSConnectionFactory(cpds, getValidationQuery(),
-                getValidationQueryTimeout(), isRollbackAfterValidation());
+        factory = new KeyedCPDSConnectionFactory(cpds, getValidationQuery(), getValidationQueryTimeout(),
+                isRollbackAfterValidation());
         factory.setMaxConnLifetimeMillis(getMaxConnLifetimeMillis());
 
-        final GenericKeyedObjectPoolConfig<PooledConnectionAndInfo> config =
-                new GenericKeyedObjectPoolConfig<>();
+        final GenericKeyedObjectPoolConfig config = new GenericKeyedObjectPoolConfig();
         config.setBlockWhenExhausted(getDefaultBlockWhenExhausted());
         config.setEvictionPolicyClassName(getDefaultEvictionPolicyClassName());
         config.setLifo(getDefaultLifo());
@@ -180,66 +181,58 @@
         config.setMaxTotal(getMaxTotal());
         config.setMaxTotalPerKey(getDefaultMaxTotal());
         config.setMaxWaitMillis(getDefaultMaxWaitMillis());
-        config.setMinEvictableIdleTimeMillis(
-                getDefaultMinEvictableIdleTimeMillis());
+        config.setMinEvictableIdleTimeMillis(getDefaultMinEvictableIdleTimeMillis());
         config.setMinIdlePerKey(getDefaultMinIdle());
         config.setNumTestsPerEvictionRun(getDefaultNumTestsPerEvictionRun());
-        config.setSoftMinEvictableIdleTimeMillis(
-                getDefaultSoftMinEvictableIdleTimeMillis());
+        config.setSoftMinEvictableIdleTimeMillis(getDefaultSoftMinEvictableIdleTimeMillis());
         config.setTestOnCreate(getDefaultTestOnCreate());
         config.setTestOnBorrow(getDefaultTestOnBorrow());
         config.setTestOnReturn(getDefaultTestOnReturn());
         config.setTestWhileIdle(getDefaultTestWhileIdle());
-        config.setTimeBetweenEvictionRunsMillis(
-                getDefaultTimeBetweenEvictionRunsMillis());
+        config.setTimeBetweenEvictionRunsMillis(getDefaultTimeBetweenEvictionRunsMillis());
 
-        final KeyedObjectPool<UserPassKey,PooledConnectionAndInfo> tmpPool =
-                new GenericKeyedObjectPool<>(factory, config);
+        final KeyedObjectPool<UserPassKey, PooledConnectionAndInfo> tmpPool = new GenericKeyedObjectPool<>(factory,
+                config);
         factory.setPool(tmpPool);
         pool = tmpPool;
     }
 
     @Override
-    protected void setupDefaults(final Connection con, final String username) throws SQLException {
+    protected void setupDefaults(final Connection connection, final String userName) throws SQLException {
         final Boolean defaultAutoCommit = isDefaultAutoCommit();
-        if (defaultAutoCommit != null &&
-                con.getAutoCommit() != defaultAutoCommit.booleanValue()) {
-            con.setAutoCommit(defaultAutoCommit.booleanValue());
+        if (defaultAutoCommit != null && connection.getAutoCommit() != defaultAutoCommit.booleanValue()) {
+            connection.setAutoCommit(defaultAutoCommit.booleanValue());
         }
 
         final int defaultTransactionIsolation = getDefaultTransactionIsolation();
         if (defaultTransactionIsolation != UNKNOWN_TRANSACTIONISOLATION) {
-            con.setTransactionIsolation(defaultTransactionIsolation);
+            connection.setTransactionIsolation(defaultTransactionIsolation);
         }
 
         final Boolean defaultReadOnly = isDefaultReadOnly();
-        if (defaultReadOnly != null &&
-                con.isReadOnly() != defaultReadOnly.booleanValue()) {
-            con.setReadOnly(defaultReadOnly.booleanValue());
+        if (defaultReadOnly != null && connection.isReadOnly() != defaultReadOnly.booleanValue()) {
+            connection.setReadOnly(defaultReadOnly.booleanValue());
         }
     }
 
     /**
      * Supports Serialization interface.
      *
-     * @param in a <code>java.io.ObjectInputStream</code> value
-     * @throws IOException if an error occurs
-     * @throws ClassNotFoundException if an error occurs
+     * @param in
+     *            a <code>java.io.ObjectInputStream</code> value
+     * @throws IOException
+     *             if an error occurs
+     * @throws ClassNotFoundException
+     *             if an error occurs
      */
-    private void readObject(final ObjectInputStream in)
-        throws IOException, ClassNotFoundException {
-        try
-        {
+    private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
+        try {
             in.defaultReadObject();
-            final SharedPoolDataSource oldDS = (SharedPoolDataSource)
-                new SharedPoolDataSourceFactory()
+            final SharedPoolDataSource oldDS = (SharedPoolDataSource) new SharedPoolDataSourceFactory()
                     .getObjectInstance(getReference(), null, null, null);
             this.pool = oldDS.pool;
-        }
-        catch (final NamingException e)
-        {
+        } catch (final NamingException e) {
             throw new IOException("NamingException: " + e);
         }
     }
 }
-
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/datasources/SharedPoolDataSourceFactory.java b/java/org/apache/tomcat/dbcp/dbcp2/datasources/SharedPoolDataSourceFactory.java
index 4ab921f..65bea41 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/datasources/SharedPoolDataSourceFactory.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/datasources/SharedPoolDataSourceFactory.java
@@ -22,13 +22,11 @@
 
 /**
  * A JNDI ObjectFactory which creates <code>SharedPoolDataSource</code>s
+ *
  * @since 2.0
  */
-public class SharedPoolDataSourceFactory
-    extends InstanceKeyDataSourceFactory
-{
-    private static final String SHARED_POOL_CLASSNAME =
-        SharedPoolDataSource.class.getName();
+public class SharedPoolDataSourceFactory extends InstanceKeyDataSourceFactory {
+    private static final String SHARED_POOL_CLASSNAME = SharedPoolDataSource.class.getName();
 
     @Override
     protected boolean isCorrectClass(final String className) {
@@ -40,10 +38,8 @@
         final SharedPoolDataSource spds = new SharedPoolDataSource();
         final RefAddr ra = ref.get("maxTotal");
         if (ra != null && ra.getContent() != null) {
-            spds.setMaxTotal(
-                Integer.parseInt(ra.getContent().toString()));
+            spds.setMaxTotal(Integer.parseInt(ra.getContent().toString()));
         }
         return spds;
     }
 }
-
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/datasources/UserPassKey.java b/java/org/apache/tomcat/dbcp/dbcp2/datasources/UserPassKey.java
index 7313993..4bcf4ab 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/datasources/UserPassKey.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/datasources/UserPassKey.java
@@ -19,85 +19,115 @@
 
 import java.io.Serializable;
 
+import org.apache.tomcat.dbcp.dbcp2.Utils;
+
 /**
- * <p>Holds a username, password pair.  Serves as a poolable object key for the KeyedObjectPool
- * backing a SharedPoolDataSource.  Two instances with the same username are considered equal.
- * This ensures that there will be only one keyed pool for each user in the pool.  The password
- * is used (along with the username) by the KeyedCPDSConnectionFactory when creating new connections.</p>
+ * <p>
+ * Holds a user name and password pair. Serves as a poolable object key for the KeyedObjectPool backing a
+ * SharedPoolDataSource. Two instances with the same user name are considered equal. This ensures that there will be
+ * only one keyed pool for each user in the pool. The password is used (along with the user name) by the
+ * KeyedCPDSConnectionFactory when creating new connections.
+ * </p>
  *
- * <p>{@link InstanceKeyDataSource#getConnection(String, String)} validates that the password used to create
- * a connection matches the password provided by the client.</p>
+ * <p>
+ * {@link InstanceKeyDataSource#getConnection(String, String)} validates that the password used to create a connection
+ * matches the password provided by the client.
+ * </p>
  *
  * @since 2.0
  */
 class UserPassKey implements Serializable {
     private static final long serialVersionUID = 5142970911626584817L;
-    private final String password;
-    private final String username;
-
-    UserPassKey(final String username, final String password) {
-        this.username = username;
-        this.password = password;
-    }
+    private final String userName;
+    private final char[] userPassword;
 
     /**
-     * Get the value of password.
-     * @return value of password.
+     * @since 2.4.0
      */
-    public String getPassword() {
-        return password;
+    UserPassKey(final String userName) {
+        this(userName, (char[]) null);
     }
 
     /**
-     * Get the value of username.
-     * @return value of username.
+     * @since 2.4.0
      */
-    public String getUsername() {
-        return username;
+    UserPassKey(final String userName, final char[] password) {
+        this.userName = userName;
+        this.userPassword = password;
+    }
+
+    UserPassKey(final String userName, final String userPassword) {
+        this(userName, Utils.toCharArray(userPassword));
     }
 
     /**
-     * @return <code>true</code> if the username fields for both
-     * objects are equal.  Two instances with the same username
-     * but different passwords are considered equal.
-     *
-     * @see java.lang.Object#equals(java.lang.Object)
+     * Only takes the user name into account.
      */
     @Override
     public boolean equals(final Object obj) {
+        if (this == obj) {
+            return true;
+        }
         if (obj == null) {
             return false;
         }
-
-        if (obj == this) {
-            return true;
-        }
-
-        if (!(obj instanceof UserPassKey)) {
+        if (getClass() != obj.getClass()) {
             return false;
         }
-
-        final UserPassKey key = (UserPassKey) obj;
-
-        return this.username == null ?
-                key.username == null :
-                this.username.equals(key.username);
+        final UserPassKey other = (UserPassKey) obj;
+        if (userName == null) {
+            if (other.userName != null) {
+                return false;
+            }
+        } else if (!userName.equals(other.userName)) {
+            return false;
+        }
+        return true;
     }
 
     /**
-     * Returns the hash of the username.
+     * Gets the value of password.
+     *
+     * @return value of password.
+     */
+    public String getPassword() {
+        return Utils.toString(userPassword);
+    }
+
+    /**
+     * Gets the value of password.
+     *
+     * @return value of password.
+     */
+    public char[] getPasswordCharArray() {
+        return userPassword;
+    }
+
+    /**
+     * Gets the value of user name.
+     *
+     * @return value of user name.
+     */
+    public String getUsername() {
+        return userName;
+    }
+
+    /**
+     * Only takes the user name into account.
      */
     @Override
     public int hashCode() {
-        return this.username != null ?
-                this.username.hashCode() : 0;
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((userName == null) ? 0 : userName.hashCode());
+        return result;
     }
 
     @Override
     public String toString() {
         final StringBuffer sb = new StringBuffer(50);
         sb.append("UserPassKey(");
-        sb.append(username).append(", ").append(password).append(')');
+        sb.append(userName).append(", ").append(userPassword).append(')');
         return sb.toString();
     }
 }
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/package-info.java b/java/org/apache/tomcat/dbcp/dbcp2/package-info.java
index 24e760c..d63195f 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/package-info.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/package-info.java
@@ -17,114 +17,115 @@
 
 /**
  * <p>
- *    Database Connection Pool API.
+ * Database Connection Pool API.
  * </p>
  *
  * <b>Overview in Dialog Form</b>
  * <p>
- *    Q: How do I use the DBCP package?
- * </p><p>
- *    A: There are two primary ways to access the DBCP pool, as a
- *    {@link java.sql.Driver Driver}, or as a {@link javax.sql.DataSource DataSource}.
- *    You'll want to create an instance of {@link org.apache.tomcat.dbcp.dbcp2.PoolingDriver} or
- *    {@link org.apache.tomcat.dbcp.dbcp2.PoolingDataSource}.  When using one of these
- *    interfaces, you can just use your JDBC objects the way you normally would.
- *    Closing a {@link java.sql.Connection} will simply return it to its pool.
+ * Q: How do I use the DBCP package?
  * </p>
  * <p>
- *    Q: But {@link org.apache.tomcat.dbcp.dbcp2.PoolingDriver PoolingDriver} and
- *    {@link org.apache.tomcat.dbcp.dbcp2.PoolingDataSource PoolingDataSource} both expect an
- *    {@link org.apache.tomcat.dbcp.pool2.ObjectPool ObjectPool} as an input.  Where do I
- *    get one of those?
- * </p><p>
- *    A: The {@link org.apache.tomcat.dbcp.pool2.ObjectPool ObjectPool} interface is defined
- *    in Commons Pool. You can use one of the provided implementations such as
- *    {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool GenericObjectPool} or
- *    {@link org.apache.tomcat.dbcp.pool2.impl.SoftReferenceObjectPool SoftReferenceObjectPool}
- *    or you can create your own.
+ * A: There are two primary ways to access the DBCP pool, as a {@link java.sql.Driver Driver}, or as a
+ * {@link javax.sql.DataSource DataSource}. You'll want to create an instance of
+ * {@link org.apache.tomcat.dbcp.dbcp2.PoolingDriver} or {@link org.apache.tomcat.dbcp.dbcp2.PoolingDataSource}. When using one
+ * of these interfaces, you can just use your JDBC objects the way you normally would. Closing a
+ * {@link java.sql.Connection} will simply return it to its pool.
  * </p>
  * <p>
- *    Q: Ok, I've found an {@link org.apache.tomcat.dbcp.pool2.ObjectPool ObjectPool}
- *    implementation that I think suits my connection pooling needs.  But it wants
- *    a {@link org.apache.tomcat.dbcp.pool2.PooledObjectFactory PooledObjectFactory}.
- *    What should I use for that?
- * </p><p>
- *    A: The DBCP package provides a class for this purpose. It's called
- *    {@link org.apache.tomcat.dbcp.dbcp2.PoolableConnectionFactory}.
- *    It implements the factory and lifecycle methods of
- *    {@link org.apache.tomcat.dbcp.pool2.PooledObjectFactory}
- *    for {@link java.sql.Connection}s.  But it doesn't create the actual database
- *    {@link java.sql.Connection}s itself, it uses a
- *    {@link org.apache.tomcat.dbcp.dbcp2.ConnectionFactory} for that.
- *    The {@link org.apache.tomcat.dbcp.dbcp2.PoolableConnectionFactory} will take
- *    {@link java.sql.Connection}s created by the {@link org.apache.tomcat.dbcp.dbcp2.ConnectionFactory}
- *    and wrap them with classes that implement the pooling behaviour.
- * </p><p>
- *    Several implementations of {@link org.apache.tomcat.dbcp.dbcp2.ConnectionFactory} are
- *    provided--one that uses {@link java.sql.DriverManager} to create connections
- *    ({@link org.apache.tomcat.dbcp.dbcp2.DriverManagerConnectionFactory}),
- *    one that uses a {@link java.sql.Driver} to create connections
- *    ({@link org.apache.tomcat.dbcp.dbcp2.DriverConnectionFactory}),
- *    one that uses a {@link javax.sql.DataSource} to create connections
- *    ({@link org.apache.tomcat.dbcp.dbcp2.DataSourceConnectionFactory}).
+ * Q: But {@link org.apache.tomcat.dbcp.dbcp2.PoolingDriver PoolingDriver} and
+ * {@link org.apache.tomcat.dbcp.dbcp2.PoolingDataSource PoolingDataSource} both expect an
+ * {@link org.apache.tomcat.dbcp.pool2.ObjectPool ObjectPool} as an input. Where do I get one of those?
  * </p>
  * <p>
- *    Q: I think I'm starting to get it, but can you walk me though it again?
- * </p><p>
- *    A: Sure.  Let's assume you want to create a {@link javax.sql.DataSource}
- *    that pools {@link java.sql.Connection}s.  Let's also assume that
- *    those pooled {@link java.sql.Connection}s should be obtained from
- *    the {@link java.sql.DriverManager}.
- *    You'll want to create a {@link org.apache.tomcat.dbcp.dbcp2.PoolingDataSource}.
- * </p><p>
- *    The {@link org.apache.tomcat.dbcp.dbcp2.PoolingDataSource} uses an underlying
- *    {@link org.apache.tomcat.dbcp.pool2.ObjectPool} to create and store its
- *    {@link java.sql.Connection}.
- * </p><p>
- *    To create a {@link org.apache.tomcat.dbcp.pool2.ObjectPool}, you'll need
- *    a {@link org.apache.tomcat.dbcp.pool2.PooledObjectFactory} that creates
- *    the actual {@link java.sql.Connection}s.  That's what
- *    {@link org.apache.tomcat.dbcp.dbcp2.PoolableConnectionFactory} is for.
- * </p><p>
- *    To create the {@link org.apache.tomcat.dbcp.dbcp2.PoolableConnectionFactory},
- *    you'll need at least two things:</p>
- *    <ol>
- *     <li>
- * A {@link org.apache.tomcat.dbcp.dbcp2.ConnectionFactory} from which
- * the actual database {@link java.sql.Connection}s will be obtained.
- *     </li>
- *     <li>
- * An empty and factory-less {@link org.apache.tomcat.dbcp.pool2.ObjectPool}
- * in which the {@link java.sql.Connection}s will be stored.
- * <br>
+ * A: The {@link org.apache.tomcat.dbcp.pool2.ObjectPool ObjectPool} interface is defined in Commons Pool. You can use one
+ * of the provided implementations such as {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool GenericObjectPool} or
+ * {@link org.apache.tomcat.dbcp.pool2.impl.SoftReferenceObjectPool SoftReferenceObjectPool} or you can create your own.
+ * </p>
+ * <p>
+ * Q: Ok, I've found an {@link org.apache.tomcat.dbcp.pool2.ObjectPool ObjectPool} implementation that I think suits my
+ * connection pooling needs. But it wants a {@link org.apache.tomcat.dbcp.pool2.PooledObjectFactory PooledObjectFactory}.
+ * What should I use for that?
+ * </p>
+ * <p>
+ * A: The DBCP package provides a class for this purpose. It's called
+ * {@link org.apache.tomcat.dbcp.dbcp2.PoolableConnectionFactory}. It implements the factory and lifecycle methods of
+ * {@link org.apache.tomcat.dbcp.pool2.PooledObjectFactory} for {@link java.sql.Connection}s. But it doesn't create the
+ * actual database {@link java.sql.Connection}s itself, it uses a {@link org.apache.tomcat.dbcp.dbcp2.ConnectionFactory} for
+ * that. The {@link org.apache.tomcat.dbcp.dbcp2.PoolableConnectionFactory} will take {@link java.sql.Connection}s created
+ * by the {@link org.apache.tomcat.dbcp.dbcp2.ConnectionFactory} and wrap them with classes that implement the pooling
+ * behaviour.
+ * </p>
+ * <p>
+ * Several implementations of {@link org.apache.tomcat.dbcp.dbcp2.ConnectionFactory} are provided--one that uses
+ * {@link java.sql.DriverManager} to create connections
+ * ({@link org.apache.tomcat.dbcp.dbcp2.DriverManagerConnectionFactory}), one that uses a {@link java.sql.Driver} to create
+ * connections ({@link org.apache.tomcat.dbcp.dbcp2.DriverConnectionFactory}), one that uses a {@link javax.sql.DataSource}
+ * to create connections ({@link org.apache.tomcat.dbcp.dbcp2.DataSourceConnectionFactory}).
+ * </p>
+ * <p>
+ * Q: I think I'm starting to get it, but can you walk me though it again?
+ * </p>
+ * <p>
+ * A: Sure. Let's assume you want to create a {@link javax.sql.DataSource} that pools {@link java.sql.Connection}s.
+ * Let's also assume that those pooled {@link java.sql.Connection}s should be obtained from the
+ * {@link java.sql.DriverManager}. You'll want to create a {@link org.apache.tomcat.dbcp.dbcp2.PoolingDataSource}.
+ * </p>
+ * <p>
+ * The {@link org.apache.tomcat.dbcp.dbcp2.PoolingDataSource} uses an underlying {@link org.apache.tomcat.dbcp.pool2.ObjectPool}
+ * to create and store its {@link java.sql.Connection}.
+ * </p>
+ * <p>
+ * To create a {@link org.apache.tomcat.dbcp.pool2.ObjectPool}, you'll need a
+ * {@link org.apache.tomcat.dbcp.pool2.PooledObjectFactory} that creates the actual {@link java.sql.Connection}s. That's
+ * what {@link org.apache.tomcat.dbcp.dbcp2.PoolableConnectionFactory} is for.
+ * </p>
+ * <p>
+ * To create the {@link org.apache.tomcat.dbcp.dbcp2.PoolableConnectionFactory}, you'll need at least two things:
+ * </p>
+ * <ol>
+ * <li>A {@link org.apache.tomcat.dbcp.dbcp2.ConnectionFactory} from which the actual database {@link java.sql.Connection}s
+ * will be obtained.</li>
+ * <li>An empty and factory-less {@link org.apache.tomcat.dbcp.pool2.ObjectPool} in which the {@link java.sql.Connection}s
+ * will be stored. <br>
  * When you pass an {@link org.apache.tomcat.dbcp.pool2.ObjectPool} into the
- * {@link org.apache.tomcat.dbcp.dbcp2.PoolableConnectionFactory}, it will
- * automatically register itself as the {@link org.apache.tomcat.dbcp.pool2.PooledObjectFactory}
- * for that pool.
- *     </li>
- *    </ol>
+ * {@link org.apache.tomcat.dbcp.dbcp2.PoolableConnectionFactory}, it will automatically register itself as the
+ * {@link org.apache.tomcat.dbcp.pool2.PooledObjectFactory} for that pool.</li>
+ * </ol>
  * <p>
- *    In code, that might look like this:
+ * In code, that might look like this:
  * </p>
- * <pre>GenericObjectPool connectionPool = new GenericObjectPool(null);
- * ConnectionFactory connectionFactory = new DriverManagerConnectionFactory("jdbc:some:connect:string", "username", "password");
- * PoolableConnectionFactory poolableConnectionFactory = new PoolableConnectionFactory(connectionFactory,connectionPool,null,null,false,true);
- * PoolingDataSource dataSource = new PoolingDataSource(connectionPool);</pre>
+ *
+ * <pre>
+ * GenericObjectPool connectionPool = new GenericObjectPool(null);
+ * ConnectionFactory connectionFactory = new DriverManagerConnectionFactory("jdbc:some:connect:string", "userName",
+ *         "password");
+ * PoolableConnectionFactory poolableConnectionFactory = new PoolableConnectionFactory(connectionFactory,
+ *         connectionPool, null, null, false, true);
+ * PoolingDataSource dataSource = new PoolingDataSource(connectionPool);
+ * </pre>
  * <p>
- *    To create a {@link org.apache.tomcat.dbcp.dbcp2.PoolingDriver}, we do the same thing,
- *    except that instead of creating a {@link javax.sql.DataSource} on the last line,
- *    we create a {@link org.apache.tomcat.dbcp.dbcp2.PoolingDriver}, and register the
- *    {@code connectionPool} with it.  E.g.,:</p>
- * <pre>GenericObjectPool connectionPool = new GenericObjectPool(null);
- * ConnectionFactory connectionFactory = new DriverManagerConnectionFactory("jdbc:some:connect:string", "username", "password");
- * PoolableConnectionFactory poolableConnectionFactory = new PoolableConnectionFactory(connectionFactory,connectionPool,null,null,false,true);
+ * To create a {@link org.apache.tomcat.dbcp.dbcp2.PoolingDriver}, we do the same thing, except that instead of creating a
+ * {@link javax.sql.DataSource} on the last line, we create a {@link org.apache.tomcat.dbcp.dbcp2.PoolingDriver}, and
+ * register the {@code connectionPool} with it. E.g.,:
+ * </p>
+ *
+ * <pre>
+ * GenericObjectPool connectionPool = new GenericObjectPool(null);
+ * ConnectionFactory connectionFactory = new DriverManagerConnectionFactory("jdbc:some:connect:string", "userName",
+ *         "password");
+ * PoolableConnectionFactory poolableConnectionFactory = new PoolableConnectionFactory(connectionFactory,
+ *         connectionPool, null, null, false, true);
  * PoolingDriver driver = new PoolingDriver();
- * driver.registerPool("example",connectionPool);</pre>
+ * driver.registerPool("example", connectionPool);
+ * </pre>
  * <p>
- *    Since the {@link org.apache.tomcat.dbcp.dbcp2.PoolingDriver} registers itself
- *    with the {@link java.sql.DriverManager} when it is created, now you can just
- *    go to the {@link java.sql.DriverManager} to create your {@link java.sql.Connection}s,
- *    like you normally would:</p>
- * <pre>Connection conn = DriverManager.getConnection("jdbc:apache:commons:dbcp:example");</pre>
+ * Since the {@link org.apache.tomcat.dbcp.dbcp2.PoolingDriver} registers itself with the {@link java.sql.DriverManager}
+ * when it is created, now you can just go to the {@link java.sql.DriverManager} to create your
+ * {@link java.sql.Connection}s, like you normally would:
+ * </p>
+ *
+ * <pre>
+ * Connection conn = DriverManager.getConnection("jdbc:apache:commons:dbcp:example");
+ * </pre>
  */
 package org.apache.tomcat.dbcp.dbcp2;