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

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

commit 50ae70a293faae7b9a43aea77df3247e4d0525d1
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Mon Apr 29 12:43:36 2024 +0100

    Update Commons DBCP to 2.12.0
---
 MERGE.txt                                          |   2 +-
 .../apache/tomcat/dbcp/dbcp2/AbandonedTrace.java   |   2 +-
 .../apache/tomcat/dbcp/dbcp2/BasicDataSource.java  | 148 +++++++++--------
 .../tomcat/dbcp/dbcp2/BasicDataSourceFactory.java  |  33 ++--
 .../tomcat/dbcp/dbcp2/BasicDataSourceMXBean.java   |   2 +-
 .../dbcp/dbcp2/ConnectionFactoryFactory.java       |   3 +-
 .../apache/tomcat/dbcp/dbcp2/DataSourceMXBean.java |  13 ++
 .../tomcat/dbcp/dbcp2/DelegatingConnection.java    |   4 +-
 .../dbcp/dbcp2/DelegatingDatabaseMetaData.java     |   6 +-
 .../dbcp/dbcp2/DelegatingPreparedStatement.java    |  42 ++---
 .../tomcat/dbcp/dbcp2/DelegatingResultSet.java     |   2 +-
 .../tomcat/dbcp/dbcp2/DelegatingStatement.java     |  12 +-
 .../org/apache/tomcat/dbcp/dbcp2/Jdbc41Bridge.java |   4 +-
 .../dbcp/dbcp2/PoolableCallableStatement.java      |   2 +-
 .../tomcat/dbcp/dbcp2/PoolableConnection.java      | 177 ++++++++++++---------
 .../dbcp/dbcp2/PoolableConnectionFactory.java      |   2 +-
 .../dbcp/dbcp2/PoolablePreparedStatement.java      |  13 +-
 .../tomcat/dbcp/dbcp2/PoolingConnection.java       |  36 ++++-
 .../tomcat/dbcp/dbcp2/PoolingDataSource.java       |   8 +-
 .../apache/tomcat/dbcp/dbcp2/PoolingDriver.java    |   2 +-
 java/org/apache/tomcat/dbcp/dbcp2/Utils.java       |   3 +-
 .../dbcp/dbcp2/cpdsadapter/ConnectionImpl.java     |  23 ++-
 .../dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java  | 127 +++++++++------
 .../dbcp2/cpdsadapter/PooledConnectionImpl.java    |  20 ++-
 .../dbcp/dbcp2/cpdsadapter/package-info.java       |  18 +--
 .../dbcp2/datasources/CPDSConnectionFactory.java   |  34 ++--
 .../datasources/KeyedCPDSConnectionFactory.java    |   2 +-
 .../dbcp2/datasources/PerUserPoolDataSource.java   |   6 +-
 .../dbcp2/datasources/SharedPoolDataSource.java    |   2 +-
 .../dbcp/dbcp2/datasources/package-info.java       |  58 +++----
 .../dbcp/dbcp2/managed/BasicManagedDataSource.java |  15 +-
 .../managed/DataSourceXAConnectionFactory.java     |   7 +-
 .../dbcp2/managed/LocalXAConnectionFactory.java    |   8 +-
 .../dbcp/dbcp2/managed/ManagedConnection.java      |   8 +-
 .../dbcp/dbcp2/managed/TransactionRegistry.java    |   2 +-
 .../dbcp/dbcp2/managed/XAConnectionFactory.java    |   4 +-
 .../org/apache/tomcat/dbcp/dbcp2/package-info.java |  12 +-
 webapps/docs/changelog.xml                         |   3 +
 38 files changed, 463 insertions(+), 402 deletions(-)

diff --git a/MERGE.txt b/MERGE.txt
index e823ce862b..0dd73a4718 100644
--- a/MERGE.txt
+++ b/MERGE.txt
@@ -75,4 +75,4 @@ Sub-tree
 src/main/java/org/apache/commons/dbcp2
 src/main/resources/org/apache/commons/dbcp2
 The SHA1 ID / tag for the most recent commit to be merged to Tomcat is:
