This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 8.5.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git


The following commit(s) were added to refs/heads/8.5.x by this push:
     new 78b6b58  Update Commons DBCP2
78b6b58 is described below

commit 78b6b58266e495b5cc5d3e64179c5c41f75c6dce
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Thu Aug 1 22:09:08 2019 +0100

    Update Commons DBCP2
---
 MERGE.txt                                          |   2 +-
 .../apache/tomcat/dbcp/dbcp2/AbandonedTrace.java   |  14 +-
 .../apache/tomcat/dbcp/dbcp2/BasicDataSource.java  | 444 ++++++-------
 .../tomcat/dbcp/dbcp2/BasicDataSourceFactory.java  |   9 +-
 .../dbcp/dbcp2/ConnectionFactoryFactory.java       |  77 +++
 .../tomcat/dbcp/dbcp2/DelegatingConnection.java    |  67 +-
 .../tomcat/dbcp/dbcp2/DelegatingResultSet.java     |   4 +-
 .../tomcat/dbcp/dbcp2/DelegatingStatement.java     |  57 +-
 .../tomcat/dbcp/dbcp2/DriverConnectionFactory.java |   2 +
 .../apache/tomcat/dbcp/dbcp2/DriverFactory.java    |  81 +++
 .../org/apache/tomcat/dbcp/dbcp2/Jdbc41Bridge.java |   2 +-
 .../dbcp/dbcp2/PoolableCallableStatement.java      |  29 +-
 .../dbcp/dbcp2/PoolablePreparedStatement.java      |  33 +-
 .../apache/tomcat/dbcp/dbcp2/SQLExceptionList.java |  51 ++
 .../dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java  | 691 +++++++++++----------
 .../dbcp2/cpdsadapter/PooledConnectionImpl.java    |  81 +++
 .../dbcp2/datasources/InstanceKeyDataSource.java   |  20 +-
 .../datasources/InstanceKeyDataSourceFactory.java  |   2 +-
 webapps/docs/changelog.xml                         |   4 +
 19 files changed, 988 insertions(+), 682 deletions(-)

diff --git a/MERGE.txt b/MERGE.txt
index dd72706..396405a 100644
--- a/MERGE.txt
+++ b/MERGE.txt
@@ -63,7 +63,7 @@ Sub-tree
 src/main/java/org/apache/commons/dbcp2
 src/main/resources/org/apache/commons/dbcp2
 The SHA1 ID for the most recent commit to be merged to Tomcat is:
-dcdbc72acf51155d2a6c3f10461d9712a3623686 (2019-04-24)
+87d9e3a66b896d81339a0947d001837ad2651605 (2019-08-01)
 
 Pool2
 Sub-tree
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/AbandonedTrace.java 
b/java/org/apache/tomcat/dbcp/dbcp2/AbandonedTrace.java
index ea6d5a2..3969480 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/AbandonedTrace.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/AbandonedTrace.java
@@ -155,7 +155,7 @@ public class AbandonedTrace implements TrackedUse {
             final Iterator<WeakReference<AbandonedTrace>> iter = 
traceList.iterator();
             while (iter.hasNext()) {
                 final AbandonedTrace traceInList = iter.next().get();
-                if (trace.equals(traceInList)) {
+                if (trace != null && trace.equals(traceInList)) {
                     iter.remove();
                     break;
                 } else if (traceInList == null) {
@@ -165,4 +165,16 @@ public class AbandonedTrace implements TrackedUse {
             }
         }
     }
+
+    /**
+     * Removes this object the source object is tracing.
+     *
+     * @param source The object tracing
+     * @since 2.7.0
+     */
+    protected void removeThisTrace(final Object source) {
+        if (source instanceof AbandonedTrace) {
+            AbandonedTrace.class.cast(source).removeTrace(this);
+        }
+    }
 }
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSource.java 
b/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSource.java
index ba3e38a..6345a22 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSource.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSource.java
@@ -76,8 +76,6 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
 
     private static final Log log = LogFactory.getLog(BasicDataSource.class);
 
-    // ------------------------------------------------------------- Properties
-
     static {
         // Attempt to prevent deadlocks - see DBCP - 272
         DriverManager.getDrivers();
@@ -108,6 +106,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
         }
     }
 