-b1e0c86d101aa43029625eb191aaee4306911702 (2023-03-08)
+rel/commons-dbcp-2.12.0 (2024-03-04)
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/AbandonedTrace.java 
b/java/org/apache/tomcat/dbcp/dbcp2/AbandonedTrace.java
index e57b4108a1..bff2021fd7 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/AbandonedTrace.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/AbandonedTrace.java
@@ -37,7 +37,7 @@ import org.apache.tomcat.dbcp.pool2.TrackedUse;
  */
 public class AbandonedTrace implements TrackedUse, AutoCloseable {
 
-    static void add(AbandonedTrace receiver, AbandonedTrace trace) {
+    static void add(final AbandonedTrace receiver, final AbandonedTrace trace) 
{
         if (receiver != null) {
             receiver.addTrace(trace);
         }
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSource.java 
b/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSource.java
index fcd65d5f0d..20b3c0c6ed 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSource.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSource.java
@@ -465,7 +465,6 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
         return ConnectionFactoryFactory.createConnectionFactory(this, 
DriverFactory.createDriver(this));
     }
 
-
     /**
      * Creates a connection pool for this datasource. This method only exists 
so subclasses can replace the
      * implementation class.
@@ -483,6 +482,10 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
         updateJmxName(config);
         // Disable JMX on the underlying pool if the DS is not registered:
         config.setJmxEnabled(registeredJmxObjectName != null);
+        // Set up usage tracking if enabled
+        if (getAbandonedUsageTracking() && abandonedConfig != null) {
+            abandonedConfig.setUseUsageTracking(true);
+        }
         final GenericObjectPool<PoolableConnection> gop = 
createObjectPool(factory, config, abandonedConfig);
         gop.setMaxTotal(maxTotal);
         gop.setMaxIdle(maxIdle);
@@ -910,6 +913,17 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
         return this.driverClassName;
     }
 
+    /**
+     * Gets the value of the {code durationBetweenEvictionRuns} property.
+     *
+     * @return the time (in milliseconds) between evictor runs
+     * @see #setDurationBetweenEvictionRuns(Duration)
+     * @since 2.10.0
+     */
+    public synchronized Duration getDurationBetweenEvictionRuns() {
+        return this.durationBetweenEvictionRuns;
+    }
+
     /**
      * Gets the value of the flag that controls whether or not connections 
being returned to the pool will be checked
      * and configured with {@link Connection#setAutoCommit(boolean) 
Connection.setAutoCommit(true)} if the auto commit
@@ -1199,7 +1213,9 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * Gets the password passed to the JDBC driver to establish connections.
      *
      * @return the connection password
+     * @deprecated Exposing passwords via JMX is an Information Exposure issue.
      */
+    @Deprecated
     @Override
     public String getPassword() {
         return this.password;
@@ -1400,17 +1416,6 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
         return this.testWhileIdle;
     }
 
-    /**
-     * Gets the value of the {code durationBetweenEvictionRuns} property.
-     *
-     * @return the time (in milliseconds) between evictor runs
-     * @see #setDurationBetweenEvictionRuns(Duration)
-     * @since 2.10.0
-     */
-    public synchronized Duration getDurationBetweenEvictionRuns() {
-        return this.durationBetweenEvictionRuns;
-    }
-
     /**
      * Gets the value of the {code durationBetweenEvictionRuns} property.
      *
@@ -1438,7 +1443,9 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * Gets the JDBC connection {code userName} property.
      *
      * @return the {code userName} passed to the JDBC driver to establish 
connections
+     * @deprecated Replaced with DataSourceMXBean.getUserName()
      */
+    @Deprecated
     @Override
     public String getUsername() {
         return this.userName;
@@ -1459,21 +1466,21 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * Gets the validation query timeout.
      *
      * @return the timeout in seconds before connection validation queries 
fail.
+     * @deprecated Use {@link #getValidationQueryTimeoutDuration()}.
      */
-    public Duration getValidationQueryTimeoutDuration() {
-        return validationQueryTimeoutDuration;
+    @Deprecated
+    @Override
+    public int getValidationQueryTimeout() {
+        return (int) validationQueryTimeoutDuration.getSeconds();
     }
 
     /**
      * Gets the validation query timeout.
      *
      * @return the timeout in seconds before connection validation queries 
fail.
-     * @deprecated Use {@link #getValidationQueryTimeoutDuration()}.
      */
-    @Deprecated
-    @Override
-    public int getValidationQueryTimeout() {
-        return (int) validationQueryTimeoutDuration.getSeconds();
+    public Duration getValidationQueryTimeoutDuration() {
+        return validationQueryTimeoutDuration;
     }
 
     /**
@@ -1693,12 +1700,6 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
         }
     }
 
-    private <T> void setConnectionPool(final 
BiConsumer<GenericObjectPool<PoolableConnection>, T> consumer, final T object) {
-        if (connectionPool != null) {
-            consumer.accept(connectionPool, object);
-        }
-    }
-
     /**
      * Sets the print writer to be used by this configuration to log 
information on abandoned objects.
      *
@@ -1779,7 +1780,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
     }
 
     /**
-     * Sets the list of SQL statements to be executed when a physical 
connection is first created.
+     * Sets the collection of SQL statements to be executed when a physical 
connection is first created.
      * <p>
      * Note: this method currently has no effect once the pool has been 
initialized. The pool is initialized the first
      * time one of the following methods is invoked: <code>getConnection, 
setLogwriter,
@@ -1789,25 +1790,32 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * @param connectionInitSqls Collection of SQL statements to execute on 
connection creation
      */
     public void setConnectionInitSqls(final Collection<String> 
connectionInitSqls) {
-//        if (connectionInitSqls != null && !connectionInitSqls.isEmpty()) {
-//            ArrayList<String> newVal = null;
-//            for (final String s : connectionInitSqls) {
-//                if (!isEmpty(s)) {
-//                    if (newVal == null) {
-//                        newVal = new ArrayList<>();
-//                    }
-//                    newVal.add(s);
-//                }
-//            }
-//            this.connectionInitSqls = newVal;
-//        } else {
-//            this.connectionInitSqls = null;
-//        }
         final List<String> collect = Utils.isEmpty(connectionInitSqls) ? null
                 : connectionInitSqls.stream().filter(s -> 
!isEmpty(s)).collect(Collectors.toList());
         this.connectionInitSqls = Utils.isEmpty(collect) ? null : collect;
     }
 
+    /**
+     * Sets the list of SQL statements to be executed when a physical 
connection is first created.
+     * <p>
+     * Note: this method currently has no effect once the pool has been 
initialized. The pool is initialized the first
+     * time one of the following methods is invoked: <code>getConnection, 
setLogwriter,
+     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+     * </p>
+     *
+     * @param connectionInitSqls List of SQL statements to execute on 
connection creation
+     * @since 2.12.0
+     */
+    public void setConnectionInitSqls(final List<String> connectionInitSqls) {
+        setConnectionInitSqls((Collection<String>) connectionInitSqls);
+    }
+
+    private <T> void setConnectionPool(final 
BiConsumer<GenericObjectPool<PoolableConnection>, T> consumer, final T object) {
+        if (connectionPool != null) {
+            consumer.accept(connectionPool, object);
+        }
+    }
+
     /**
      * Sets the connection properties passed to driver.connect(...).
      * <p>
@@ -1955,20 +1963,6 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * @since 2.1
      */
     public void setDisconnectionSqlCodes(final Collection<String> 
disconnectionSqlCodes) {
-//        if (disconnectionSqlCodes != null && 
!disconnectionSqlCodes.isEmpty()) {
-//            HashSet<String> newVal = null;
-//            for (final String s : disconnectionSqlCodes) {
-//                if (!isEmpty(s)) {
-//                    if (newVal == null) {
-//                        newVal = new HashSet<>();
-//                    }
-//                    newVal.add(s);
-//                }
-//            }
-//            this.disconnectionSqlCodes = newVal;
-//        } else {
-//            this.disconnectionSqlCodes = null;
-//        }
         final Set<String> collect = Utils.isEmpty(disconnectionSqlCodes) ? null
                 : disconnectionSqlCodes.stream().filter(s -> 
!isEmpty(s)).collect(Collectors.toSet());
         this.disconnectionSqlCodes = Utils.isEmpty(collect) ? null : collect;
@@ -2016,6 +2010,18 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
         this.driverClassName = isEmpty(driverClassName) ? null : 
driverClassName;
     }
 
+    /**
+     * Sets the {code durationBetweenEvictionRuns} property.
+     *
+     * @param timeBetweenEvictionRunsMillis the new time between evictor runs
+     * @see #setDurationBetweenEvictionRuns(Duration)
+     * @since 2.10.0
+     */
+    public synchronized void setDurationBetweenEvictionRuns(final Duration 
timeBetweenEvictionRunsMillis) {
+        this.durationBetweenEvictionRuns = timeBetweenEvictionRunsMillis;
+        setConnectionPool(GenericObjectPool::setDurationBetweenEvictionRuns, 
timeBetweenEvictionRunsMillis);
+    }
+
     /**
      * Sets the value of the flag that controls whether or not connections 
being returned to the pool will be checked
      * and configured with {@link Connection#setAutoCommit(boolean) 
Connection.setAutoCommit(true)} if the auto commit
@@ -2075,16 +2081,6 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
         this.jmxName = jmxName;
     }
 
-    /**
-     * Sets if connection level JMX tracking is requested for this DataSource. 
If true, each connection will be
-     * registered for tracking with JMX.
-     *
-     * @param registerConnectionMBean connection tracking requested for this 
DataSource.
-     */
-    public void setRegisterConnectionMBean(final boolean 
registerConnectionMBean) {
-        this.registerConnectionMBean = registerConnectionMBean;
-    }
-
     /**
      * Sets the LIFO property. True means the pool behaves as a LIFO queue; 
false means FIFO.
      *
@@ -2118,7 +2114,7 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
      * <strong>BasicDataSource does NOT support this method. </strong>
      *
      * <p>
-     * Set the login timeout (in seconds) for connecting to the database.
+     * Sets the login timeout (in seconds) for connecting to the database.
      * </p>
      * <p>
      * Calls {@link #createDataSource()}, so has the side effect of 
initializing the connection pool.
@@ -2322,6 +2318,16 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
         this.poolPreparedStatements = poolingStatements;
     }
 
+    /**
+     * Sets if connection level JMX tracking is requested for this DataSource. 
If true, each connection will be
+     * registered for tracking with JMX.
+     *
+     * @param registerConnectionMBean connection tracking requested for this 
DataSource.
+     */
+    public void setRegisterConnectionMBean(final boolean 
registerConnectionMBean) {
+        this.registerConnectionMBean = registerConnectionMBean;
+    }
+
     /**
      * @param removeAbandonedOnBorrow true means abandoned connections may be 
removed when connections are borrowed from
      *                                the pool.
@@ -2458,18 +2464,6 @@ public class BasicDataSource implements DataSource, 
BasicDataSourceMXBean, MBean
         setConnectionPool(GenericObjectPool::setTestWhileIdle, 
Boolean.valueOf(testWhileIdle));
     }
 
-    /**
-     * Sets the {code durationBetweenEvictionRuns} property.
-     *
-     * @param timeBetweenEvictionRunsMillis the new time between evictor runs
-     * @see #setDurationBetweenEvictionRuns(Duration)
-     * @since 2.10.0
-     */
-    public synchronized void setDurationBetweenEvictionRuns(final Duration 
timeBetweenEvictionRunsMillis) {
-        this.durationBetweenEvictionRuns = timeBetweenEvictionRunsMillis;
-        setConnectionPool(GenericObjectPool::setDurationBetweenEvictionRuns, 
timeBetweenEvictionRunsMillis);
-    }
-
     /**
      * Sets the {code durationBetweenEvictionRuns} property.
      *
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceFactory.java 
b/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceFactory.java
index daa7cf0091..8e736624a9 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceFactory.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceFactory.java
@@ -24,7 +24,6 @@ import java.sql.SQLException;
 import java.time.Duration;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.Enumeration;
 import java.util.Hashtable;
 import java.util.LinkedHashMap;
@@ -331,7 +330,7 @@ public class BasicDataSourceFactory implements 
ObjectFactory {
         if (propText != null) {
             try {
                 p.load(new ByteArrayInputStream(propText.replace(';', 
'\n').getBytes(StandardCharsets.ISO_8859_1)));
-            } catch (IOException e) {
+            } catch (final IOException e) {
                 throw new SQLException(propText, e);
             }
         }
@@ -339,7 +338,7 @@ public class BasicDataSourceFactory implements 
ObjectFactory {
     }
 
     /**
-     * Parse list of property values from a delimited string
+     * Parses list of property values from a delimited string
      *
      * @param value
      *            delimited list of values
@@ -347,9 +346,9 @@ public class BasicDataSourceFactory implements 
ObjectFactory {
      *            character used to separate values in the list
      * @return String Collection of values
      */
-    private static Collection<String> parseList(final String value, final char 
delimiter) {
+    private static List<String> parseList(final String value, final char 
delimiter) {
         final StringTokenizer tokenizer = new StringTokenizer(value, 
Character.toString(delimiter));
-        final Collection<String> tokens = new 
ArrayList<>(tokenizer.countTokens());
+        final List<String> tokens = new ArrayList<>(tokenizer.countTokens());
         while (tokenizer.hasMoreTokens()) {
             tokens.add(tokenizer.nextToken());
         }
@@ -420,20 +419,18 @@ public class BasicDataSourceFactory implements 
ObjectFactory {
      *            container for info messages
      */
     private void validatePropertyNames(final Reference ref, final Name name, 
final List<String> warnMessages,
-        final List<String> infoMessages) {
+            final List<String> infoMessages) {
         final String nameString = name != null ? "Name = " + name.toString() + 
" " : "";
-        if (NUPROP_WARNTEXT != null && !NUPROP_WARNTEXT.isEmpty()) {
-            NUPROP_WARNTEXT.forEach((propertyName, value) -> {
-                final RefAddr ra = ref.get(propertyName);
-                if (ra != null && !ALL_PROPERTY_NAMES.contains(ra.getType())) {
-                    final StringBuilder stringBuilder = new 
StringBuilder(nameString);
-                    final String propertyValue = 
Objects.toString(ra.getContent(), null);
-                    stringBuilder.append(value).append(" You have set value of 
\"").append(propertyValue).append("\" for \"").append(propertyName)
+        NUPROP_WARNTEXT.forEach((propertyName, value) -> {
+            final RefAddr ra = ref.get(propertyName);
+            if (ra != null && !ALL_PROPERTY_NAMES.contains(ra.getType())) {
+                final StringBuilder stringBuilder = new 
StringBuilder(nameString);
+                final String propertyValue = Objects.toString(ra.getContent(), 
null);
+                stringBuilder.append(value).append(" You have set value of 
\"").append(propertyValue).append("\" for \"").append(propertyName)
                         .append("\" property, which is being ignored.");
-                    warnMessages.add(stringBuilder.toString());
-                }
-            });
-        }
+                warnMessages.add(stringBuilder.toString());
+            }
+        });
 
         final Enumeration<RefAddr> allRefAddrs = ref.getAll();
         while (allRefAddrs.hasMoreElements()) {
@@ -445,7 +442,7 @@ public class BasicDataSourceFactory implements 
ObjectFactory {
                 final String propertyValue = Objects.toString(ra.getContent(), 
null);
                 final StringBuilder stringBuilder = new 
StringBuilder(nameString);
                 stringBuilder.append("Ignoring unknown property: 
").append("value of \"").append(propertyValue).append("\" for 
\"").append(propertyName)
-                    .append("\" property");
+                        .append("\" property");
                 infoMessages.add(stringBuilder.toString());
             }
         }
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceMXBean.java 
b/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceMXBean.java
index 06798a368b..84c3a6765d 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceMXBean.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceMXBean.java
@@ -31,7 +31,7 @@ public interface BasicDataSourceMXBean extends 
DataSourceMXBean {
      * See {@link BasicDataSource#getPassword()}
      *
      * @return {@link BasicDataSource#getPassword()}
-     * @deprecated exposing password via JMX is an Information Exposure issue.
+     * @deprecated Exposing passwords via JMX is an Information Exposure issue.
      */
     @Deprecated
     String getPassword();
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/ConnectionFactoryFactory.java 
b/java/org/apache/tomcat/dbcp/dbcp2/ConnectionFactoryFactory.java
index 01d5894c79..57d4f7b07b 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/ConnectionFactoryFactory.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/ConnectionFactoryFactory.java
@@ -42,13 +42,14 @@ final class ConnectionFactoryFactory {
         final Properties connectionProperties = 
basicDataSource.getConnectionProperties();
         final String url = basicDataSource.getUrl();
         // Set up the driver connection factory we will use
-        final String user = basicDataSource.getUsername();
+        final String user = basicDataSource.getUserName();
         if (user != null) {
             connectionProperties.put(Constants.KEY_USER, user);
         } else {
             basicDataSource.log(String.format("DBCP DataSource configured 
without a '%s'", Constants.KEY_USER));
         }
 
+        @SuppressWarnings("deprecation")
         final String pwd = basicDataSource.getPassword();
         if (pwd != null) {
             connectionProperties.put(Constants.KEY_PASSWORD, pwd);
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/DataSourceMXBean.java 
b/java/org/apache/tomcat/dbcp/dbcp2/DataSourceMXBean.java
index f6dbef1dd8..de2afe062c 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/DataSourceMXBean.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/DataSourceMXBean.java
@@ -280,9 +280,22 @@ public interface DataSourceMXBean {
      * See {@link BasicDataSource#getUsername()}.
      *
      * @return {@link BasicDataSource#getUsername()}.
+     * @deprecated Use {@link #getUserName()}.
      */
+    @Deprecated
     String getUsername();
 
+    /**
+     * See {@link BasicDataSource#getUsername()}.
+     *
+     * @return {@link BasicDataSource#getUsername()}.
+     * @since 2.11.0
+     */
+    @SuppressWarnings("javadoc")
+    default String getUserName() {
+        return getUsername();
+    }
+
     /**
      * See {@link BasicDataSource#getValidationQuery()}.
      *
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingConnection.java 
b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingConnection.java
index a9e620d3b7..3d9624dc94 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingConnection.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingConnection.java
@@ -120,7 +120,7 @@ public class DelegatingConnection<C extends Connection> 
extends AbandonedTrace i
     }
 
     /**
-     * Clears the cached state. Call when you known that the underlying 
connection may have been accessed
+     * Clears the cached state. Call when you know that the underlying 
connection may have been accessed
      * directly.
      */
     public void clearCachedState() {
@@ -646,7 +646,7 @@ public class DelegatingConnection<C extends Connection> 
extends AbandonedTrace i
 
     protected void passivate() throws SQLException {
         // The JDBC specification requires that a Connection close any open
-        // Statement's when it is closed.
+        // Statements when it is closed.
         // DBCP-288. Not all the traced objects will be statements
         final List<AbandonedTrace> traceList = getTrace();
         if (!Utils.isEmpty(traceList)) {
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingDatabaseMetaData.java 
b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingDatabaseMetaData.java
index fa9bfaa34e..79543e401b 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingDatabaseMetaData.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingDatabaseMetaData.java
@@ -21,6 +21,7 @@ import java.sql.DatabaseMetaData;
 import java.sql.ResultSet;
 import java.sql.RowIdLifetime;
 import java.sql.SQLException;
+import java.util.Objects;
 
 /**
  * <p>
@@ -51,8 +52,8 @@ public class DelegatingDatabaseMetaData implements 
DatabaseMetaData {
      */
     public DelegatingDatabaseMetaData(final DelegatingConnection<?> connection,
             final DatabaseMetaData databaseMetaData) {
-        this.connection = connection;
-        this.databaseMetaData = databaseMetaData;
+        this.connection = Objects.requireNonNull(connection, "connection");
+        this.databaseMetaData = Objects.requireNonNull(databaseMetaData, 
"databaseMetaData");
     }
 
     @Override
@@ -1894,7 +1895,6 @@ public class DelegatingDatabaseMetaData implements 
DatabaseMetaData {
         }
     }
 
-
     @Override
     public <T> T unwrap(final Class<T> iface) throws SQLException {
         if (iface.isAssignableFrom(getClass())) {
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingPreparedStatement.java 
b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingPreparedStatement.java
index 0dd7668a95..8c0cc3200a 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingPreparedStatement.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingPreparedStatement.java
@@ -167,6 +167,27 @@ public class DelegatingPreparedStatement extends 
DelegatingStatement implements
         }
     }
 
+    protected void prepareToReturn() throws SQLException {
+        setClosedInternal(true);
+        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> traceList = getTrace();
+        if (traceList != null) {
+            final List<Exception> thrownList = new ArrayList<>();
+            traceList.forEach(trace -> trace.close(thrownList::add));
+            clearTrace();
+            if (!thrownList.isEmpty()) {
+                throw new SQLExceptionList(thrownList);
+            }
+        }
+
+        super.passivate();
+    }
+
     @Override
     public void setArray(final int i, final Array x) throws SQLException {
         checkOpen();
@@ -694,25 +715,4 @@ public class DelegatingPreparedStatement extends 
DelegatingStatement implements
         final Statement statement = getDelegate();
         return statement == null ? "NULL" : statement.toString();
     }
-
-    protected void prepareToReturn() throws SQLException {
-        setClosedInternal(true);
-        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> traceList = getTrace();
-        if (traceList != null) {
-            final List<Exception> thrownList = new ArrayList<>();
-            traceList.forEach(trace -> trace.close(thrownList::add));
-            clearTrace();
-            if (!thrownList.isEmpty()) {
-                throw new SQLExceptionList(thrownList);
-            }
-        }
-
-        super.passivate();
-    }
 }
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingResultSet.java 
b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingResultSet.java
index 227d806833..cbee420a75 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingResultSet.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingResultSet.java
@@ -97,7 +97,7 @@ public final class DelegatingResultSet extends AbandonedTrace 
implements ResultS
 
     /**
      * Creates a wrapper for the ResultSet which traces this ResultSet to the 
Connection which created it (via, for
-     * example DatabaseMetadata, and the code which created it.
+     * example DatabaseMetadata), and the code which created it.
      * <p>
      * Private to ensure all construction is {@link #wrapResultSet(Connection, 
ResultSet)}
      * </p>
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingStatement.java 
b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingStatement.java
index ff5d937fc4..968aecee02 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingStatement.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingStatement.java
@@ -448,19 +448,19 @@ public class DelegatingStatement extends AbandonedTrace 
implements Statement {
      * a "genuine" {@link Statement}.
      * </p>
      *
-     * @return The innermost delegate.
+     * @return The innermost delegate, may return null.
      *
      * @see #getDelegate
      */
     public Statement getInnermostDelegate() {
-        Statement s = statement;
-        while (s instanceof DelegatingStatement) {
-            s = ((DelegatingStatement) s).getDelegate();
-            if (this == s) {
+        Statement stmt = statement;
+        while (stmt instanceof DelegatingStatement) {
+            stmt = ((DelegatingStatement) stmt).getDelegate();
+            if (this == stmt) {
                 return null;
             }
         }
-        return s;
+        return stmt;
     }
 
     /**
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/Jdbc41Bridge.java 
b/java/org/apache/tomcat/dbcp/dbcp2/Jdbc41Bridge.java
index baf1a2a596..64e8552b7d 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/Jdbc41Bridge.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/Jdbc41Bridge.java
@@ -41,8 +41,8 @@ import java.util.logging.Logger;
 import javax.sql.CommonDataSource;
 
 /**
- * Defines bridge methods to JDBC 4.1 (Java 7) methods to allow call sites to 
operate safely (without
- * {@link AbstractMethodError}) when using a JDBC driver written for JDBC 4.0 
(Java 6).
+ * Defines bridge methods to JDBC 4.1 (Java 7 or above) methods to allow call 
sites to operate safely (without
+ * {@link AbstractMethodError}) when using a JDBC driver written for JDBC 4.0 
(Java 6 or above).
  * <p>
  * There should be no need to this kind of code for JDBC 4.2 in Java 8 due to 
JDBC's use of default methods.
  * </p>
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/PoolableCallableStatement.java 
b/java/org/apache/tomcat/dbcp/dbcp2/PoolableCallableStatement.java
index 08d690d424..0bb84c0347 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/PoolableCallableStatement.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/PoolableCallableStatement.java
@@ -44,7 +44,7 @@ public class PoolableCallableStatement extends 
DelegatingCallableStatement {
     private final PStmtKey key;
 
     /**
-     * Constructor.
+     * Constructs a new instance.
      *
      * @param callableStatement
      *            the underlying {@link CallableStatement}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnection.java 
b/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnection.java
index 3ad15ada77..0459d176db 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnection.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnection.java
@@ -24,6 +24,8 @@ import java.sql.SQLException;
 import java.time.Duration;
 import java.util.Collection;
 import java.util.concurrent.Executor;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
 
 import javax.management.InstanceAlreadyExistsException;
 import javax.management.MBeanRegistrationException;
@@ -32,6 +34,7 @@ import javax.management.NotCompliantMBeanException;
 import javax.management.ObjectName;
 
 import org.apache.tomcat.dbcp.pool2.ObjectPool;
+import org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool;
 
 /**
  * A delegating connection that, rather than closing the underlying 
connection, returns itself to an {@link ObjectPool}
@@ -76,6 +79,8 @@ public class PoolableConnection extends 
DelegatingConnection<Connection> impleme
     /** Whether or not to fast fail validation after fatal connection errors */
     private final boolean fastFailValidation;
 
+    private final Lock lock = new ReentrantLock();
+
     /**
      * @param conn
      *            my underlying connection
@@ -137,59 +142,64 @@ public class PoolableConnection extends 
DelegatingConnection<Connection> impleme
      * Returns me to my pool.
      */
     @Override
-    public synchronized void close() throws SQLException {
-        if (isClosedInternal()) {
-            // already closed
-            return;
-        }
-
-        boolean isUnderlyingConnectionClosed;
+    public void close() throws SQLException {
+        lock.lock();
         try {
-            isUnderlyingConnectionClosed = getDelegateInternal().isClosed();
-        } catch (final SQLException e) {
-            try {
-                pool.invalidateObject(this);
-            } catch (final IllegalStateException ise) {
-                // pool is closed, so close the connection
-                passivate();
-                getInnermostDelegate().close();
-            } catch (final Exception ignored) {
-                // DO NOTHING the original exception will be rethrown
+            if (isClosedInternal()) {
+                // already closed
+                return;
             }
-            throw new SQLException("Cannot close connection (isClosed check 
failed)", e);
-        }
 
-        /*
-         * Can't set close before this code block since the connection needs 
to be open when validation runs. Can't set
-         * close after this code block since by then the connection will have 
been returned to the pool and may have
-         * been borrowed by another thread. Therefore, the close flag is set 
in passivate().
-         */
-        if (isUnderlyingConnectionClosed) {
-            // Abnormal close: underlying connection closed unexpectedly, so we
-            // must destroy this proxy
+            boolean isUnderlyingConnectionClosed;
             try {
-                pool.invalidateObject(this);
-            } catch (final IllegalStateException e) {
-                // pool is closed, so close the connection
-                passivate();
-                getInnermostDelegate().close();
-            } catch (final Exception e) {
-                throw new SQLException("Cannot close connection (invalidating 
pooled object failed)", e);
+                isUnderlyingConnectionClosed = 
getDelegateInternal().isClosed();
+            } catch (final SQLException e) {
+                try {
+                    pool.invalidateObject(this);
+                } catch (final IllegalStateException ise) {
+                    // pool is closed, so close the connection
+                    passivate();
+                    getInnermostDelegate().close();
+                } catch (final Exception ignored) {
+                    // DO NOTHING the original exception will be rethrown
+                }
+                throw new SQLException("Cannot close connection (isClosed 
check failed)", e);
             }
-        } else {
-            // Normal close: underlying connection is still open, so we
-            // simply need to return this proxy to the pool
-            try {
-                pool.returnObject(this);
-            } catch (final IllegalStateException e) {
-                // pool is closed, so close the connection
-                passivate();
-                getInnermostDelegate().close();
-            } catch (final SQLException | RuntimeException e) {
-                throw e;
-            } catch (final Exception e) {
-                throw new SQLException("Cannot close connection (return to 
pool failed)", e);
+
+            /*
+             * Can't set close before this code block since the connection 
needs to be open when validation runs. Can't set
+             * close after this code block since by then the connection will 
have been returned to the pool and may have
+             * been borrowed by another thread. Therefore, the close flag is 
set in passivate().
+             */
+            if (isUnderlyingConnectionClosed) {
+                // Abnormal close: underlying connection closed unexpectedly, 
so we
+                // must destroy this proxy
+                try {
+                    pool.invalidateObject(this);
+                } catch (final IllegalStateException e) {
+                    // pool is closed, so close the connection
+                    passivate();
+                    getInnermostDelegate().close();
+                } catch (final Exception e) {
+                    throw new SQLException("Cannot close connection 
(invalidating pooled object failed)", e);
+                }
+            } else {
+                // Normal close: underlying connection is still open, so we
+                // simply need to return this proxy to the pool
+                try {
+                    pool.returnObject(this);
+                } catch (final IllegalStateException e) {
+                    // pool is closed, so close the connection
+                    passivate();
+                    getInnermostDelegate().close();
+                } catch (final SQLException | RuntimeException e) {
+                    throw e;
+                } catch (final Exception e) {
+                    throw new SQLException("Cannot close connection (return to 
pool failed)", e);
+                }
             }
+        } finally {
+            lock.unlock();
         }
     }
 
@@ -202,7 +212,7 @@ public class PoolableConnection extends 
DelegatingConnection<Connection> impleme
     }
 
     /**
-     * Expose the {@link #toString()} method via a bean getter so it can be 
read as a property via JMX.
+     * Expose the {@link #toString()} method via a bean getter, so it can be 
read as a property via JMX.
      */
     @Override
     public String getToString() {
@@ -262,6 +272,14 @@ public class PoolableConnection extends 
DelegatingConnection<Connection> impleme
         return fatalException;
     }
 
+    /**
+     * @return Whether to fail-fast.
+     * @since 2.6.0
+     */
+    public boolean isFastFailValidation() {
+        return fastFailValidation;
+    }
+
     /**
      * Checks the SQLState of the input exception and any nested SQLExceptions 
it wraps.
      * <p>
@@ -289,14 +307,6 @@ public class PoolableConnection extends 
DelegatingConnection<Connection> impleme
         return fatalException;
     }
 
-    /**
-     * @return Whether to fail-fast.
-     * @since 2.6.0
-     */
-    public boolean isFastFailValidation() {
-        return fastFailValidation;
-    }
-
     @Override
     protected void passivate() throws SQLException {
         super.passivate();
@@ -322,28 +332,15 @@ public class PoolableConnection extends 
DelegatingConnection<Connection> impleme
         super.closeInternal();
     }
 
-    /**
-     * Validates the connection, using the following algorithm:
-     * <ol>
-     * <li>If {@code fastFailValidation} (constructor argument) is {@code 
true} and this connection has previously
-     * thrown a fatal disconnection exception, a {@code SQLException} is 
thrown.</li>
-     * <li>If {@code sql} is null, the driver's #{@link 
Connection#isValid(int) isValid(timeout)} is called. If it
-     * returns {@code false}, {@code SQLException} is thrown; otherwise, this 
method returns successfully.</li>
-     * <li>If {@code sql} is not null, it is executed as a query and if the 
resulting {@code ResultSet} contains at
-     * least one row, this method returns successfully. If not, {@code 
SQLException} is thrown.</li>
-     * </ol>
-     *
-     * @param sql
-     *            The validation SQL query.
-     * @param timeoutSeconds
-     *            The validation timeout in seconds.
-     * @throws SQLException
-     *             Thrown when validation fails or an SQLException occurs 
during validation
-     * @deprecated Use {@link #validate(String, Duration)}.
-     */
-    @Deprecated
-    public void validate(final String sql, final int timeoutSeconds) throws 
SQLException {
-        validate(sql, Duration.ofSeconds(timeoutSeconds));
+    @Override
+    public void setLastUsed() {
+        super.setLastUsed();
+        if (pool instanceof GenericObjectPool<?>) {
+            final GenericObjectPool<PoolableConnection> gop = 
(GenericObjectPool<PoolableConnection>) pool;
+            if (gop.isAbandonedConfig()) {
+                gop.use(this);
+            }
+        }
     }
 
     /**
@@ -399,4 +396,28 @@ public class PoolableConnection extends 
DelegatingConnection<Connection> impleme
             throw sqle;
         }
     }
+
+    /**
+     * Validates the connection, using the following algorithm:
+     * <ol>
+     * <li>If {@code fastFailValidation} (constructor argument) is {@code 
true} and this connection has previously
+     * thrown a fatal disconnection exception, a {@code SQLException} is 
thrown.</li>
+     * <li>If {@code sql} is null, the driver's #{@link 
Connection#isValid(int) isValid(timeout)} is called. If it
+     * returns {@code false}, {@code SQLException} is thrown; otherwise, this 
method returns successfully.</li>
+     * <li>If {@code sql} is not null, it is executed as a query and if the 
resulting {@code ResultSet} contains at
+     * least one row, this method returns successfully. If not, {@code 
SQLException} is thrown.</li>
+     * </ol>
+     *
+     * @param sql
+     *            The validation SQL query.
+     * @param timeoutSeconds
+     *            The validation timeout in seconds.
+     * @throws SQLException
+     *             Thrown when validation fails or an SQLException occurs 
during validation
+     * @deprecated Use {@link #validate(String, Duration)}.
+     */
+    @Deprecated
+    public void validate(final String sql, final int timeoutSeconds) throws 
SQLException {
+        validate(sql, Duration.ofSeconds(timeoutSeconds));
+    }
 }
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnectionFactory.java 
b/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnectionFactory.java
index b0c9ef9501..4ebede76c5 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnectionFactory.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnectionFactory.java
@@ -458,7 +458,7 @@ public class PoolableConnectionFactory implements 
PooledObjectFactory<PoolableCo
             final String name = dataSourceJmxObjectName.toString() + 
Constants.JMX_CONNECTION_BASE_EXT + connIndex;
             try {
                 connJmxName = new ObjectName(name);
-            } catch (MalformedObjectNameException e) {
+            } catch (final MalformedObjectNameException e) {
                 Utils.closeQuietly((AutoCloseable) conn);
                 throw new SQLException(name, e);
             }
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/PoolablePreparedStatement.java 
b/java/org/apache/tomcat/dbcp/dbcp2/PoolablePreparedStatement.java
index 30723e0320..6da7a269f9 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/PoolablePreparedStatement.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/PoolablePreparedStatement.java
@@ -49,12 +49,12 @@ public class PoolablePreparedStatement<K> extends 
DelegatingPreparedStatement {
     private volatile boolean batchAdded;
 
     /**
-     * Constructor.
+     * Constructs a new instance.
      *
      * @param stmt
      *            my underlying {@link PreparedStatement}
      * @param key
-     *            my key" as used by {@link KeyedObjectPool}
+     *            my key as used by {@link KeyedObjectPool}
      * @param pool
      *            the {@link KeyedObjectPool} from which I was obtained.
      * @param conn
@@ -113,6 +113,15 @@ public class PoolablePreparedStatement<K> extends 
DelegatingPreparedStatement {
         }
     }
 
+    /**
+     * Package-protected for tests.
+     *
+     * @return The key.
+     */
+    K getKey() {
+        return key;
+    }
+
     @Override
     public void passivate() throws SQLException {
         // DBCP-372. clearBatch with throw an exception if called when the
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/PoolingConnection.java 
b/java/org/apache/tomcat/dbcp/dbcp2/PoolingConnection.java
index b35e031833..fc609e6a98 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/PoolingConnection.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/PoolingConnection.java
@@ -20,6 +20,7 @@ import java.sql.CallableStatement;
 import java.sql.Connection;
 import java.sql.PreparedStatement;
 import java.sql.SQLException;
+import java.sql.Statement;
 import java.util.NoSuchElementException;
 import java.util.Objects;
 
@@ -27,6 +28,7 @@ import org.apache.tomcat.dbcp.pool2.KeyedObjectPool;
 import org.apache.tomcat.dbcp.pool2.KeyedPooledObjectFactory;
 import org.apache.tomcat.dbcp.pool2.PooledObject;
 import org.apache.tomcat.dbcp.pool2.impl.DefaultPooledObject;
+import org.apache.tomcat.dbcp.pool2.impl.GenericKeyedObjectPool;
 
 /**
  * A {@link DelegatingConnection} that pools {@link PreparedStatement}s.
@@ -46,18 +48,27 @@ public class PoolingConnection extends 
DelegatingConnection<Connection>
     /**
      * Statement types.
      *
+     * See subclasses of {@link Statement}.
+     *
      * @since 2.0 protected enum.
      * @since 2.4.0 public enum.
+     * @see Statement
+     * @see CallableStatement
+     * @see PreparedStatement
      */
     public enum StatementType {
 
         /**
          * Callable statement.
+         *
+         * @see CallableStatement
          */
         CALLABLE_STATEMENT,
 
         /**
          * Prepared statement.
+         *
+         * @see PreparedStatement
          */
         PREPARED_STATEMENT
     }
@@ -68,7 +79,7 @@ public class PoolingConnection extends 
DelegatingConnection<Connection>
     private boolean clearStatementPoolOnReturn;
 
     /**
-     * Constructor.
+     * Constructs a new instance.
      *
      * @param connection
      *            the underlying {@link Connection}.
@@ -292,9 +303,16 @@ public class PoolingConnection extends 
DelegatingConnection<Connection>
      *            the wrapped pooled statement to be destroyed.
      */
     @Override
-    public void destroyObject(final PStmtKey key, final 
PooledObject<DelegatingPreparedStatement> pooledObject)
-            throws SQLException {
-        pooledObject.getObject().getInnermostDelegate().close();
+    public void destroyObject(final PStmtKey key, final 
PooledObject<DelegatingPreparedStatement> pooledObject) throws SQLException {
+        if (pooledObject != null) {
+            final DelegatingPreparedStatement object = 
pooledObject.getObject();
+            if (object != null) {
+                final Statement innermostDelegate = 
object.getInnermostDelegate();
+                if (innermostDelegate != null) {
+                    innermostDelegate.close();
+                }
+            }
+        }
     }
 
     private String getCatalogOrNull() {
@@ -550,7 +568,6 @@ public class PoolingConnection extends 
DelegatingConnection<Connection>
      * @return a {@link PoolablePreparedStatement}
      * @throws SQLException
      *             Wraps an underlying exception.
-     *
      */
     @Override
     public PreparedStatement prepareStatement(final String sql, final int[] 
columnIndexes) throws SQLException {
@@ -596,11 +613,18 @@ public class PoolingConnection extends 
DelegatingConnection<Connection>
 
     @Override
     public synchronized String toString() {
+        if (pStmtPool instanceof GenericKeyedObjectPool) {
+            // DBCP-596 PoolingConnection.toString() causes StackOverflowError
+            final GenericKeyedObjectPool<?, ?> gkop = 
(GenericKeyedObjectPool<?, ?>) pStmtPool;
+            if (gkop.getFactory() == this) {
+                return "PoolingConnection: " + pStmtPool.getClass() + "@" + 
System.identityHashCode(pStmtPool);
+            }
+        }
         return "PoolingConnection: " + Objects.toString(pStmtPool);
     }
 
     /**
-     * {@link KeyedPooledObjectFactory} method for validating pooled 
statements. Currently always returns true.
+     * {@link KeyedPooledObjectFactory} method for validating pooled 
statements. Currently, always returns true.
      *
      * @param key
      *            ignored
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/PoolingDataSource.java 
b/java/org/apache/tomcat/dbcp/dbcp2/PoolingDataSource.java
index f11e1dfa4d..7293a115ac 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/PoolingDataSource.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/PoolingDataSource.java
@@ -46,7 +46,7 @@ public class PoolingDataSource<C extends Connection> 
implements DataSource, Auto
      *
      * @since 2.0
      */
-    private class PoolGuardConnectionWrapper<D extends Connection> extends 
DelegatingConnection<D> {
+    private final class PoolGuardConnectionWrapper<D extends Connection> 
extends DelegatingConnection<D> {
 
         PoolGuardConnectionWrapper(final D delegate) {
             super(delegate);
@@ -121,11 +121,9 @@ public class PoolingDataSource<C extends Connection> 
implements DataSource, Auto
      * @since 2.1
      */
     @Override
-    public void close() throws RuntimeException, SQLException {
+    public void close() throws SQLException {
         try {
             pool.close();
-        } catch (final RuntimeException rte) {
-            throw new RuntimeException(Utils.getMessage("pool.close.fail"), 
rte);
         } catch (final Exception e) {
             throw new SQLException(Utils.getMessage("pool.close.fail"), e);
         }
@@ -163,7 +161,7 @@ public class PoolingDataSource<C extends Connection> 
implements DataSource, Auto
      *             always thrown
      */
     @Override
-    public Connection getConnection(final String uname, final String passwd) 
throws SQLException {
+    public Connection getConnection(final String userName, final String 
password) throws SQLException {
         throw new UnsupportedOperationException();
     }
 
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/PoolingDriver.java 
b/java/org/apache/tomcat/dbcp/dbcp2/PoolingDriver.java
index 9b4c878e6e..d758825198 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/PoolingDriver.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/PoolingDriver.java
@@ -41,7 +41,7 @@ public class PoolingDriver implements Driver {
      *
      * @since 2.0
      */
-    private class PoolGuardConnectionWrapper extends 
DelegatingConnection<Connection> {
+    private final class PoolGuardConnectionWrapper extends 
DelegatingConnection<Connection> {
 
         private final ObjectPool<? extends Connection> pool;
 
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/Utils.java 
b/java/org/apache/tomcat/dbcp/dbcp2/Utils.java
index 7b44dcdcb0..fe89dd1c47 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/Utils.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/Utils.java
@@ -13,7 +13,6 @@
  * 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;
 
@@ -115,7 +114,7 @@ public final class Utils {
      * @param exceptionHandler Consumes exception thrown closing this resource.
      * @since 2.10.0
      */
-    public static void close(AutoCloseable autoCloseable, final 
Consumer<Exception> exceptionHandler) {
+    public static void close(final AutoCloseable autoCloseable, final 
Consumer<Exception> exceptionHandler) {
         if (autoCloseable != null) {
             try {
                 autoCloseable.close();
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/ConnectionImpl.java 
b/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/ConnectionImpl.java
index 6b323dd6ec..e187abd60c 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/ConnectionImpl.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/ConnectionImpl.java
@@ -84,7 +84,7 @@ final class ConnectionImpl extends 
DelegatingConnection<Connection> {
     }
 
     /**
-     * Get the delegated connection, if allowed.
+     * Gets the delegated connection, if allowed.
      *
      * @return the internal connection, or null if access is not allowed.
      * @see #isAccessToUnderlyingConnectionAllowed()
@@ -98,7 +98,7 @@ final class ConnectionImpl extends 
DelegatingConnection<Connection> {
     }
 
     /**
-     * Get the innermost connection, if allowed.
+     * Gets the innermost connection, if allowed.
      *
      * @return the innermost internal connection, or null if access is not 
allowed.
      * @see #isAccessToUnderlyingConnectionAllowed()
@@ -111,6 +111,15 @@ final class ConnectionImpl extends 
DelegatingConnection<Connection> {
         return null;
     }
 
+    /**
+     * Package-private for tests.
+     *
+     * @return the PooledConnectionImpl.
+     */
+    PooledConnectionImpl getPooledConnectionImpl() {
+        return pooledConnection;
+    }
+
     /**
      * If false, getDelegate() and getInnermostDelegate() will return null.
      *
@@ -126,7 +135,7 @@ final class ConnectionImpl extends 
DelegatingConnection<Connection> {
      * be returned, otherwise delegate to the wrapped JDBC 1.x {@link 
java.sql.Connection}.
      *
      * @param sql
-     *            an SQL statement that may contain one or more '?' parameter 
placeholders. Typically this statement is
+     *            an SQL statement that may contain one or more '?' parameter 
placeholders. Typically, this statement is
      *            specified using JDBC call escape syntax.
      * @return a default {@code CallableStatement} object containing the 
pre-compiled SQL statement.
      * @throws SQLException
@@ -245,6 +254,10 @@ final class ConnectionImpl extends 
DelegatingConnection<Connection> {
         }
     }
 
+    //
+    // Methods for accessing the delegate connection
+    //
+
     /**
      * If pooling of {@code PreparedStatement}s is turned on in the {@link 
DriverAdapterCPDS}, a pooled object may
      * be returned, otherwise delegate to the wrapped JDBC 1.x {@link 
java.sql.Connection}.
@@ -265,10 +278,6 @@ final class ConnectionImpl extends 
DelegatingConnection<Connection> {
         }
     }
 
-    //
-    // Methods for accessing the delegate connection
-    //
-
     @Override
     public PreparedStatement prepareStatement(final String sql, final int 
resultSetType, final int resultSetConcurrency,
             final int resultSetHoldability) throws SQLException {
diff --git 
a/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java 
b/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java
index 3d93a50932..ae2dc3be23 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java
@@ -63,13 +63,13 @@ import 
org.apache.tomcat.dbcp.pool2.impl.GenericKeyedObjectPoolConfig;
  * </p>
  * <p>
  * The DriverAdapterCPDS also provides {@code PreparedStatement} pooling which 
is not generally available in jdbc2
- * {@code ConnectionPoolDataSource} implementation, but is addressed within 
the jdbc3 specification. The
- * {@code PreparedStatement} pool in DriverAdapterCPDS has been in the dbcp 
package for some time, but it has not
+ * {@code ConnectionPoolDataSource} implementation, but is addressed within 
the JDBC 3 specification. The
+ * {@code PreparedStatement} pool in DriverAdapterCPDS has been in the DBCP 
package for some time, but it has not
  * undergone extensive testing in the configuration used here. It should be 
considered experimental and can be toggled
  * with the poolPreparedStatements attribute.
  * </p>
  * <p>
- * The <a href="package-summary.html">package documentation</a> contains an 
example using catalina and JNDI. The
+ * The <a href="package-summary.html">package documentation</a> contains an 
example using Apache Catalina and JNDI. The
  * <a href="../datasources/package-summary.html">datasources package 
documentation</a> shows how to use
  * {@code DriverAdapterCPDS} as a source for {@code Jdbc2PoolDataSource} 
without the use of JNDI.
  * </p>
@@ -78,13 +78,38 @@ import 
org.apache.tomcat.dbcp.pool2.impl.GenericKeyedObjectPoolConfig;
  */
 public class DriverAdapterCPDS implements ConnectionPoolDataSource, 
Referenceable, Serializable, ObjectFactory {
 
+    private static final String KEY_MIN_EVICTABLE_IDLE_DURATION = 
"minEvictableIdleDuration";
+
+    private static final String KEY_DURATION_BETWEEN_EVICTION_RUNS = 
"durationBetweenEvictionRuns";
+
+    private static final String KEY_LOGIN_TIMEOUT = "loginTimeout";
+
+    private static final String KEY_URL = "url";
+
+    private static final String KEY_DRIVER = "driver";
+
+    private static final String KEY_DESCRIPTION = "description";
+
+    private static final String KEY_ACCESS_TO_UNDERLYING_CONNECTION_ALLOWED = 
"accessToUnderlyingConnectionAllowed";
+
+    private static final String KEY_MAX_PREPARED_STATEMENTS = 
"maxPreparedStatements";
+
+    private static final String KEY_MIN_EVICTABLE_IDLE_TIME_MILLIS = 
"minEvictableIdleTimeMillis";
+
+    private static final String KEY_NUM_TESTS_PER_EVICTION_RUN = 
"numTestsPerEvictionRun";
+
+    private static final String KEY_TIME_BETWEEN_EVICTION_RUNS_MILLIS = 
"timeBetweenEvictionRunsMillis";
+
+    private static final String KEY_MAX_IDLE = "maxIdle";
+
+    private static final String KEY_POOL_PREPARED_STATEMENTS = 
"poolPreparedStatements";
+
     private static final long serialVersionUID = -4820523787212147844L;
 
-    private static final String GET_CONNECTION_CALLED = "A PooledConnection 
was already requested from this source, "
-        + "further initialization is not allowed.";
+    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
+        // Attempt to prevent deadlocks - see DBCP-272
         DriverManager.getDrivers();
     }
 
@@ -271,24 +296,23 @@ public class DriverAdapterCPDS implements 
ConnectionPoolDataSource, Referenceabl
      * 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 ClassNotFoundException {
+    public Object getObjectInstance(final Object refObj, final Name name, 
final Context context, final Hashtable<?, ?> env) throws ClassNotFoundException 
{
         // 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");
+                RefAddr ra = ref.get(KEY_DESCRIPTION);
                 if (isNotEmpty(ra)) {
                     setDescription(getStringContent(ra));
                 }
 
-                ra = ref.get("driver");
+                ra = ref.get(KEY_DRIVER);
                 if (isNotEmpty(ra)) {
                     setDriver(getStringContent(ra));
                 }
-                ra = ref.get("url");
+                ra = ref.get(KEY_URL);
                 if (isNotEmpty(ra)) {
                     setUrl(getStringContent(ra));
                 }
@@ -301,36 +325,36 @@ public class DriverAdapterCPDS implements 
ConnectionPoolDataSource, Referenceabl
                     setPassword(getStringContent(ra));
                 }
 
-                ra = ref.get("poolPreparedStatements");
+                ra = ref.get(KEY_POOL_PREPARED_STATEMENTS);
                 if (isNotEmpty(ra)) {
                     setPoolPreparedStatements(getBooleanContentString(ra));
                 }
-                ra = ref.get("maxIdle");
+                ra = ref.get(KEY_MAX_IDLE);
                 if (isNotEmpty(ra)) {
                     setMaxIdle(getIntegerStringContent(ra));
                 }
 
-                ra = ref.get("timeBetweenEvictionRunsMillis");
+                ra = ref.get(KEY_TIME_BETWEEN_EVICTION_RUNS_MILLIS);
                 if (isNotEmpty(ra)) {
                     
setTimeBetweenEvictionRunsMillis(getIntegerStringContent(ra));
                 }
 
-                ra = ref.get("numTestsPerEvictionRun");
+                ra = ref.get(KEY_NUM_TESTS_PER_EVICTION_RUN);
                 if (isNotEmpty(ra)) {
                     setNumTestsPerEvictionRun(getIntegerStringContent(ra));
                 }
 
-                ra = ref.get("minEvictableIdleTimeMillis");
+                ra = ref.get(KEY_MIN_EVICTABLE_IDLE_TIME_MILLIS);
                 if (isNotEmpty(ra)) {
                     setMinEvictableIdleTimeMillis(getIntegerStringContent(ra));
                 }
 
-                ra = ref.get("maxPreparedStatements");
+                ra = ref.get(KEY_MAX_PREPARED_STATEMENTS);
                 if (isNotEmpty(ra)) {
                     setMaxPreparedStatements(getIntegerStringContent(ra));
                 }
 
-                ra = ref.get("accessToUnderlyingConnectionAllowed");
+                ra = ref.get(KEY_ACCESS_TO_UNDERLYING_CONNECTION_ALLOWED);
                 if (isNotEmpty(ra)) {
                     
setAccessToUnderlyingConnectionAllowed(getBooleanContentString(ra));
                 }
@@ -380,33 +404,19 @@ public class DriverAdapterCPDS implements 
ConnectionPoolDataSource, Referenceabl
      * @param pooledUserPassword password to be used fur the connection
      */
     @Override
-    public PooledConnection getPooledConnection(final String pooledUserName, 
final String pooledUserPassword)
-        throws SQLException {
+    public PooledConnection getPooledConnection(final String pooledUserName, 
final String pooledUserPassword) throws SQLException {
         getConnectionCalled = true;
+        if (connectionProperties != null) {
+            update(connectionProperties, Constants.KEY_USER, pooledUserName);
+            update(connectionProperties, Constants.KEY_PASSWORD, 
pooledUserPassword);
+        }
+        // Workaround for buggy WebLogic 5.1 class loader - ignore 
ClassCircularityError upon first invocation.
         PooledConnectionImpl pooledConnection = null;
-        // Workaround for buggy WebLogic 5.1 class loader - ignore the 
exception upon first invocation.
         try {
-            if (connectionProperties != null) {
-                update(connectionProperties, Constants.KEY_USER, 
pooledUserName);
-                update(connectionProperties, Constants.KEY_PASSWORD, 
pooledUserPassword);
-                pooledConnection = new PooledConnectionImpl(
-                    DriverManager.getConnection(getUrl(), 
connectionProperties));
-            } else {
-                pooledConnection = new PooledConnectionImpl(
-                    DriverManager.getConnection(getUrl(), pooledUserName, 
pooledUserPassword));
-            }
-            
pooledConnection.setAccessToUnderlyingConnectionAllowed(isAccessToUnderlyingConnectionAllowed());
+            pooledConnection = getPooledConnectionImpl(pooledUserName, 
pooledUserPassword);
         } catch (final ClassCircularityError e) {
-            if (connectionProperties != null) {
-                pooledConnection = new PooledConnectionImpl(
-                    DriverManager.getConnection(getUrl(), 
connectionProperties));
-            } else {
-                pooledConnection = new PooledConnectionImpl(
-                    DriverManager.getConnection(getUrl(), pooledUserName, 
pooledUserPassword));
-            }
-            
pooledConnection.setAccessToUnderlyingConnectionAllowed(isAccessToUnderlyingConnectionAllowed());
+            pooledConnection = getPooledConnectionImpl(pooledUserName, 
pooledUserPassword);
         }
-        KeyedObjectPool<PStmtKey, DelegatingPreparedStatement> stmtPool = null;
         if (isPoolPreparedStatements()) {
             final GenericKeyedObjectPoolConfig<DelegatingPreparedStatement> 
config = new GenericKeyedObjectPoolConfig<>();
             config.setMaxTotalPerKey(Integer.MAX_VALUE);
@@ -428,12 +438,23 @@ public class DriverAdapterCPDS implements 
ConnectionPoolDataSource, Referenceabl
                 config.setNumTestsPerEvictionRun(0);
                 config.setMinEvictableIdleDuration(Duration.ZERO);
             }
-            stmtPool = new GenericKeyedObjectPool<>(pooledConnection, config);
+            final KeyedObjectPool<PStmtKey, DelegatingPreparedStatement> 
stmtPool = new GenericKeyedObjectPool<>(pooledConnection, config);
             pooledConnection.setStatementPool(stmtPool);
         }
         return pooledConnection;
     }
 
+    private PooledConnectionImpl getPooledConnectionImpl(final String 
pooledUserName, final String pooledUserPassword) throws SQLException {
+        PooledConnectionImpl pooledConnection;
+        if (connectionProperties != null) {
+            pooledConnection = new 
PooledConnectionImpl(DriverManager.getConnection(getUrl(), 
connectionProperties));
+        } else {
+            pooledConnection = new 
PooledConnectionImpl(DriverManager.getConnection(getUrl(), pooledUserName, 
pooledUserPassword));
+        }
+        
pooledConnection.setAccessToUnderlyingConnectionAllowed(isAccessToUnderlyingConnectionAllowed());
+        return pooledConnection;
+    }
+
     /**
      * Implements {@link Referenceable}.
      */
@@ -444,25 +465,25 @@ public class DriverAdapterCPDS implements 
ConnectionPoolDataSource, Referenceabl
 
         final Reference ref = new Reference(getClass().getName(), factory, 
null);
 
-        ref.add(new StringRefAddr("description", getDescription()));
-        ref.add(new StringRefAddr("driver", getDriver()));
-        ref.add(new StringRefAddr("loginTimeout", 
String.valueOf(getLoginTimeout())));
+        ref.add(new StringRefAddr(KEY_DESCRIPTION, getDescription()));
+        ref.add(new StringRefAddr(KEY_DRIVER, getDriver()));
+        ref.add(new StringRefAddr(KEY_LOGIN_TIMEOUT, 
String.valueOf(getLoginTimeout())));
         ref.add(new StringRefAddr(Constants.KEY_PASSWORD, getPassword()));
         ref.add(new StringRefAddr(Constants.KEY_USER, getUser()));
-        ref.add(new StringRefAddr("url", getUrl()));
+        ref.add(new StringRefAddr(KEY_URL, getUrl()));
 
-        ref.add(new StringRefAddr("poolPreparedStatements", 
String.valueOf(isPoolPreparedStatements())));
-        ref.add(new StringRefAddr("maxIdle", String.valueOf(getMaxIdle())));
-        ref.add(new StringRefAddr("numTestsPerEvictionRun", 
String.valueOf(getNumTestsPerEvictionRun())));
-        ref.add(new StringRefAddr("maxPreparedStatements", 
String.valueOf(getMaxPreparedStatements())));
+        ref.add(new StringRefAddr(KEY_POOL_PREPARED_STATEMENTS, 
String.valueOf(isPoolPreparedStatements())));
+        ref.add(new StringRefAddr(KEY_MAX_IDLE, String.valueOf(getMaxIdle())));
+        ref.add(new StringRefAddr(KEY_NUM_TESTS_PER_EVICTION_RUN, 
String.valueOf(getNumTestsPerEvictionRun())));
+        ref.add(new StringRefAddr(KEY_MAX_PREPARED_STATEMENTS, 
String.valueOf(getMaxPreparedStatements())));
         //
         // Pair of current and deprecated.
-        ref.add(new StringRefAddr("durationBetweenEvictionRuns", 
String.valueOf(getDurationBetweenEvictionRuns())));
-        ref.add(new StringRefAddr("timeBetweenEvictionRunsMillis", 
String.valueOf(getTimeBetweenEvictionRunsMillis())));
+        ref.add(new StringRefAddr(KEY_DURATION_BETWEEN_EVICTION_RUNS, 
String.valueOf(getDurationBetweenEvictionRuns())));
+        ref.add(new StringRefAddr(KEY_TIME_BETWEEN_EVICTION_RUNS_MILLIS, 
String.valueOf(getTimeBetweenEvictionRunsMillis())));
         //
         // Pair of current and deprecated.
-        ref.add(new StringRefAddr("minEvictableIdleDuration", 
String.valueOf(getMinEvictableIdleDuration())));
-        ref.add(new StringRefAddr("minEvictableIdleTimeMillis", 
String.valueOf(getMinEvictableIdleTimeMillis())));
+        ref.add(new StringRefAddr(KEY_MIN_EVICTABLE_IDLE_DURATION, 
String.valueOf(getMinEvictableIdleDuration())));
+        ref.add(new StringRefAddr(KEY_MIN_EVICTABLE_IDLE_TIME_MILLIS, 
String.valueOf(getMinEvictableIdleTimeMillis())));
 
         return ref;
     }
diff --git 
a/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PooledConnectionImpl.java 
b/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PooledConnectionImpl.java
index b2e9e5c542..15e45c2bb0 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PooledConnectionImpl.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PooledConnectionImpl.java
@@ -20,6 +20,7 @@ import java.sql.CallableStatement;
 import java.sql.Connection;
 import java.sql.PreparedStatement;
 import java.sql.SQLException;
+import java.sql.Statement;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -91,7 +92,7 @@ final class PooledConnectionImpl
     private boolean accessToUnderlyingConnectionAllowed;
 
     /**
-     * Wraps the real connection.
+     * Wraps a real connection.
      *
      * @param connection
      *            the connection to be wrapped.
@@ -328,9 +329,16 @@ final class PooledConnectionImpl
      *            the wrapped {@link PreparedStatement} to be destroyed.
      */
     @Override
-    public void destroyObject(final PStmtKey key, final 
PooledObject<DelegatingPreparedStatement> pooledObject)
-            throws SQLException {
-        pooledObject.getObject().getInnermostDelegate().close();
+    public void destroyObject(final PStmtKey key, final 
PooledObject<DelegatingPreparedStatement> pooledObject) throws SQLException {
+        if (pooledObject != null) {
+            final DelegatingPreparedStatement object = 
pooledObject.getObject();
+            if (object != null) {
+                final Statement innermostDelegate = 
object.getInnermostDelegate();
+                if (innermostDelegate != null) {
+                    innermostDelegate.close();
+                }
+            }
+        }
     }
 
     /**
@@ -433,7 +441,7 @@ final class PooledConnectionImpl
     }
 
     /**
-     * My {@link KeyedPooledObjectFactory} method for passivating {@link 
PreparedStatement}s. Currently invokes
+     * My {@link KeyedPooledObjectFactory} method for passivating {@link 
PreparedStatement}s. Currently, invokes
      * {@link PreparedStatement#clearParameters}.
      *
      * @param key
@@ -453,7 +461,7 @@ final class PooledConnectionImpl
      * Creates or obtains a {@link CallableStatement} from my pool.
      *
      * @param sql
-     *            an SQL statement that may contain one or more '?' parameter 
placeholders. Typically this statement is
+     *            an SQL statement that may contain one or more '?' parameter 
placeholders. Typically, this statement is
      *            specified using JDBC call escape syntax.
      * @return a default {@code CallableStatement} object containing the 
pre-compiled SQL statement.
      * @throws SQLException
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/package-info.java 
b/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/package-info.java
index e5496f3bfd..0f70728f8f 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/package-info.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/package-info.java
@@ -35,15 +35,15 @@
  *       &lt;name&gt;factory&lt;/name&gt;
  *       
&lt;value&gt;org.apache.tomcat.dbcp.dbcp2.cpdsadapter.DriverAdapterCPDS&lt;/value&gt;
  *     &lt;/parameter&gt;
- *         
&lt;parameter&gt;&lt;name&gt;user&lt;/name&gt;&lt;value&gt;root&lt;/value&gt;&lt;/parameter&gt;
- *         
&lt;parameter&gt;&lt;name&gt;password&lt;/name&gt;&lt;value&gt;&lt;/value&gt;&lt;/parameter&gt;
- *         &lt;parameter&gt;
- *             &lt;name&gt;driver&lt;/name&gt;
- *             
&lt;value&gt;org.gjt.mm.mysql.Driver&lt;/value&gt;&lt;/parameter&gt;
- *         &lt;parameter&gt;
- *              &lt;name&gt;url&lt;/name&gt;
- *              
&lt;value&gt;jdbc:mysql://localhost:3306/bookstore&lt;/value&gt;
- *         &lt;/parameter&gt;
+ *     
&lt;parameter&gt;&lt;name&gt;user&lt;/name&gt;&lt;value&gt;root&lt;/value&gt;&lt;/parameter&gt;
+ *     
&lt;parameter&gt;&lt;name&gt;password&lt;/name&gt;&lt;value&gt;&lt;/value&gt;&lt;/parameter&gt;
+ *     &lt;parameter&gt;
+ *       &lt;name&gt;driver&lt;/name&gt;
+ *       &lt;value&gt;org.gjt.mm.mysql.Driver&lt;/value&gt;&lt;/parameter&gt;
+ *     &lt;parameter&gt;
+ *       &lt;name&gt;url&lt;/name&gt;
+ *       &lt;value&gt;jdbc:mysql://localhost:3306/bookstore&lt;/value&gt;
+ *     &lt;/parameter&gt;
  *   &lt;/ResourceParams&gt;
  * </pre>
  *
diff --git 
a/java/org/apache/tomcat/dbcp/dbcp2/datasources/CPDSConnectionFactory.java 
b/java/org/apache/tomcat/dbcp/dbcp2/datasources/CPDSConnectionFactory.java
index 3f28aeb50a..f90b2ad76e 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/datasources/CPDSConnectionFactory.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/datasources/CPDSConnectionFactory.java
@@ -304,26 +304,22 @@ final class CPDSConnectionFactory
     }
 
     @Override
-    public synchronized PooledObject<PooledConnectionAndInfo> makeObject() {
-        try {
-            PooledConnection pc = null;
-            if (userPassKey.getUserName() == null) {
-                pc = cpds.getPooledConnection();
-            } else {
-                pc = cpds.getPooledConnection(userPassKey.getUserName(), 
userPassKey.getPassword());
-            }
-            if (pc == null) {
-                throw new IllegalStateException("Connection pool data source 
returned null from getPooledConnection");
-            }
-            // should we add this object as a listener or the pool.
-            // consider the validateObject method in decision
-            pc.addConnectionEventListener(this);
-            final PooledConnectionAndInfo pci = new 
PooledConnectionAndInfo(pc, userPassKey);
-            pcMap.put(pc, pci);
-            return new DefaultPooledObject<>(pci);
-        } catch (final SQLException e) {
-            throw new RuntimeException(e.getMessage());
+    public synchronized PooledObject<PooledConnectionAndInfo> makeObject() 
throws SQLException {
+        PooledConnection pc = null;
+        if (userPassKey.getUserName() == null) {
+            pc = cpds.getPooledConnection();
+        } else {
+            pc = cpds.getPooledConnection(userPassKey.getUserName(), 
userPassKey.getPassword());
+        }
+        if (pc == null) {
+            throw new IllegalStateException("Connection pool data source 
returned null from getPooledConnection");
         }
+        // should we add this object as a listener or the pool.
+        // consider the validateObject method in decision
+        pc.addConnectionEventListener(this);
+        final PooledConnectionAndInfo pci = new PooledConnectionAndInfo(pc, 
userPassKey);
+        pcMap.put(pc, pci);
+        return new DefaultPooledObject<>(pci);
     }
 
     @Override
diff --git 
a/java/org/apache/tomcat/dbcp/dbcp2/datasources/KeyedCPDSConnectionFactory.java 
b/java/org/apache/tomcat/dbcp/dbcp2/datasources/KeyedCPDSConnectionFactory.java
index 816fd06bce..a5ddd34b68 100644
--- 
a/java/org/apache/tomcat/dbcp/dbcp2/datasources/KeyedCPDSConnectionFactory.java
+++ 
b/java/org/apache/tomcat/dbcp/dbcp2/datasources/KeyedCPDSConnectionFactory.java
@@ -205,7 +205,7 @@ final class KeyedCPDSConnectionFactory implements 
KeyedPooledObjectFactory<UserP
     /**
      * Invalidates the PooledConnection in the pool. The 
KeyedCPDSConnectionFactory closes the connection and pool
      * counters are updated appropriately. Also clears any idle instances 
associated with the user name that was used to
-     * create the PooledConnection. Connections associated with this user are 
not affected and they will not be
+     * create the PooledConnection. Connections associated with this user are 
not affected, and they will not be
      * automatically closed on return to the pool.
      */
     @Override
diff --git 
a/java/org/apache/tomcat/dbcp/dbcp2/datasources/PerUserPoolDataSource.java 
b/java/org/apache/tomcat/dbcp/dbcp2/datasources/PerUserPoolDataSource.java
index ef005ca847..5614e5948e 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/datasources/PerUserPoolDataSource.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/datasources/PerUserPoolDataSource.java
@@ -63,7 +63,7 @@ public class PerUserPoolDataSource extends 
InstanceKeyDataSource {
     private static final Log log = 
LogFactory.getLog(PerUserPoolDataSource.class);
 
     private static <K, V> HashMap<K, V> createMap() {
-        // Should there be a default size different than what this ctor 
provides?
+        // Should there be a default size different from what this ctor 
provides?
         return new HashMap<>();
     }
 
@@ -685,7 +685,7 @@ public class PerUserPoolDataSource extends 
InstanceKeyDataSource {
      * Supports Serialization interface.
      *
      * @param in
-     *            a {@code java.io.ObjectInputStream} value
+     *            a {@link java.io.ObjectInputStream} value
      * @throws IOException
      *             if an error occurs
      * @throws ClassNotFoundException
@@ -722,7 +722,7 @@ public class PerUserPoolDataSource extends 
InstanceKeyDataSource {
         pool.setLifo(getPerUserLifo(userName));
         pool.setMaxIdle(getPerUserMaxIdle(userName));
         pool.setMaxTotal(getPerUserMaxTotal(userName));
-        pool.setMaxWait(Duration.ofMillis(getPerUserMaxWaitMillis(userName)));
+        pool.setMaxWait(getPerUserMaxWaitDuration(userName));
         
pool.setMinEvictableIdleDuration(getPerUserMinEvictableIdleDuration(userName));
         pool.setMinIdle(getPerUserMinIdle(userName));
         
pool.setNumTestsPerEvictionRun(getPerUserNumTestsPerEvictionRun(userName));
diff --git 
a/java/org/apache/tomcat/dbcp/dbcp2/datasources/SharedPoolDataSource.java 
b/java/org/apache/tomcat/dbcp/dbcp2/datasources/SharedPoolDataSource.java
index 7aaaa29cfb..e3907066d5 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/datasources/SharedPoolDataSource.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/datasources/SharedPoolDataSource.java
@@ -145,7 +145,7 @@ public class SharedPoolDataSource extends 
InstanceKeyDataSource {
      * Supports Serialization interface.
      *
      * @param in
-     *            a {@code java.io.ObjectInputStream} value
+     *            a {@link java.io.ObjectInputStream} value
      * @throws IOException
      *             if an error occurs
      * @throws ClassNotFoundException
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/datasources/package-info.java 
b/java/org/apache/tomcat/dbcp/dbcp2/datasources/package-info.java
index 25a762d52a..ab303af3c3 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/datasources/package-info.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/datasources/package-info.java
@@ -20,11 +20,9 @@
  * This package contains two DataSources: {@code PerUserPoolDataSource} and
  * {@code SharedPoolDataSource} which provide a database connection pool.
  * Below are a couple of usage examples.  One shows deployment into a JNDI 
system.
- * The other is a simple example initializing the pool using standard java 
code.
+ * The other is a simple example initializing the pool using standard Java 
code.
  * </p>
- *
  * <h2>JNDI</h2>
- *
  * <p>
  * Most
  * J2EE containers will provide some way of deploying resources into JNDI.  The
@@ -35,8 +33,7 @@
  * <p>In server.xml, the following would be added to the &lt;Context&gt; for 
your
  * webapp:
  * </p>
- *
- * <code>
+ * <pre>
  *  &lt;Resource name="jdbc/bookstore" auth="Container"
  *             
type="org.apache.tomcat.dbcp.dbcp2.datasources.PerUserPoolPoolDataSource"/&gt;
  *   &lt;ResourceParams name="jdbc/bookstore"&gt;
@@ -51,14 +48,12 @@
  *       &lt;name&gt;defaultMaxTotal&lt;/name&gt;&lt;value&gt;30&lt;/value&gt;
  *     &lt;/parameter&gt;
  *   &lt;/ResourceParams&gt;
- * </code>
- *
+ * </pre>
  * <p>
  * In web.xml.  Note that elements must be given in the order of the dtd
  * described in the servlet specification:
  * </p>
- *
- * <code>
+ * <pre>
  * &lt;resource-ref&gt;
  *   &lt;description&gt;
  *     Resource reference to a factory for java.sql.Connection
@@ -75,8 +70,7 @@
  *     Container
  *   &lt;/res-auth&gt;
  * &lt;/resource-ref&gt;
- * </code>
- *
+ * </pre>
  * <p>
  * Apache Tomcat deploys all objects configured similarly to above within the
  * <strong>java:comp/env</strong> namespace.  So the JNDI path given for
@@ -84,14 +78,11 @@
  * {@code ConnectionPoolDataSource} that is deployed as given in the
  * <a href="../cpdsadapter/package-summary.html">cpdsadapter example</a>
  * </p>
- *
  * <p>
  * The {@code DataSource} is now available to the application as shown
  * below:
  * </p>
- *
- * <code>
- *
+ * <pre>
  *     Context ctx = new InitialContext();
  *     DataSource ds = (DataSource)
  *         ctx.lookup("java:comp/env/jdbc/bookstore");
@@ -108,9 +99,7 @@
  *         if (con != null)
  *             con.close();
  *     }
- *
- * </code>
- *
+ * </pre>
  * <p>
  * The reference to the {@code DataSource} could be maintained, for
  * multiple getConnection() requests.  Or the {@code DataSource} can be
@@ -120,24 +109,19 @@
  * between different lookups.  This behavior may be different in other
  * implementations.
  * </p>
- *
  * <h2>Without JNDI</h2>
- *
  * <p>
  * Connection pooling is useful in applications regardless of whether they run
  * in a J2EE environment and a {@code DataSource} can be used within a
  * simpler environment.  The example below shows SharedPoolDataSource using
  * DriverAdapterCPDS as the back end source, though any CPDS is applicable.
  * </p>
+ * <pre>
+ * public class Pool {
  *
- * <code>
- *
- * public class Pool
- * {
  *     private static DataSource ds;
  *
- *     static
- *     {
+ *     static {
  *         DriverAdapterCPDS cpds = new DriverAdapterCPDS();
  *         cpds.setDriver("org.gjt.mm.mysql.Driver");
  *         cpds.setUrl("jdbc:mysql://localhost:3306/bookstore");
@@ -152,32 +136,26 @@
  *         ds = tds;
  *     }
  *
- *     public static getConnection()
- *     {
+ *     public static getConnection() {
  *         return ds.getConnection();
  *     }
  * }
- *
- * </code>
- *
+ * </pre>
  * <p>
  * This class can then be used wherever a connection is needed:
  * </p>
- *
- * <code>
+ * <pre>
  *     Connection con = null;
- *     try
- *     {
+ *     try {
  *         con = Pool.getConnection();
  *         ...
  *         use the connection
  *         ...
- *     }
- *     finally
- *     {
- *         if (con != null)
+ *     } finally {
+ *         if (con != null) {
  *             con.close();
+ *         }
  *     }
- * </code>
+ * </pre>
  */
 package org.apache.tomcat.dbcp.dbcp2.datasources;
diff --git 
a/java/org/apache/tomcat/dbcp/dbcp2/managed/BasicManagedDataSource.java 
b/java/org/apache/tomcat/dbcp/dbcp2/managed/BasicManagedDataSource.java
index a81ed4f513..436a073f06 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/managed/BasicManagedDataSource.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/managed/BasicManagedDataSource.java
@@ -73,7 +73,7 @@ public class BasicManagedDataSource extends BasicDataSource {
             throw new SQLException("Transaction manager must be set before a 
connection can be created");
         }
 
-        // If xa data source is not specified a DriverConnectionFactory is 
created and wrapped with a
+        // If XA data source is not specified a DriverConnectionFactory is 
created and wrapped with a
         // LocalXAConnectionFactory
         if (xaDataSource == null) {
             final ConnectionFactory connectionFactory = 
super.createConnectionFactory();
@@ -88,22 +88,21 @@ public class BasicManagedDataSource extends BasicDataSource 
{
             Class<?> xaDataSourceClass = null;
             try {
                 xaDataSourceClass = Class.forName(xaDataSource);
-            } catch (final Exception t) {
-                final String message = "Cannot load XA data source class '" + 
xaDataSource + "'";
-                throw new SQLException(message, t);
+            } catch (final Exception e) {
+                throw new SQLException("Cannot load XA data source class '" + 
xaDataSource + "'", e);
             }
 
             try {
                 xaDataSourceInstance = (XADataSource) 
xaDataSourceClass.getConstructor().newInstance();
-            } catch (final Exception t) {
-                final String message = "Cannot create XA data source of class 
'" + xaDataSource + "'";
-                throw new SQLException(message, t);
+            } catch (final Exception e) {
+                throw new SQLException("Cannot create XA data source of class 
'" + xaDataSource + "'", e);
             }
         }
 
         // finally, create the XAConnectionFactory using the XA data source
+        @SuppressWarnings("deprecation")
         final XAConnectionFactory xaConnectionFactory = new 
DataSourceXAConnectionFactory(getTransactionManager(),
-                xaDataSourceInstance, getUsername(), 
Utils.toCharArray(getPassword()), getTransactionSynchronizationRegistry());
+                xaDataSourceInstance, getUserName(), 
Utils.toCharArray(getPassword()), getTransactionSynchronizationRegistry());
         transactionRegistry = xaConnectionFactory.getTransactionRegistry();
         return xaConnectionFactory;
     }
diff --git 
a/java/org/apache/tomcat/dbcp/dbcp2/managed/DataSourceXAConnectionFactory.java 
b/java/org/apache/tomcat/dbcp/dbcp2/managed/DataSourceXAConnectionFactory.java
index 267c866722..8ca6d2be26 100644
--- 
a/java/org/apache/tomcat/dbcp/dbcp2/managed/DataSourceXAConnectionFactory.java
+++ 
b/java/org/apache/tomcat/dbcp/dbcp2/managed/DataSourceXAConnectionFactory.java
@@ -115,9 +115,7 @@ public class DataSourceXAConnectionFactory implements 
XAConnectionFactory {
             final String userName, final char[] userPassword, final 
TransactionSynchronizationRegistry transactionSynchronizationRegistry) {
         Objects.requireNonNull(transactionManager, "transactionManager");
         Objects.requireNonNull(xaDataSource, "xaDataSource");
-
         // We do allow the transactionSynchronizationRegistry to be null for 
non-app server environments
-
         this.transactionRegistry = new TransactionRegistry(transactionManager, 
transactionSynchronizationRegistry);
         this.xaDataSource = xaDataSource;
         this.userName = userName;
@@ -166,14 +164,11 @@ public class DataSourceXAConnectionFactory implements 
XAConnectionFactory {
         } else {
             xaConnection = xaDataSource.getXAConnection(userName, 
Utils.toString(userPassword));
         }
-
         // get the real connection and XAResource from the connection
         final Connection connection = xaConnection.getConnection();
         final XAResource xaResource = xaConnection.getXAResource();
-
-        // register the xa resource for the connection
+        // register the XA resource for the connection
         transactionRegistry.registerConnection(connection, xaResource);
-
         // The Connection we're returning is a handle on the XAConnection.
         // When the pool calling us closes the Connection, we need to
         // also close the XAConnection that holds the physical connection.
diff --git 
a/java/org/apache/tomcat/dbcp/dbcp2/managed/LocalXAConnectionFactory.java 
b/java/org/apache/tomcat/dbcp/dbcp2/managed/LocalXAConnectionFactory.java
index 8906330837..d32b701567 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/managed/LocalXAConnectionFactory.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/managed/LocalXAConnectionFactory.java
@@ -60,7 +60,7 @@ public class LocalXAConnectionFactory implements 
XAConnectionFactory {
         private boolean originalAutoCommit; // @GuardedBy("this")
 
         /**
-         * Construct a new instance for a given connection.
+         * Constructs a new instance for a given connection.
          *
          * @param localTransaction A connection.
          */
@@ -266,7 +266,7 @@ public class LocalXAConnectionFactory implements 
XAConnectionFactory {
         }
 
         /**
-         * Signals that a the connection has been enrolled in a transaction. 
This method saves off the current auto
+         * Signals that a connection has been enrolled in a transaction. This 
method saves off the current auto
          * commit flag, and then disables auto commit. The original auto 
commit setting is restored when the transaction
          * completes.
          *
@@ -288,7 +288,7 @@ public class LocalXAConnectionFactory implements 
XAConnectionFactory {
                     throw new XAException("Already enlisted in another 
transaction with xid " + xid);
                 }
 
-                // save off the current auto commit flag so it can be restored 
after the transaction completes
+                // save off the current auto commit flag, so it can be 
restored after the transaction completes
                 try {
                     originalAutoCommit = connection.getAutoCommit();
                 } catch (final SQLException ignored) {
@@ -362,7 +362,7 @@ public class LocalXAConnectionFactory implements 
XAConnectionFactory {
         // create a XAResource to manage the connection during XA transactions
         final XAResource xaResource = new LocalXAResource(connection);
 
-        // register the xa resource for the connection
+        // register the XA resource for the connection
         transactionRegistry.registerConnection(connection, xaResource);
 
         return connection;
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/managed/ManagedConnection.java 
b/java/org/apache/tomcat/dbcp/dbcp2/managed/ManagedConnection.java
index 81d370e5c9..579231d362 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/managed/ManagedConnection.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/managed/ManagedConnection.java
@@ -30,7 +30,7 @@ import org.apache.tomcat.dbcp.pool2.ObjectPool;
  * transaction or JTA Transaction) is in progress. When a global transaction 
is active a single physical connection to
  * the database is used by all ManagedConnections accessed in the scope of the 
transaction. Connection sharing means
  * that all data access during a transaction has a consistent view of the 
database. When the global transaction is
- * committed or rolled back the enlisted connections are committed or rolled 
back. Typically upon transaction
+ * committed or rolled back the enlisted connections are committed or rolled 
back. Typically, upon transaction
  * completion, a connection returns to the auto commit setting in effect 
before being enlisted in the transaction, but
  * some vendors do not properly implement this.
  * <p>
@@ -236,7 +236,7 @@ public class ManagedConnection<C extends Connection> 
extends DelegatingConnectio
     }
 
     private void updateTransactionStatus() throws SQLException {
-        // if there is a is an active transaction context, assure the 
transaction context hasn't changed
+        // if there is an active transaction context, assure the transaction 
context hasn't changed
         if (transactionContext != null && 
!transactionContext.isTransactionComplete()) {
             if (transactionContext.isActive()) {
                 if (transactionContext != 
transactionRegistry.getActiveTransactionContext()) {
@@ -253,7 +253,7 @@ public class ManagedConnection<C extends Connection> 
extends DelegatingConnectio
         // the existing transaction context ended (or we didn't have one), get 
the active transaction context
         transactionContext = transactionRegistry.getActiveTransactionContext();
 
-        // if there is an active transaction context and it already has a 
shared connection, use it
+        // if there is an active transaction context, and it already has a 
shared connection, use it
         if (transactionContext != null && 
transactionContext.getSharedConnection() != null) {
             // A connection for the connection factory has already been 
enrolled
             // in the transaction, replace our delegate with the enrolled 
connection
@@ -284,7 +284,7 @@ public class ManagedConnection<C extends Connection> 
extends DelegatingConnectio
             final C shared = (C) transactionContext.getSharedConnection();
             setDelegate(shared);
 
-            // remember that we are using a shared connection so it can be 
cleared after the
+            // remember that we are using a shared connection, so it can be 
cleared after the
             // transaction completes
             isSharedConnection = true;
         } else {
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/managed/TransactionRegistry.java 
b/java/org/apache/tomcat/dbcp/dbcp2/managed/TransactionRegistry.java
index 1d0d163d31..793257ff72 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/managed/TransactionRegistry.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/managed/TransactionRegistry.java
@@ -85,7 +85,7 @@ public class TransactionRegistry {
                 return null;
             }
 
-            // This is the transaction on the thread so no need to check it's 
status - we should try to use it and
+            // This is the transaction on the thread so no need to check its 
status - we should try to use it and
             // fail later based on the subsequent status
         } catch (final SystemException e) {
             throw new SQLException("Unable to determine current transaction ", 
e);
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/managed/XAConnectionFactory.java 
b/java/org/apache/tomcat/dbcp/dbcp2/managed/XAConnectionFactory.java
index a5c5420feb..b9913fbb42 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/managed/XAConnectionFactory.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/managed/XAConnectionFactory.java
@@ -25,7 +25,7 @@ import org.apache.tomcat.dbcp.dbcp2.ConnectionFactory;
  * XAConnectionFactory is an extension of ConnectionFactory used to create 
connections in a transaction managed
  * environment. The XAConnectionFactory operates like a normal 
ConnectionFactory except a TransactionRegistry is
  * provided from which the XAResource for a connection can be obtained. This 
allows the existing DBCP pool code to work
- * with XAConnections and gives a the ManagedConnection a way to enlist a 
connection in the transaction.
+ * with XAConnections and gives the ManagedConnection a way to enlist a 
connection in the transaction.
  *
  * @since 2.0
  */
@@ -45,7 +45,7 @@ public interface XAConnectionFactory extends 
ConnectionFactory {
     Connection createConnection() throws SQLException;
 
     /**
-     * Gets the TransactionRegistry for this connection factory which contains 
a the XAResource for every connection
+     * Gets the TransactionRegistry for this connection factory which contains 
the XAResource for every connection
      * created by this factory.
      *
      * @return the transaction registry for this connection factory
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/package-info.java 
b/java/org/apache/tomcat/dbcp/dbcp2/package-info.java
index d63195f000..58a517589d 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/package-info.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/package-info.java
@@ -19,7 +19,6 @@
  * <p>
  * Database Connection Pool API.
  * </p>
- *
  * <b>Overview in Dialog Form</b>
  * <p>
  * Q: How do I use the DBCP package?
@@ -94,13 +93,12 @@
  * <p>
  * In code, that might look like this:
  * </p>
- *
  * <pre>
  * GenericObjectPool connectionPool = new GenericObjectPool(null);
  * ConnectionFactory connectionFactory = new 
DriverManagerConnectionFactory("jdbc:some:connect:string", "userName",
  *         "password");
- * PoolableConnectionFactory poolableConnectionFactory = new 
PoolableConnectionFactory(connectionFactory,
- *         connectionPool, null, null, false, true);
+ * ObjectName oName = new ObjectName("MyTests:DataSource=test"); // or null to 
not use JMX
+ * PoolableConnectionFactory poolableConnectionFactory = new 
PoolableConnectionFactory(connectionFactory, oName);
  * PoolingDataSource dataSource = new PoolingDataSource(connectionPool);
  * </pre>
  * <p>
@@ -108,13 +106,12 @@
  * {@link javax.sql.DataSource} on the last line, we create a {@link 
org.apache.tomcat.dbcp.dbcp2.PoolingDriver}, and
  * register the {@code connectionPool} with it. E.g.,:
  * </p>
- *
  * <pre>
  * GenericObjectPool connectionPool = new GenericObjectPool(null);
  * ConnectionFactory connectionFactory = new 
DriverManagerConnectionFactory("jdbc:some:connect:string", "userName",
  *         "password");
- * PoolableConnectionFactory poolableConnectionFactory = new 
PoolableConnectionFactory(connectionFactory,
- *         connectionPool, null, null, false, true);
+ * ObjectName oName = new ObjectName("MyTests:DataSource=test"); // or null to 
not use JMX
+ * PoolableConnectionFactory poolableConnectionFactory = new 
PoolableConnectionFactory(connectionFactory, oName);
  * PoolingDriver driver = new PoolingDriver();
  * driver.registerPool("example", connectionPool);
  * </pre>
@@ -123,7 +120,6 @@
  * when it is created, now you can just go to the {@link 
java.sql.DriverManager} to create your
  * {@link java.sql.Connection}s, like you normally would:
  * </p>
- *
  * <pre>
  * Connection conn = 
DriverManager.getConnection("jdbc:apache:commons:dbcp:example");
  * </pre>
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index f86a63668c..18667ad683 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -211,6 +211,9 @@
       <update>
         Update the internal fork of Apache Commons BCEL to 6.9.0. (markt)
       </update>
+      <update>
+        Update the internal fork of Apache Commons DBCP to 2.12.0. (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