+    @SuppressWarnings("resource")
     protected static void validateConnectionFactory(final 
PoolableConnectionFactory connectionFactory)
             throws Exception {
         PoolableConnection conn = null;
@@ -315,6 +314,11 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
     private volatile int validationQueryTimeoutSeconds = -1;
 
     /**
+     * The fully qualified Java class name of a {@link ConnectionFactory} 
implementation.
+     */
+    private String connectionFactoryClassName;
+
+    /**
      * 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
@@ -380,10 +384,8 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * 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);
@@ -408,8 +410,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * 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 {
@@ -458,77 +459,17 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * 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>
+     * <p>
      * This method exists so subclasses can replace the implementation class.
+     * </p>
      *
      * @return A new connection factory.
      *
-     * @throws SQLException
-     *            If the connection factort cannot be created
+     * @throws SQLException If the connection factort cannot be created
      */
     protected ConnectionFactory createConnectionFactory() throws SQLException {
         // Load the JDBC driver class
-        Driver driverToUse = this.driver;
-
-        if (driverToUse == null) {
-            Class<?> driverFromCCL = null;
-            if (driverClassName != null) {
-                try {
-                    try {
-                        if (driverClassLoader == null) {
-                            driverFromCCL = Class.forName(driverClassName);
-                        } else {
-                            driverFromCCL = Class.forName(driverClassName, 
true, driverClassLoader);
-                        }
-                    } catch (final ClassNotFoundException cnfe) {
-                        driverFromCCL = 
Thread.currentThread().getContextClassLoader().loadClass(driverClassName);
-                    }
-                } catch (final Exception t) {
-                    final String message = "Cannot load JDBC driver class '" + 
driverClassName + "'";
-                    logWriter.println(message);
-                    t.printStackTrace(logWriter);
-                    throw new SQLException(message, t);
-                }
-            }
-
-            try {
-                if (driverFromCCL == null) {
-                    driverToUse = DriverManager.getDriver(url);
-                } else {
-                    // Usage of DriverManager is not possible, as it does not
-                    // respect the ContextClassLoader
-                    // N.B. This cast may cause ClassCastException which is 
handled below
-                    driverToUse = (Driver) 
driverFromCCL.getConstructor().newInstance();
-                    if (!driverToUse.acceptsURL(url)) {
-                        throw new SQLException("No suitable driver", "08001");
-                    }
-                }
-            } catch (final Exception t) {
-                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);
-            }
-        }
-
-        // Set up the driver connection factory we will use
-        final String user = userName;
-        if (user != null) {
-            connectionProperties.put("user", user);
-        } else {
-            log("DBCP DataSource configured without a 'username'");
-        }
-
-        final String pwd = password;
-        if (pwd != null) {
-            connectionProperties.put("password", pwd);
-        } else {
-            log("DBCP DataSource configured without a 'password'");
-        }
-
-        final ConnectionFactory driverConnectionFactory = new 
DriverConnectionFactory(driverToUse, url,
-                connectionProperties);
-        return driverConnectionFactory;
+        return ConnectionFactoryFactory.createConnectionFactory(this, 
DriverFactory.createDriver(this));
     }
 
     /**
@@ -540,8 +481,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * positive value causes {@link GenericObjectPool}'s eviction timer to be 
started.
      * </p>
      *
-     * @param factory
-     *            The factory to use to create new connections for this pool.
+     * @param factory The factory to use to create new connections for this 
pool.
      */
     protected void createConnectionPool(final PoolableConnectionFactory 
factory) {
         // Create an object pool to contain our active connections
@@ -574,8 +514,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * </p>
      *
      * @return The current internal DataSource or a newly created instance if 
it has not yet been created.
-     * @throws SQLException
-     *             if the object pool cannot be created.
+     * @throws SQLException if the object pool cannot be created.
      */
     protected DataSource createDataSource() throws SQLException {
         if (closed) {
@@ -648,7 +587,8 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
                 throw new SQLException("Error preloading the connection pool", 
e);
             }
 
-            // If timeBetweenEvictionRunsMillis > 0, start the pool's evictor 
task
+            // If timeBetweenEvictionRunsMillis > 0, start the pool's evictor
+            // task
             startPoolMaintenance();
 
             dataSource = newDataSource;
@@ -660,8 +600,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * 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
      *
      * @return A new DataSource instance
      */
@@ -674,12 +613,9 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
     /**
      * 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,
@@ -698,10 +634,8 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * 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
      *
      * @return A new PoolableConnectionFactory configured with the current 
configuration of this BasicDataSource
      */
@@ -738,6 +672,17 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
     }
 
     /**
+     * Manually evicts idle connections
+     *
+     * @throws Exception when there is a problem evicting idle objects.
+     */
+    public void evict() throws Exception {
+        if (connectionPool != null) {
+            connectionPool.evict();
+        }
+    }
+
+    /**
      * 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.
@@ -788,8 +733,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
     /**
      * 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
@@ -812,24 +756,34 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
     /**
      * <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
-     *             always thrown.
-     * @throws SQLException
-     *             if a database access error occurs
+     * @throws UnsupportedOperationException 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");
     }
 
     /**
+     * Returns the ConnectionFactoryClassName that has been configured for use 
by this pool.
+     * <p>
+     * Note: This getter only returns the last value set by a call to {@link 
#setConnectionFactoryClassName(String)}.
+     * </p>
+     *
+     * @return the ConnectionFactoryClassName that has been configured for use 
by this pool.
+     * @since 2.7.0
+     */
+    public String getConnectionFactoryClassName() {
+        return this.connectionFactoryClassName;
+    }
+
+    /**
      * 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.
      *
@@ -856,7 +810,6 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
         return connectionPool;
     }
 
-    // For unit testing
     Properties getConnectionProperties() {
         return connectionProperties;
     }
@@ -1096,15 +1049,15 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * 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");
     }
 
@@ -1116,8 +1069,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * 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
@@ -1485,13 +1437,12 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * 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.
+     * @param connection The Connection to invalidate.
      *
-     * @throws IllegalStateException
-     *             if invalidating the connection failed.
+     * @throws IllegalStateException if invalidating the connection failed.
      * @since 2.1
      */
+    @SuppressWarnings("resource")
     public void invalidateConnection(final Connection connection) throws 
IllegalStateException {
         if (connection == null) {
             return;
@@ -1519,18 +1470,6 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
     }
 
     /**
-     * Manually evicts idle connections.
-     *
-     * @throws Exception Thrown by {@link GenericObjectPool#evict()}.
-     * @see GenericObjectPool#evict()
-     */
-    public void evict() throws Exception {
-        if (connectionPool != null) {
-            connectionPool.evict();
-        }
-    }
-
-    /**
      * Returns the value of the accessToUnderlyingConnectionAllowed property.
      *
      * @return true if access to the underlying connection is allowed, false 
otherwise.
@@ -1551,6 +1490,16 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
     }
 
     /**
+     * Delegates in a null-safe manner to {@link String#isEmpty()}.
+     *
+     * @param value the string to test, may be null.
+     * @return boolean false if value is null, otherwise {@link 
String#isEmpty()}.
+     */
+    private boolean isEmpty(String value) {
+        return value == null ? true : value.trim().isEmpty();
+    }
+
+    /**
      * Returns true if we are pooling statements.
      *
      * @return true if prepared and callable statements are pooled
@@ -1588,6 +1537,20 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
         }
     }
 
+    /**
+     * Logs the given throwable.
+     * @param message TODO
+     * @param throwable the throwable.
+     *
+     * @since 2.7.0
+     */
+    protected void log(String message, Throwable throwable) {
+        if (logWriter != null) {
+            logWriter.println(message);
+            throwable.printStackTrace(logWriter);
+        }
+    }
+
     @Override
     public void postDeregister() {
         // NO-OP
@@ -1622,8 +1585,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
     /**
      * 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) {
@@ -1633,8 +1595,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
     /**
      * 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) {
@@ -1652,9 +1613,8 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * 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) {
@@ -1678,8 +1638,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * 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;
@@ -1690,25 +1649,40 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * 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 autoCommitOnReturn
-     *            Whether or not connections being returned to the pool will 
be checked and configured with auto-commit.
+     * @param autoCommitOnReturn Whether or not connections being returned to 
the pool will be checked and configured
+     *                           with auto-commit.
      * @since 2.6.0
      */
     public void setAutoCommitOnReturn(final boolean autoCommitOnReturn) {
         this.autoCommitOnReturn = autoCommitOnReturn;
     }
 
+    // ----------------------------------------------------- DataSource Methods
+
     /**
      * 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;
     }
 
     /**
+     * Sets the ConnectionFactory class name.
+     *
+     * @param connectionFactoryClassName A class name.
+     * @since 2.7.0
+     */
+    public void setConnectionFactoryClassName(final String 
connectionFactoryClassName) {
+        if (isEmpty(connectionFactoryClassName)) {
+            this.connectionFactoryClassName = null;
+        } else {
+            this.connectionFactoryClassName = connectionFactoryClassName;
+        }
+    }
+
+    /**
      * 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
@@ -1716,14 +1690,13 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * 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 (!isEmpty(s)) {
                     if (newVal == null) {
                         newVal = new ArrayList<>();
                     }
@@ -1736,8 +1709,6 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
         }
     }
 
-    // ----------------------------------------------------- DataSource Methods
-
     /**
      * Sets the connection properties passed to driver.connect(...).
      * <p>
@@ -1747,8 +1718,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * NOTE - The "user" and "password" properties will be added explicitly, 
so they do not need to be included here.
      * </p>
      *
-     * @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) {
         Objects.requireNonNull(connectionProperties, "connectionProperties is 
null");
@@ -1762,7 +1732,8 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
                     final String value = entry.substring(index + 1);
                     properties.setProperty(name, value);
                 } else {
-                    // no value is empty string which is how 
java.util.Properties works
+                    // no value is empty string which is how
+                    // java.util.Properties works
                     properties.setProperty(entry, "");
                 }
             }
@@ -1780,8 +1751,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * 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;
@@ -1797,14 +1767,13 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * 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 {
+        if (isEmpty(defaultCatalog)) {
             this.defaultCatalog = null;
+        } else {
+            this.defaultCatalog = defaultCatalog;
         }
     }
 
@@ -1812,8 +1781,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * 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.
+     * @param defaultQueryTimeoutSeconds The default query timeout in seconds.
      */
     public void setDefaultQueryTimeout(final Integer 
defaultQueryTimeoutSeconds) {
         this.defaultQueryTimeoutSeconds = defaultQueryTimeoutSeconds;
@@ -1829,8 +1797,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * 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;
@@ -1846,15 +1813,14 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
      * </p>
      *
-     * @param defaultSchema
-     *            the default catalog
+     * @param defaultSchema the default catalog
      * @since 2.5.0
      */
     public void setDefaultSchema(final String defaultSchema) {
-        if (defaultSchema != null && defaultSchema.trim().length() > 0) {
-            this.defaultSchema = defaultSchema;
-        } else {
+        if (isEmpty(defaultSchema)) {
             this.defaultSchema = null;
+        } else {
+            this.defaultSchema = defaultSchema;
         }
     }
 
@@ -1868,8 +1834,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * 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) {
@@ -1894,15 +1859,14 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * 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 (!isEmpty(s)) {
                     if (newVal == null) {
                         newVal = new HashSet<>();
                     }
@@ -1923,8 +1887,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
      * </p>
      *
-     * @param driver
-     *            The JDBC Driver instance to use for this pool.
+     * @param driver The JDBC Driver instance to use for this pool.
      */
     public synchronized void setDriver(final Driver driver) {
         this.driver = driver;
@@ -1940,8 +1903,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * 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) {
         this.driverClassLoader = driverClassLoader;
@@ -1957,14 +1919,13 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * 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 {
+        if (isEmpty(driverClassName)) {
             this.driverClassName = null;
+        } else {
+            this.driverClassName = driverClassName;
         }
     }
 
@@ -1973,8 +1934,8 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * 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 autoCommitOnReturn
-     *            Whether or not connections being returned to the pool will 
be checked and configured with auto-commit.
+     * @param autoCommitOnReturn Whether or not connections being returned to 
the pool will be checked and configured
+     *                           with auto-commit.
      * @deprecated Use {@link #setAutoCommitOnReturn(boolean)}.
      */
     @Deprecated
@@ -1985,8 +1946,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
     /**
      * 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) {
         if (connectionPool != null) {
@@ -1997,8 +1957,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
 
     /**
      * @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) {
@@ -2015,8 +1974,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * 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;
@@ -2028,8 +1986,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * 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
+     * @param jmxName The JMX name that has been requested for this DataSource
      */
     public void setJmxName(final String jmxName) {
         this.jmxName = jmxName;
@@ -2038,8 +1995,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
     /**
      * 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) {
         this.lifo = lifo;
@@ -2049,8 +2005,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
     }
 
     /**
-     * @param logAbandoned
-     *            new logAbandoned property value
+     * @param logAbandoned new logAbandoned property value
      */
     public void setLogAbandoned(final boolean logAbandoned) {
         if (abandonedConfig == null) {
@@ -2068,9 +2023,8 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * 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.
+     * @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;
@@ -2086,16 +2040,15 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * 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");
     }
 
@@ -2107,10 +2060,8 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * 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 {
@@ -2129,8 +2080,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
      * </p>
      *
-     * @param maxConnLifetimeMillis
-     *            The maximum permitted lifetime of a connection in 
milliseconds.
+     * @param maxConnLifetimeMillis The maximum permitted lifetime of a 
connection in milliseconds.
      */
     public void setMaxConnLifetimeMillis(final long maxConnLifetimeMillis) {
         this.maxConnLifetimeMillis = maxConnLifetimeMillis;
@@ -2141,8 +2091,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * 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;
@@ -2161,8 +2110,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * 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;
@@ -2172,8 +2120,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * 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) {
@@ -2186,8 +2133,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
     /**
      * 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) {
@@ -2200,8 +2146,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
     /**
      * 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) {
@@ -2211,13 +2156,14 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
         }
     }
 
+    // ------------------------------------------------------ Protected Methods
+
     /**
      * 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) {
@@ -2230,8 +2176,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
     /**
      * 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) {
@@ -2241,8 +2186,6 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
         }
     }
 
-    // ------------------------------------------------------ Protected Methods
-
     /**
      * <p>
      * Sets the {@link #password}.
@@ -2253,8 +2196,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * 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;
@@ -2270,16 +2212,15 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * 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;
     }
 
     /**
-     * @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) {
@@ -2294,8 +2235,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
     }
 
     /**
-     * @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) {
@@ -2319,8 +2259,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * {@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()
@@ -2340,8 +2279,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * 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.
+     * @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;
@@ -2351,9 +2289,9 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * 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) {
@@ -2367,8 +2305,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * 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;
@@ -2381,8 +2318,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * 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;
@@ -2395,8 +2331,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * 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;
@@ -2409,8 +2344,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * 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;
@@ -2422,8 +2356,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
     /**
      * 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) {
@@ -2443,8 +2376,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * 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;
@@ -2460,8 +2392,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
      * </p>
      *
-     * @param userName
-     *            the new value for the JDBC connection user name
+     * @param userName the new value for the JDBC connection user name
      */
     public void setUsername(final String userName) {
         this.userName = userName;
@@ -2477,14 +2408,13 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * 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) {
-            this.validationQuery = validationQuery;
-        } else {
+        if (isEmpty(validationQuery)) {
             this.validationQuery = null;
+        } else {
+            this.validationQuery = validationQuery;
         }
     }
 
@@ -2497,8 +2427,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
      * </p>
      *
-     * @param validationQueryTimeoutSeconds
-     *            new validation query timeout value in seconds
+     * @param validationQueryTimeoutSeconds new validation query timeout value 
in seconds
      */
     public void setValidationQueryTimeout(final int 
validationQueryTimeoutSeconds) {
         this.validationQueryTimeoutSeconds = validationQueryTimeoutSeconds;
@@ -2527,4 +2456,5 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
         config.setJmxNameBase(base.toString());
         config.setJmxNamePrefix(Constants.JMX_CONNECTION_POOL_PREFIX);
     }
+
 }
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceFactory.java 
b/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceFactory.java
index eff9a7c..158b944 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceFactory.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceFactory.java
@@ -87,6 +87,7 @@ public class BasicDataSourceFactory implements ObjectFactory {
     private static final String PROP_VALIDATION_QUERY = "validationQuery";
     private static final String PROP_VALIDATION_QUERY_TIMEOUT = 
"validationQueryTimeout";
     private static final String PROP_JMX_NAME = "jmxName";
+    private static final String PROP_CONNECTION_FACTORY_CLASS_NAME = 
"connectionFactoryClassName";
 
     /**
      * The property name for connectionInitSqls. The associated value String 
must be of the form [query;]*
@@ -141,7 +142,8 @@ public class BasicDataSourceFactory implements 
ObjectFactory {
             PROP_REMOVE_ABANDONED_TIMEOUT, PROP_LOG_ABANDONED, 
PROP_ABANDONED_USAGE_TRACKING, PROP_POOL_PREPARED_STATEMENTS,
             PROP_MAX_OPEN_PREPARED_STATEMENTS, PROP_CONNECTION_PROPERTIES, 
PROP_MAX_CONN_LIFETIME_MILLIS,
             PROP_LOG_EXPIRED_CONNECTIONS, PROP_ROLLBACK_ON_RETURN, 
PROP_ENABLE_AUTO_COMMIT_ON_RETURN,
-            PROP_DEFAULT_QUERY_TIMEOUT, PROP_FAST_FAIL_VALIDATION, 
PROP_DISCONNECTION_SQL_CODES, PROP_JMX_NAME };
+            PROP_DEFAULT_QUERY_TIMEOUT, PROP_FAST_FAIL_VALIDATION, 
PROP_DISCONNECTION_SQL_CODES, PROP_JMX_NAME,
+            PROP_CONNECTION_FACTORY_CLASS_NAME };
 
     /**
      * Obsolete properties from DBCP 1.x. with warning strings suggesting new 
properties. LinkedHashMap will guarantee
@@ -548,6 +550,11 @@ public class BasicDataSourceFactory implements 
ObjectFactory {
             dataSource.setDisconnectionSqlCodes(parseList(value, ','));
         }
 
+        value = properties.getProperty(PROP_CONNECTION_FACTORY_CLASS_NAME);
+        if (value != null) {
+            dataSource.setConnectionFactoryClassName(value);
+        }
+
         // DBCP-215
         // Trick to make sure that initialSize connections are created
         if (dataSource.getInitialSize() > 0) {
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/ConnectionFactoryFactory.java 
b/java/org/apache/tomcat/dbcp/dbcp2/ConnectionFactoryFactory.java
new file mode 100644
index 0000000..708ee3a
--- /dev/null
+++ b/java/org/apache/tomcat/dbcp/dbcp2/ConnectionFactoryFactory.java
@@ -0,0 +1,77 @@
+/*
+ * 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.sql.Driver;
+import java.sql.SQLException;
+import java.util.Properties;
+
+/*
+ * Creates {@link ConnectionFactory} instances.
+ *
+ * @since 2.7.0
+ */
+class ConnectionFactoryFactory {
+
+    /**
+     * Creates a new {@link DriverConnectionFactory} allowing for an override 
through
+     * {@link BasicDataSource#getDriverClassName()}.
+     *
+     * @param basicDataSource Configures creation.
+     * @param driver          The JDBC driver.
+     * @return a new {@link DriverConnectionFactory} allowing for a {@link 
BasicDataSource#getDriverClassName()}
+     *         override.
+     * @throws SQLException Thrown when instantiation fails.
+     */
+    static ConnectionFactory createConnectionFactory(final BasicDataSource 
basicDataSource, final Driver driver)
+            throws SQLException {
+        final Properties connectionProperties = 
basicDataSource.getConnectionProperties();
+        final String url = basicDataSource.getUrl();
+        // Set up the driver connection factory we will use
+        final String user = basicDataSource.getUsername();
+        if (user != null) {
+            connectionProperties.put("user", user);
+        } else {
+            basicDataSource.log("DBCP DataSource configured without a 
'username'");
+        }
+
+        final String pwd = basicDataSource.getPassword();
+        if (pwd != null) {
+            connectionProperties.put("password", pwd);
+        } else {
+            basicDataSource.log("DBCP DataSource configured without a 
'password'");
+        }
+        final String connectionFactoryClassName = 
basicDataSource.getConnectionFactoryClassName();
+        if (connectionFactoryClassName != null) {
+            try {
+                final Class<?> connectionFactoryFromCCL = 
Class.forName(connectionFactoryClassName);
+                return (ConnectionFactory) connectionFactoryFromCCL
+                        .getConstructor(Driver.class, String.class, 
Properties.class)
+                        .newInstance(driver, url, connectionProperties);
+            } catch (final Exception t) {
+                final String message = "Cannot load ConnectionFactory 
implementation '" + connectionFactoryClassName
+                        + "'";
+                basicDataSource.log(message, t);
+                throw new SQLException(message, t);
+            }
+        }
+        // Defaults to DriverConnectionFactory
+        return new DriverConnectionFactory(driver, url, connectionProperties);
+    }
+
+}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingConnection.java 
b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingConnection.java
index 5869a36..21d77eb 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingConnection.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingConnection.java
@@ -34,6 +34,7 @@ import java.sql.SQLXML;
 import java.sql.Savepoint;
 import java.sql.Statement;
 import java.sql.Struct;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
@@ -87,19 +88,20 @@ public class DelegatingConnection<C extends Connection> 
extends AbandonedTrace i
     /**
      * Returns a string representation of the metadata associated with the 
innermost delegate connection.
      */
+    @SuppressWarnings("resource")
     @Override
     public synchronized String toString() {
-        String s = null;
+        String str = null;
 
-        final Connection c = this.getInnermostDelegateInternal();
-        if (c != null) {
+        final Connection conn = this.getInnermostDelegateInternal();
+        if (conn != null) {
             try {
-                if (c.isClosed()) {
-                    s = "connection is closed";
+                if (conn.isClosed()) {
+                    str = "connection is closed";
                 } else {
                     final StringBuffer sb = new StringBuffer();
                     sb.append(hashCode());
-                    final DatabaseMetaData meta = c.getMetaData();
+                    final DatabaseMetaData meta = conn.getMetaData();
                     if (meta != null) {
                         sb.append(", URL=");
                         sb.append(meta.getURL());
@@ -107,19 +109,14 @@ public class DelegatingConnection<C extends Connection> 
extends AbandonedTrace i
                         sb.append(meta.getUserName());
                         sb.append(", ");
                         sb.append(meta.getDriverName());
-                        s = sb.toString();
+                        str = sb.toString();
                     }
                 }
             } catch (final SQLException ex) {
                 // Ignore
             }
         }
-
-        if (s == null) {
-            s = super.toString();
-        }
-
-        return s;
+        return str != null ? str : super.toString();
     }
 
     /**
@@ -142,6 +139,7 @@ public class DelegatingConnection<C extends Connection> 
extends AbandonedTrace i
      *            connection to compare innermost delegate with
      * @return true if innermost delegate equals <code>c</code>
      */
+    @SuppressWarnings("resource")
     public boolean innermostDelegateEquals(final Connection c) {
         final Connection innerCon = getInnermostDelegateInternal();
         if (innerCon == null) {
@@ -174,15 +172,16 @@ public class DelegatingConnection<C extends Connection> 
extends AbandonedTrace i
      *
      * @return innermost delegate.
      */
+    @SuppressWarnings("resource")
     public final Connection getInnermostDelegateInternal() {
-        Connection c = connection;
-        while (c != null && c instanceof DelegatingConnection) {
-            c = ((DelegatingConnection<?>) c).getDelegateInternal();
-            if (this == c) {
+        Connection conn = connection;
+        while (conn != null && conn instanceof DelegatingConnection) {
+            conn = ((DelegatingConnection<?>) conn).getDelegateInternal();
+            if (this == conn) {
                 return null;
             }
         }
-        return c;
+        return conn;
     }
 
     /**
@@ -251,6 +250,18 @@ public class DelegatingConnection<C extends Connection> 
extends AbandonedTrace i
         throw e;
     }
 
+    /**
+     * Handles the given {@code SQLException}.
+     *
+     * @param <T> The throwable type.
+     * @param e   The SQLException
+     * @return the given {@code SQLException}
+     * @since 2.7.0
+     */
+    protected <T extends Throwable> T handleExceptionNoThrow(final T e) {
+        return e;
+    }
+
     private void initializeStatement(final DelegatingStatement ds) throws 
SQLException {
         if (defaultQueryTimeoutSeconds != null && 
defaultQueryTimeoutSeconds.intValue() != ds.getQueryTimeout()) {
             ds.setQueryTimeout(defaultQueryTimeoutSeconds.intValue());
@@ -606,23 +617,35 @@ public class DelegatingConnection<C extends Connection> 
extends AbandonedTrace i
     }
 
     protected void passivate() throws SQLException {
-        // The JDBC spec requires that a Connection close any open
+        // The JDBC specification requires that a Connection close any open
         // 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.isEmpty()) {
+            final List<Exception> thrown = new ArrayList<>();
             final Iterator<AbandonedTrace> traceIter = traces.iterator();
             while (traceIter.hasNext()) {
                 final Object trace = traceIter.next();
                 if (trace instanceof Statement) {
-                    ((Statement) trace).close();
+                    try {
+                        ((Statement) trace).close();
+                    } catch (Exception e) {
+                        thrown.add(e);
+                    }
                 } else if (trace instanceof ResultSet) {
                     // DBCP-265: Need to close the result sets that are
                     // generated via DatabaseMetaData
-                    ((ResultSet) trace).close();
+                    try {
+                        ((ResultSet) trace).close();
+                    } catch (Exception e) {
+                        thrown.add(e);
+                    }
                 }
             }
             clearTrace();
+            if (!thrown.isEmpty()) {
+                throw new SQLExceptionList(thrown);
+            }
         }
         setLastUsed(0);
     }
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingResultSet.java 
b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingResultSet.java
index e26d13c..1561ede 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingResultSet.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingResultSet.java
@@ -185,11 +185,11 @@ public final class DelegatingResultSet extends 
AbandonedTrace implements ResultS
     public void close() throws SQLException {
         try {
             if (statement != null) {
-                ((AbandonedTrace) statement).removeTrace(this);
+                removeThisTrace(statement);
                 statement = null;
             }
             if (connection != null) {
-                ((AbandonedTrace) connection).removeTrace(this);
+                removeThisTrace(connection);
                 connection = null;
             }
             resultSet.close();
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingStatement.java 
b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingStatement.java
index 966d9b8..2537eae 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingStatement.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingStatement.java
@@ -21,6 +21,7 @@ import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.SQLWarning;
 import java.sql.Statement;
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -125,35 +126,53 @@ public class DelegatingStatement extends AbandonedTrace 
implements Statement {
         if (isClosed()) {
             return;
         }
+        final List<Exception> thrown = new ArrayList<>();
         try {
-            try {
-                if (connection != null) {
-                    connection.removeTrace(this);
-                    connection = null;
-                }
+            if (connection != null) {
+                connection.removeTrace(this);
+                connection = null;
+            }
 
-                // The JDBC spec requires that a statement close any open
-                // ResultSet's when it is closed.
-                // 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) {
-                    final ResultSet[] set = resultSets.toArray(new 
ResultSet[resultSets.size()]);
-                    for (final ResultSet element : set) {
-                        element.close();
+            // The JDBC spec requires that a statement close any open
+            // ResultSet's when it is closed.
+            // 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> resultSetList = getTrace();
+            if (resultSetList != null) {
+                final int size = resultSetList.size();
+                final ResultSet[] resultSets = resultSetList.toArray(new 
ResultSet[size]);
+                for (final ResultSet resultSet : resultSets) {
+                    if (resultSet != null) {
+                        try {
+                            resultSet.close();
+                        } catch (Exception e) {
+                            if (connection != null) {
+                                // Does not rethrow e.
+                                connection.handleExceptionNoThrow(e);
+                            }
+                            thrown.add(e);
+                        }
                     }
                     clearTrace();
                 }
-
                 if (statement != null) {
-                    statement.close();
+                    try {
+                        statement.close();
+                    } catch (Exception e) {
+                        if (connection != null) {
+                            // Does not rethrow e.
+                            connection.handleExceptionNoThrow(e);
+                        }
+                        thrown.add(e);
+                    }
                 }
-            } catch (final SQLException e) {
-                handleException(e);
             }
         } finally {
             closed = true;
             statement = null;
+            if (!thrown.isEmpty()) {
+                throw new SQLExceptionList(thrown);
+            }
         }
     }
 
@@ -512,7 +531,7 @@ public class DelegatingStatement extends AbandonedTrace 
implements Statement {
     }
 
     /*
-     * Note was protected prior to JDBC 4
+     * Note: This method was protected prior to JDBC 4.
      */
     @Override
     public boolean isClosed() throws SQLException {
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/DriverConnectionFactory.java 
b/java/org/apache/tomcat/dbcp/dbcp2/DriverConnectionFactory.java
index 7e26052..45444ec 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/DriverConnectionFactory.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/DriverConnectionFactory.java
@@ -29,7 +29,9 @@ import java.util.Properties;
 public class DriverConnectionFactory implements ConnectionFactory {
 
     private final String connectionString;
+
     private final Driver driver;
+
     private final Properties properties;
 
     /**
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/DriverFactory.java 
b/java/org/apache/tomcat/dbcp/dbcp2/DriverFactory.java
new file mode 100644
index 0000000..82af50d
--- /dev/null
+++ b/java/org/apache/tomcat/dbcp/dbcp2/DriverFactory.java
@@ -0,0 +1,81 @@
+/*
+ * 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.sql.Driver;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+
+/*
+ * Creates {@link Driver} instances.
+ *
+ * @since 2.7.0
+ */
+class DriverFactory {
+
+    static Driver createDriver(final BasicDataSource basicDataSource) throws 
SQLException {
+        // Load the JDBC driver class
+        Driver driverToUse = basicDataSource.getDriver();
+        String driverClassName = basicDataSource.getDriverClassName();
+        ClassLoader driverClassLoader = basicDataSource.getDriverClassLoader();
+        String url = basicDataSource.getUrl();
+
+        if (driverToUse == null) {
+            Class<?> driverFromCCL = null;
+            if (driverClassName != null) {
+                try {
+                    try {
+                        if (driverClassLoader == null) {
+                            driverFromCCL = Class.forName(driverClassName);
+                        } else {
+                            driverFromCCL = Class.forName(driverClassName, 
true, driverClassLoader);
+                        }
+                    } catch (final ClassNotFoundException cnfe) {
+                        driverFromCCL = 
Thread.currentThread().getContextClassLoader().loadClass(driverClassName);
+                    }
+                } catch (final Exception t) {
+                    final String message = "Cannot load JDBC driver class '" + 
driverClassName + "'";
+                    basicDataSource.log(message, t);
+                    throw new SQLException(message, t);
+                }
+            }
+
+            try {
+                if (driverFromCCL == null) {
+                    driverToUse = DriverManager.getDriver(url);
+                } else {
+                    // Usage of DriverManager is not possible, as it does not
+                    // respect the ContextClassLoader
+                    // N.B. This cast may cause ClassCastException which is
+                    // handled below
+                    driverToUse = (Driver) 
driverFromCCL.getConstructor().newInstance();
+                    if (!driverToUse.acceptsURL(url)) {
+                        throw new SQLException("No suitable driver", "08001");
+                    }
+                }
+            } catch (final Exception t) {
+                final String message = "Cannot create JDBC driver of class '"
+                        + (driverClassName != null ? driverClassName : "") + 
"' for connect URL '" + url + "'";
+                basicDataSource.log(message, t);
+                throw new SQLException(message, t);
+            }
+        }
+        return driverToUse;
+    }
+
+}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/Jdbc41Bridge.java 
b/java/org/apache/tomcat/dbcp/dbcp2/Jdbc41Bridge.java
index b4ee5b9..eb0d09d 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/Jdbc41Bridge.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/Jdbc41Bridge.java
@@ -304,7 +304,7 @@ public class Jdbc41Bridge {
                 return (T) resultSet.getURL(columnLabel);
             }
             throw new SQLFeatureNotSupportedException(
-                    String.format("resultSet=%s, columnLabel=%,d, type=%s", 
resultSet, columnLabel, type));
+                    String.format("resultSet=%s, columnLabel=%s, type=%s", 
resultSet, columnLabel, type));
         }
     }
 
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/PoolableCallableStatement.java 
b/java/org/apache/tomcat/dbcp/dbcp2/PoolableCallableStatement.java
index 486da28..9c0be44 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/PoolableCallableStatement.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/PoolableCallableStatement.java
@@ -21,6 +21,7 @@ import java.sql.CallableStatement;
 import java.sql.Connection;
 import java.sql.ResultSet;
 import java.sql.SQLException;
+import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.tomcat.dbcp.pool2.KeyedObjectPool;
@@ -67,9 +68,7 @@ public class PoolableCallableStatement extends 
DelegatingCallableStatement {
 
         // Remove from trace now because this statement will be
         // added by the activate method.
-        if (getConnectionInternal() != null) {
-            getConnectionInternal().removeTrace(this);
-        }
+        removeThisTrace(getConnectionInternal());
     }
 
     /**
@@ -115,21 +114,29 @@ public class PoolableCallableStatement extends 
DelegatingCallableStatement {
     @Override
     public void passivate() throws SQLException {
         setClosedInternal(true);
-        if (getConnectionInternal() != null) {
-            getConnectionInternal().removeTrace(this);
-        }
+        removeThisTrace(getConnectionInternal());
 
         // The JDBC spec requires that a statement close any open
         // ResultSet's when it is closed.
         // 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) {
-            final ResultSet[] set = resultSets.toArray(new 
ResultSet[resultSets.size()]);
-            for (final ResultSet element : set) {
-                element.close();
+        final List<AbandonedTrace> resultSetList = getTrace();
+        if (resultSetList != null) {
+            final List<Exception> thrown = new ArrayList<>();
+            final ResultSet[] resultSets = resultSetList.toArray(new 
ResultSet[resultSetList.size()]);
+            for (final ResultSet resultSet : resultSets) {
+                if (resultSet != null) {
+                    try {
+                        resultSet.close();
+                    } catch (Exception e) {
+                        thrown.add(e);
+                    }
+                }
             }
             clearTrace();
+            if (!thrown.isEmpty()) {
+                throw new SQLExceptionList(thrown);
+            }
         }
 
         super.passivate();
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/PoolablePreparedStatement.java 
b/java/org/apache/tomcat/dbcp/dbcp2/PoolablePreparedStatement.java
index 29136d0..d8e45c4 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/PoolablePreparedStatement.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/PoolablePreparedStatement.java
@@ -20,6 +20,7 @@ package org.apache.tomcat.dbcp.dbcp2;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
+import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.tomcat.dbcp.pool2.KeyedObjectPool;
@@ -29,6 +30,7 @@ import org.apache.tomcat.dbcp.pool2.KeyedObjectPool;
  * {@link PreparedStatement}s.
  * <p>
  * My {@link #close} method returns me to my containing pool. (See {@link 
PoolingConnection}.)
+ * </p>
  *
  * @param <K>
  *            the key type
@@ -37,6 +39,7 @@ import org.apache.tomcat.dbcp.pool2.KeyedObjectPool;
  * @since 2.0
  */
 public class PoolablePreparedStatement<K> extends DelegatingPreparedStatement {
+
     /**
      * The {@link KeyedObjectPool} from which I was obtained.
      */
@@ -50,7 +53,7 @@ public class PoolablePreparedStatement<K> extends 
DelegatingPreparedStatement {
     private volatile boolean batchAdded = false;
 
     /**
-     * Constructor
+     * Constructor.
      *
      * @param stmt
      *            my underlying {@link PreparedStatement}
@@ -69,9 +72,7 @@ public class PoolablePreparedStatement<K> extends 
DelegatingPreparedStatement {
 
         // Remove from trace now because this statement will be
         // added by the activate method.
-        if (getConnectionInternal() != null) {
-            getConnectionInternal().removeTrace(this);
-        }
+        removeThisTrace(getConnectionInternal());
     }
 
     /**
@@ -128,21 +129,29 @@ public class PoolablePreparedStatement<K> extends 
DelegatingPreparedStatement {
             clearBatch();
         }
         setClosedInternal(true);
-        if (getConnectionInternal() != null) {
-            getConnectionInternal().removeTrace(this);
-        }
+        removeThisTrace(getConnectionInternal());
 
         // The JDBC spec requires that a statement closes any open
         // ResultSet's when it is closed.
         // 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) {
-            final ResultSet[] set = resultSets.toArray(new 
ResultSet[resultSets.size()]);
-            for (final ResultSet element : set) {
-                element.close();
+        final List<AbandonedTrace> resultSetList = getTrace();
+        if (resultSetList != null) {
+            final List<Exception> thrown = new ArrayList<>();
+            final ResultSet[] resultSets = resultSetList.toArray(new 
ResultSet[resultSetList.size()]);
+            for (final ResultSet resultSet : resultSets) {
+                if (resultSet != null) {
+                    try {
+                        resultSet.close();
+                    } catch (Exception e) {
+                        thrown.add(e);
+                    }
+                }
             }
             clearTrace();
+            if (!thrown.isEmpty()) {
+                throw new SQLExceptionList(thrown);
+            }
         }
 
         super.passivate();
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/SQLExceptionList.java 
b/java/org/apache/tomcat/dbcp/dbcp2/SQLExceptionList.java
new file mode 100644
index 0000000..b740ba0
--- /dev/null
+++ b/java/org/apache/tomcat/dbcp/dbcp2/SQLExceptionList.java
@@ -0,0 +1,51 @@
+/*
+ * 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.sql.SQLException;
+import java.util.List;
+
+/**
+ * A SQLException based on a list of Throwable causes.
+ * <p>
+ * The first exception in the list is used as this exception's cause and is 
accessible with the usual
+ * {@link #getCause()} while the complete list is accessible with {@link 
#getCauseList()}.
+ * </p>
+ *
+ * @since 2.7.0
+ */
+public class SQLExceptionList extends SQLException {
+
+    private static final long serialVersionUID = 1L;
+    private final List<? extends Throwable> causeList;
+
+    /**
+     * Creates a new exception caused by a list of exceptions.
+     *
+     * @param causeList a list of cause exceptions.
+     */
+    public SQLExceptionList(List<? extends Throwable> causeList) {
+        super(String.format("%,d exceptions: %s", 
Integer.valueOf(causeList.size()), causeList), causeList.get(0));
+        this.causeList = causeList;
+    }
+
+    public List<? extends Throwable> getCauseList() {
+        return causeList;
+    }
+
+}
diff --git 
a/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java 
b/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java
index fe0944f..27ad570 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java
@@ -86,6 +86,11 @@ public class DriverAdapterCPDS implements 
ConnectionPoolDataSource, Referenceabl
     private static final String GET_CONNECTION_CALLED = "A PooledConnection 
was already requested from this source, "
             + "further initialization is not allowed.";
 
+    static {
+        // Attempt to prevent deadlocks - see DBCP - 272
+        DriverManager.getDrivers();
+    }
+
     /** Description */
     private String description;
 
@@ -106,13 +111,13 @@ public class DriverAdapterCPDS implements 
ConnectionPoolDataSource, Referenceabl
 
     /** Log stream. NOT USED */
     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;
 
     /** Whether or not getConnection has been called */
@@ -121,11 +126,6 @@ public class DriverAdapterCPDS implements 
ConnectionPoolDataSource, Referenceabl
     /** Connection properties passed to JDBC Driver */
     private Properties connectionProperties;
 
-    static {
-        // Attempt to prevent deadlocks - see DBCP - 272
-        DriverManager.getDrivers();
-    }
-
     /**
      * Controls access to the underlying connection
      */
@@ -138,6 +138,208 @@ public class DriverAdapterCPDS implements 
ConnectionPoolDataSource, Referenceabl
     }
 
     /**
+     * Throws an IllegalStateException, if a PooledConnection has already been 
requested.
+     */
+    private void assertInitializationAllowed() throws IllegalStateException {
+        if (getConnectionCalled) {
+            throw new IllegalStateException(GET_CONNECTION_CALLED);
+        }
+    }
+
+    private boolean getBooleanContentString(RefAddr ra) {
+        return Boolean.valueOf(getStringContent(ra)).booleanValue();
+    }
+
+    /**
+     * Gets the connection properties passed to the JDBC driver.
+     *
+     * @return the JDBC connection properties used when creating connections.
+     */
+    public Properties getConnectionProperties() {
+        return connectionProperties;
+    }
+
+    /**
+     * 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)
+     */
+    public String getDescription() {
+        return description;
+    }
+
+    /**
+     * Gets the driver class name.
+     *
+     * @return value of driver.
+     */
+    public String getDriver() {
+        return driver;
+    }
+
+    private int getIntegerStringContent(final RefAddr ra) {
+        return Integer.parseInt(getStringContent(ra));
+    }
+
+    /**
+     * 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() {
+        return loginTimeout;
+    }
+
+    /**
+     * Gets the log writer for this data source. NOT USED.
+     */
+    @Override
+    public PrintWriter getLogWriter() {
+        return logWriter;
+    }
+
+    /**
+     * 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() {
+        return this.maxIdle;
+    }
+
+    /**
+     * Gets the maximum number of prepared statements.
+     *
+     * @return maxPrepartedStatements value
+     */
+    public int getMaxPreparedStatements() {
+        return maxPreparedStatements;
+    }
+
+    /**
+     * 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
+     * @return the minimum amount of time a statement may sit idle in the pool.
+     */
+    public int getMinEvictableIdleTimeMillis() {
+        return minEvictableIdleTimeMillis;
+    }
+
+    /**
+     * 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;
+    }
+
+    /**
+     * Implements {@link 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 {
+        // 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;
+            if (ref.getClassName().equals(getClass().getName())) {
+                RefAddr ra = ref.get("description");
+                if (isNotEmpty(ra)) {
+                    setDescription(getStringContent(ra));
+                }
+
+                ra = ref.get("driver");
+                if (isNotEmpty(ra)) {
+                    setDriver(getStringContent(ra));
+                }
+                ra = ref.get("url");
+                if (isNotEmpty(ra)) {
+                    setUrl(getStringContent(ra));
+                }
+                ra = ref.get(KEY_USER);
+                if (isNotEmpty(ra)) {
+                    setUser(getStringContent(ra));
+                }
+                ra = ref.get(KEY_PASSWORD);
+                if (isNotEmpty(ra)) {
+                    setPassword(getStringContent(ra));
+                }
+
+                ra = ref.get("poolPreparedStatements");
+                if (isNotEmpty(ra)) {
+                    setPoolPreparedStatements(getBooleanContentString(ra));
+                }
+                ra = ref.get("maxIdle");
+                if (isNotEmpty(ra)) {
+                    setMaxIdle(getIntegerStringContent(ra));
+                }
+
+                ra = ref.get("timeBetweenEvictionRunsMillis");
+                if (isNotEmpty(ra)) {
+                    
setTimeBetweenEvictionRunsMillis(getIntegerStringContent(ra));
+                }
+
+                ra = ref.get("numTestsPerEvictionRun");
+                if (isNotEmpty(ra)) {
+                    setNumTestsPerEvictionRun(getIntegerStringContent(ra));
+                }
+
+                ra = ref.get("minEvictableIdleTimeMillis");
+                if (isNotEmpty(ra)) {
+                    setMinEvictableIdleTimeMillis(getIntegerStringContent(ra));
+                }
+                ra = ref.get("maxPreparedStatements");
+                if (isNotEmpty(ra)) {
+                    setMaxPreparedStatements(getIntegerStringContent(ra));
+                }
+
+                ra = ref.get("accessToUnderlyingConnectionAllowed");
+                if (isNotEmpty(ra)) {
+                    
setAccessToUnderlyingConnectionAllowed(getBooleanContentString(ra));
+                }
+
+                cpds = this;
+            }
+        }
+        return cpds;
+    }
+
+    @Override
+    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
+        throw new SQLFeatureNotSupportedException();
+    }
+
+    /**
+     * Gets the value of password for the default user.
+     *
+     * @return value of password.
+     */
+    public String getPassword() {
+        return Utils.toString(userPassword);
+    }
+
+    /**
+     * Gets the value of password for the default user.
+     *
+     * @return value of password.
+     * @since 2.4.0
+     */
+    public char[] getPasswordCharArray() {
+        return userPassword;
+    }
+
+    /**
      * Attempts to establish a database connection using the default user and 
password.
      */
     @Override
@@ -146,7 +348,7 @@ public class DriverAdapterCPDS implements 
ConnectionPoolDataSource, Referenceabl
     }
 
     /**
-     * Attempt to establish a database connection.
+     * Attempts to establish a database connection.
      *
      * @param pooledUserName
      *            name to be used for the connection
@@ -208,16 +410,8 @@ public class DriverAdapterCPDS implements 
ConnectionPoolDataSource, Referenceabl
         return pooledConnection;
     }
 
-    @Override
-    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
-        throw new SQLFeatureNotSupportedException();
-    }
-
-    // ----------------------------------------------------------------------
-    // Referenceable implementation
-
     /**
-     * <CODE>Referenceable</CODE> implementation.
+     * Implements {@link Referenceable}.
      */
     @Override
     public Reference getReference() throws NamingException {
@@ -243,256 +437,110 @@ public class DriverAdapterCPDS implements 
ConnectionPoolDataSource, Referenceabl
         return ref;
     }
 
-    // ----------------------------------------------------------------------
-    // ObjectFactory implementation
-
-    /**
-     * 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 {
-        // 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;
-            if (ref.getClassName().equals(getClass().getName())) {
-                RefAddr ra = ref.get("description");
-                if (ra != null && ra.getContent() != null) {
-                    setDescription(ra.getContent().toString());
-                }
-
-                ra = ref.get("driver");
-                if (ra != null && ra.getContent() != null) {
-                    setDriver(ra.getContent().toString());
-                }
-                ra = ref.get("url");
-                if (ra != null && ra.getContent() != null) {
-                    setUrl(ra.getContent().toString());
-                }
-                ra = ref.get(KEY_USER);
-                if (ra != null && ra.getContent() != null) {
-                    setUser(ra.getContent().toString());
-                }
-                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());
-                }
-                ra = ref.get("maxIdle");
-                if (ra != null && ra.getContent() != null) {
-                    setMaxIdle(Integer.parseInt(ra.getContent().toString()));
-                }
-
-                ra = ref.get("timeBetweenEvictionRunsMillis");
-                if (ra != null && ra.getContent() != null) {
-                    
setTimeBetweenEvictionRunsMillis(Integer.parseInt(ra.getContent().toString()));
-                }
-
-                ra = ref.get("numTestsPerEvictionRun");
-                if (ra != null && ra.getContent() != null) {
-                    
setNumTestsPerEvictionRun(Integer.parseInt(ra.getContent().toString()));
-                }
-
-                ra = ref.get("minEvictableIdleTimeMillis");
-                if (ra != null && ra.getContent() != null) {
-                    
setMinEvictableIdleTimeMillis(Integer.parseInt(ra.getContent().toString()));
-                }
-                ra = ref.get("maxPreparedStatements");
-                if (ra != null && ra.getContent() != null) {
-                    
setMaxPreparedStatements(Integer.parseInt(ra.getContent().toString()));
-                }
-
-                ra = ref.get("accessToUnderlyingConnectionAllowed");
-                if (ra != null && ra.getContent() != null) {
-                    
setAccessToUnderlyingConnectionAllowed(Boolean.valueOf(ra.getContent().toString()).booleanValue());
-                }
-
-                cpds = this;
-            }
-        }
-        return cpds;
-    }
-
-    /**
-     * Throws an IllegalStateException, if a PooledConnection has already been 
requested.
-     */
-    private void assertInitializationAllowed() throws IllegalStateException {
-        if (getConnectionCalled) {
-            throw new IllegalStateException(GET_CONNECTION_CALLED);
-        }
+    private String getStringContent(RefAddr ra) {
+        return ra.getContent().toString();
     }
 
-    // ----------------------------------------------------------------------
-    // Properties
-
     /**
-     * Gets the connection properties passed to the JDBC driver.
-     *
-     * @return the JDBC connection properties used when creating connections.
-     */
-    public Properties getConnectionProperties() {
-        return connectionProperties;
-    }
-
-    /**
-     * <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>
-     *
-     * @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 != 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.
-     *
-     * @return value of description, may be null.
-     * @see #setDescription(String)
-     */
-    public String getDescription() {
-        return description;
-    }
-
-    /**
-     * 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.
-     */
-    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.
+     * 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 value of password.
+     * @return the value of the evictor thread timer
+     * @see #setTimeBetweenEvictionRunsMillis(long)
      */
-    public String getPassword() {
-        return Utils.toString(userPassword);
+    public long getTimeBetweenEvictionRunsMillis() {
+        return timeBetweenEvictionRunsMillis;
     }
 
     /**
-     * Sets the value of password for the default user.
+     * Gets the value of url used to locate the database for this datasource.
      *
-     * @param userPassword
-     *            Value to assign to password.
-     * @throws IllegalStateException
-     *             if {@link #getPooledConnection()} has been called
+     * @return value of url.
      */
-    public void setPassword(final char[] userPassword) {
-        assertInitializationAllowed();
-        this.userPassword = Utils.clone(userPassword);
-        update(connectionProperties, KEY_PASSWORD, 
Utils.toString(this.userPassword));
+    public String getUrl() {
+        return url;
     }
 
     /**
-     * Sets the value of password for the default user.
+     * Gets the value of default user (login or user name).
      *
-     * @param userPassword
-     *            Value to assign to password.
-     * @throws IllegalStateException
-     *             if {@link #getPooledConnection()} has been called
+     * @return value of user.
      */
-    public void setPassword(final String userPassword) {
-        assertInitializationAllowed();
-        this.userPassword = Utils.toCharArray(userPassword);
-        update(connectionProperties, KEY_PASSWORD, userPassword);
+    public String getUser() {
+        return userName;
     }
 
     /**
-     * Gets the value of url used to locate the database for this datasource.
+     * Returns the value of the accessToUnderlyingConnectionAllowed property.
      *
-     * @return value of url.
+     * @return true if access to the underlying is allowed, false otherwise.
      */
-    public String getUrl() {
-        return url;
+    public synchronized boolean isAccessToUnderlyingConnectionAllowed() {
+        return this.accessToUnderlyingConnectionAllowed;
+    }
+
+    private boolean isNotEmpty(RefAddr ra) {
+        return ra != null && ra.getContent() != null;
     }
 
     /**
-     * Sets the value of URL string used to locate the database for this 
datasource.
+     * Whether to toggle the pooling of <code>PreparedStatement</code>s
      *
-     * @param v
-     *            Value to assign to url.
-     * @throws IllegalStateException
-     *             if {@link #getPooledConnection()} has been called
+     * @return value of poolPreparedStatements.
      */
-    public void setUrl(final String v) {
-        assertInitializationAllowed();
-        this.url = v;
+    public boolean isPoolPreparedStatements() {
+        return poolPreparedStatements;
     }
 
     /**
-     * Gets the value of default user (login or user name).
+     * Sets the value of the accessToUnderlyingConnectionAllowed property. It 
controls if the PoolGuard allows access to
+     * the underlying connection. (Default: false)
      *
-     * @return value of user.
+     * @param allow
+     *            Access to the underlying connection is granted when true.
      */
-    public String getUser() {
-        return userName;
+    public synchronized void setAccessToUnderlyingConnectionAllowed(final 
boolean allow) {
+        this.accessToUnderlyingConnectionAllowed = allow;
     }
 
     /**
-     * Sets the value of default user (login or user name).
+     * Sets the connection properties passed to the JDBC driver.
+     * <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 v
-     *            Value to assign to user.
+     * @param props
+     *            Connection properties to use when creating new connections.
      * @throws IllegalStateException
      *             if {@link #getPooledConnection()} has been called
      */
-    public void setUser(final String v) {
+    public void setConnectionProperties(final Properties props) {
         assertInitializationAllowed();
-        this.userName = v;
-        update(connectionProperties, KEY_USER, v);
+        connectionProperties = props;
+        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 driver class name.
+     * Sets 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 driver.
+     * @param v
+     *            Value to assign to description.
      */
-    public String getDriver() {
-        return driver;
+    public void setDescription(final String v) {
+        this.description = v;
     }
 
     /**
@@ -514,23 +562,6 @@ public class DriverAdapterCPDS implements 
ConnectionPoolDataSource, Referenceabl
     }
 
     /**
-     * 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() {
-        return loginTimeout;
-    }
-
-    /**
-     * Gets the log writer for this data source. NOT USED.
-     */
-    @Override
-    public PrintWriter getLogWriter() {
-        return logWriter;
-    }
-
-    /**
      * Sets the maximum time in seconds that this data source will wait while 
attempting to connect to a database. NOT
      * USED.
      */
@@ -547,41 +578,6 @@ public class DriverAdapterCPDS implements 
ConnectionPoolDataSource, Referenceabl
         logWriter = out;
     }
 
-    // ------------------------------------------------------------------
-    // PreparedStatement pool properties
-
-    /**
-     * Flag to toggle the pooling of <code>PreparedStatement</code>s
-     *
-     * @return value of poolPreparedStatements.
-     */
-    public boolean isPoolPreparedStatements() {
-        return poolPreparedStatements;
-    }
-
-    /**
-     * Flag to toggle the pooling of <code>PreparedStatement</code>s
-     *
-     * @param poolPreparedStatements
-     *            true to pool statements.
-     * @throws IllegalStateException
-     *             if {@link #getPooledConnection()} has been called
-     */
-    public void setPoolPreparedStatements(final boolean 
poolPreparedStatements) {
-        assertInitializationAllowed();
-        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.
-     *
-     * @return the value of maxIdle
-     */
-    public int getMaxIdle() {
-        return this.maxIdle;
-    }
-
     /**
      * Gets the maximum number of statements that can remain idle in the pool, 
without extra ones being released, or
      * negative for no limit.
@@ -597,41 +593,29 @@ public class DriverAdapterCPDS implements 
ConnectionPoolDataSource, Referenceabl
     }
 
     /**
-     * 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.
+     * Sets the maximum number of prepared statements.
      *
-     * @return the value of the evictor thread timer
-     * @see #setTimeBetweenEvictionRunsMillis(long)
+     * @param maxPreparedStatements
+     *            the new maximum number of prepared statements
      */
-    public long getTimeBetweenEvictionRunsMillis() {
-        return timeBetweenEvictionRunsMillis;
+    public void setMaxPreparedStatements(final int maxPreparedStatements) {
+        this.maxPreparedStatements = maxPreparedStatements;
     }
 
     /**
-     * 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.
+     * 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 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()
+     * @param minEvictableIdleTimeMillis
+     *            minimum time to set (in ms)
+     * @see #getMinEvictableIdleTimeMillis()
+     * @see #setTimeBetweenEvictionRunsMillis(long)
      * @throws IllegalStateException
      *             if {@link #getPooledConnection()} has been called
      */
-    public void setTimeBetweenEvictionRunsMillis(final long 
timeBetweenEvictionRunsMillis) {
+    public void setMinEvictableIdleTimeMillis(final int 
minEvictableIdleTimeMillis) {
         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;
+        this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
     }
 
     /**
@@ -655,80 +639,87 @@ public class DriverAdapterCPDS implements 
ConnectionPoolDataSource, Referenceabl
     }
 
     /**
-     * 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).
+     * Sets the value of password for the default user.
      *
-     * @see #setMinEvictableIdleTimeMillis
-     * @see #setTimeBetweenEvictionRunsMillis
-     * @return the minimum amount of time a statement may sit idle in the pool.
+     * @param userPassword
+     *            Value to assign to password.
+     * @throws IllegalStateException
+     *             if {@link #getPooledConnection()} has been called
      */
-    public int getMinEvictableIdleTimeMillis() {
-        return minEvictableIdleTimeMillis;
+    public void setPassword(final char[] userPassword) {
+        assertInitializationAllowed();
+        this.userPassword = Utils.clone(userPassword);
+        update(connectionProperties, KEY_PASSWORD, 
Utils.toString(this.userPassword));
     }
 
     /**
-     * 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.
+     * Sets the value of password for the default user.
      *
-     * @param minEvictableIdleTimeMillis
-     *            minimum time to set (in ms)
-     * @see #getMinEvictableIdleTimeMillis()
-     * @see #setTimeBetweenEvictionRunsMillis(long)
+     * @param userPassword
+     *            Value to assign to password.
      * @throws IllegalStateException
      *             if {@link #getPooledConnection()} has been called
      */
-    public void setMinEvictableIdleTimeMillis(final int 
minEvictableIdleTimeMillis) {
+    public void setPassword(final String userPassword) {
         assertInitializationAllowed();
-        this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
+        this.userPassword = Utils.toCharArray(userPassword);
+        update(connectionProperties, KEY_PASSWORD, userPassword);
     }
 
     /**
-     * Returns the value of the accessToUnderlyingConnectionAllowed property.
+     * Whether to toggle the pooling of <code>PreparedStatement</code>s
      *
-     * @return true if access to the underlying is allowed, false otherwise.
+     * @param poolPreparedStatements
+     *            true to pool statements.
+     * @throws IllegalStateException
+     *             if {@link #getPooledConnection()} has been called
      */
-    public synchronized boolean isAccessToUnderlyingConnectionAllowed() {
-        return this.accessToUnderlyingConnectionAllowed;
+    public void setPoolPreparedStatements(final boolean 
poolPreparedStatements) {
+        assertInitializationAllowed();
+        this.poolPreparedStatements = poolPreparedStatements;
     }
 
     /**
-     * Sets the value of the accessToUnderlyingConnectionAllowed property. It 
controls if the PoolGuard allows access to
-     * the underlying connection. (Default: false)
+     * 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 allow
-     *            Access to the underlying connection is granted when true.
+     * @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 synchronized void setAccessToUnderlyingConnectionAllowed(final 
boolean allow) {
-        this.accessToUnderlyingConnectionAllowed = allow;
+    public void setTimeBetweenEvictionRunsMillis(final long 
timeBetweenEvictionRunsMillis) {
+        assertInitializationAllowed();
+        this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
     }
 
     /**
-     * Gets the maximum number of prepared statements.
+     * Sets the value of URL string used to locate the database for this 
datasource.
      *
-     * @return maxPrepartedStatements value
+     * @param v
+     *            Value to assign to url.
+     * @throws IllegalStateException
+     *             if {@link #getPooledConnection()} has been called
      */
-    public int getMaxPreparedStatements() {
-        return maxPreparedStatements;
+    public void setUrl(final String v) {
+        assertInitializationAllowed();
+        this.url = v;
     }
 
     /**
-     * Sets the maximum number of prepared statements.
+     * Sets the value of default user (login or user name).
      *
-     * @param maxPreparedStatements
-     *            the new maximum number of prepared statements
+     * @param v
+     *            Value to assign to user.
+     * @throws IllegalStateException
+     *             if {@link #getPooledConnection()} has been called
      */
-    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);
-            }
-        }
+    public void setUser(final String v) {
+        assertInitializationAllowed();
+        this.userName = v;
+        update(connectionProperties, KEY_USER, v);
     }
 
     /**
@@ -765,7 +756,7 @@ public class DriverAdapterCPDS implements 
ConnectionPoolDataSource, Referenceabl
         builder.append(", connectionProperties=");
         Properties tmpProps = connectionProperties;
         final String pwdKey = "password";
-        if (connectionProperties.contains(pwdKey)) {
+        if (connectionProperties != null && 
connectionProperties.contains(pwdKey)) {
             tmpProps = (Properties) connectionProperties.clone();
             tmpProps.remove(pwdKey);
         }
@@ -775,4 +766,14 @@ public class DriverAdapterCPDS implements 
ConnectionPoolDataSource, Referenceabl
         builder.append("]");
         return builder.toString();
     }
+
+    private void update(final Properties properties, final String key, final 
String value) {
+        if (properties != null && key != null) {
+            if (value == null) {
+                properties.remove(key);
+            } else {
+                properties.setProperty(key, value);
+            }
+        }
+    }
 }
diff --git 
a/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PooledConnectionImpl.java 
b/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PooledConnectionImpl.java
index 74b9eee..7127e45 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PooledConnectionImpl.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PooledConnectionImpl.java
@@ -181,6 +181,10 @@ class PooledConnectionImpl
 
     /**
      * Creates a {@link PStmtKey} for the given arguments.
+     *
+     * @param sql
+     *            The SQL statement.
+     * @return a {@link PStmtKey} for the given arguments.
      */
     protected PStmtKey createKey(final String sql) {
         return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), 
getSchemaOrNull());
@@ -188,6 +192,13 @@ class PooledConnectionImpl
 
     /**
      * Creates a {@link PStmtKey} for the given arguments.
+     *
+     * @param sql
+     *            The SQL statement.
+     * @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 key to uniquely identify a prepared statement.
      */
     protected PStmtKey createKey(final String sql, final int 
autoGeneratedKeys) {
         return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), 
getSchemaOrNull(), autoGeneratedKeys);
@@ -195,6 +206,13 @@ class PooledConnectionImpl
 
     /**
      * Creates a {@link PStmtKey} for the given arguments.
+     *
+     * @param sql
+     *            The SQL statement.
+     * @param columnIndexes
+     *            An array of column indexes indicating the columns that 
should be returned from the inserted row or
+     *            rows.
+     * @return a key to uniquely identify a prepared statement.
      */
     protected PStmtKey createKey(final String sql, final int columnIndexes[]) {
         return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), 
getSchemaOrNull(), columnIndexes);
@@ -202,6 +220,16 @@ class PooledConnectionImpl
 
     /**
      * Creates a {@link PStmtKey} for the given arguments.
+     *
+     * @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>.
+     * @return a key to uniquely identify a prepared statement.
      */
     protected PStmtKey createKey(final String sql, final int resultSetType, 
final int resultSetConcurrency) {
         return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), 
getSchemaOrNull(), resultSetType,
@@ -210,6 +238,19 @@ class PooledConnectionImpl
 
     /**
      * Creates a {@link PStmtKey} for the given arguments.
+     *
+     * @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>
+     * @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 key to uniquely identify a prepared statement.
      */
     protected PStmtKey createKey(final String sql, final int resultSetType, 
final int resultSetConcurrency,
             final int resultSetHoldability) {
@@ -220,6 +261,20 @@ class PooledConnectionImpl
     /**
      * Creates a {@link PStmtKey} for the given arguments.
      *
+     * @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>.
+     * @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.
+     * @return a key to uniquely identify a prepared statement.
      * @since 2.4.0
      */
     protected PStmtKey createKey(final String sql, final int resultSetType, 
final int resultSetConcurrency,
@@ -231,6 +286,17 @@ class PooledConnectionImpl
     /**
      * Creates a {@link PStmtKey} for the given arguments.
      *
+     * @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>.
+     * @param statementType
+     *            The SQL statement type, prepared or callable.
+     * @return a key to uniquely identify a prepared statement.
      * @since 2.4.0
      */
     protected PStmtKey createKey(final String sql, final int resultSetType, 
final int resultSetConcurrency,
@@ -241,6 +307,12 @@ class PooledConnectionImpl
 
     /**
      * Creates a {@link PStmtKey} for the given arguments.
+     *
+     * @param sql
+     *            The SQL statement.
+     * @param statementType
+     *            The SQL statement type, prepared or callable.
+     * @return a key to uniquely identify a prepared statement.
      */
     protected PStmtKey createKey(final String sql, final StatementType 
statementType) {
         return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), 
getSchemaOrNull(), statementType);
@@ -248,6 +320,12 @@ class PooledConnectionImpl
 
     /**
      * Creates a {@link PStmtKey} for the given arguments.
+     *
+     * @param sql
+     *            The SQL statement.
+     * @param columnNames
+     *            An array of column names indicating the columns that should 
be returned from the inserted row or rows.
+     * @return a key to uniquely identify a prepared statement.
      */
     protected PStmtKey createKey(final String sql, final String columnNames[]) 
{
         return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), 
getSchemaOrNull(), columnNames);
@@ -361,6 +439,9 @@ class PooledConnectionImpl
 
     /**
      * Normalizes the given SQL statement, producing a canonical form that is 
semantically equivalent to the original.
+     * @param sql
+     *            The SQL statement.
+     * @return the normalized SQL statement.
      */
     protected String normalizeSQL(final String sql) {
         return sql.trim();
diff --git 
a/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSource.java 
b/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSource.java
index a0fe1b4..e50e34d 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSource.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSource.java
@@ -98,7 +98,7 @@ public abstract class InstanceKeyDataSource implements 
DataSource, Referenceable
     /** Description */
     private String description;
 
-    /** Environment that may be used to set up a jndi initial context. */
+    /** Environment that may be used to set up a JNDI initial context. */
     private Properties jndiEnvironment;
 
     /** Login TimeOut in seconds */
@@ -146,6 +146,8 @@ public abstract class InstanceKeyDataSource implements 
DataSource, Referenceable
 
     /**
      * Throws an IllegalStateException, if a PooledConnection has already been 
requested.
+     *
+     * @throws IllegalStateException Thrown if a PooledConnection has already 
been requested.
      */
     protected void assertInitializationAllowed() throws IllegalStateException {
         if (getConnectionCalled) {
@@ -520,8 +522,8 @@ public abstract class InstanceKeyDataSource implements 
DataSource, Referenceable
     }
 
     /**
-     * Gets 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 data source is being
+     * accessed via JNDI.
      *
      * @return value of connectionPoolDataSource.
      */
@@ -530,8 +532,8 @@ public abstract class InstanceKeyDataSource implements 
DataSource, Referenceable
     }
 
     /**
-     * Sets 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
+     * data source.
      *
      * @param v
      *            Value to assign to connectionPoolDataSource.
@@ -549,8 +551,8 @@ public abstract class InstanceKeyDataSource implements 
DataSource, Referenceable
     }
 
     /**
-     * Gets 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 data source
+     * from a JNDI service provider.
      *
      * @return value of dataSourceName.
      */
@@ -559,8 +561,8 @@ public abstract class InstanceKeyDataSource implements 
DataSource, Referenceable
     }
 
     /**
-     * Sets 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 data source
+     * from a JNDI service provider.
      *
      * @param v
      *            Value to assign to dataSourceName.
diff --git 
a/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSourceFactory.java
 
b/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSourceFactory.java
index eb0c8a9..c471d53 100644
--- 
a/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSourceFactory.java
+++ 
b/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSourceFactory.java
@@ -120,7 +120,7 @@ abstract class InstanceKeyDataSourceFactory implements 
ObjectFactory {
             if (isCorrectClass(ref.getClassName())) {
                 final RefAddr refAddr = ref.get("instanceKey");
                 if (refAddr != null && refAddr.getContent() != null) {
-                    // object was bound to jndi via Referenceable api.
+                    // object was bound to JNDI via Referenceable API.
                     obj = instanceMap.get(refAddr.getContent());
                 } else {
                     // Tomcat JNDI creates a Reference out of server.xml
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 14ced5d..46123de 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -169,6 +169,10 @@
         Update the internal fork of Commons Pool2 to 796e32d (2018-08-01) to
         pick up the changes Commons Pool2 2.7.0. (markt)
       </update>
+      <update>
+        Update the internal fork of Commons DBCP2 to 87d9e3a (2018-08-01) to
+        pick up the changes Commons DBCP2 2.7.0 RC1. (markt)
+      </update>
     </changelog>
   </subsection>
 </section>


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to