This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch 9.0.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 8f2e9bd56c4e0942e17c949e059167fb91831419 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 696735fc46..033f6df371 100644 --- a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingStatement.java +++ b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingStatement.java @@ -447,19 +447,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 @@ * <name>factory</name> * <value>org.apache.tomcat.dbcp.dbcp2.cpdsadapter.DriverAdapterCPDS</value> * </parameter> - * <parameter><name>user</name><value>root</value></parameter> - * <parameter><name>password</name><value></value></parameter> - * <parameter> - * <name>driver</name> - * <value>org.gjt.mm.mysql.Driver</value></parameter> - * <parameter> - * <name>url</name> - * <value>jdbc:mysql://localhost:3306/bookstore</value> - * </parameter> + * <parameter><name>user</name><value>root</value></parameter> + * <parameter><name>password</name><value></value></parameter> + * <parameter> + * <name>driver</name> + * <value>org.gjt.mm.mysql.Driver</value></parameter> + * <parameter> + * <name>url</name> + * <value>jdbc:mysql://localhost:3306/bookstore</value> + * </parameter> * </ResourceParams> * </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 <Context> for your * webapp: * </p> - * - * <code> + * <pre> * <Resource name="jdbc/bookstore" auth="Container" * type="org.apache.tomcat.dbcp.dbcp2.datasources.PerUserPoolPoolDataSource"/> * <ResourceParams name="jdbc/bookstore"> @@ -51,14 +48,12 @@ * <name>defaultMaxTotal</name><value>30</value> * </parameter> * </ResourceParams> - * </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> * <resource-ref> * <description> * Resource reference to a factory for java.sql.Connection @@ -75,8 +70,7 @@ * Container * </res-auth> * </resource-ref> - * </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 ad2227ad1a..b43272f94a 100644 --- a/java/org/apache/tomcat/dbcp/dbcp2/managed/BasicManagedDataSource.java +++ b/java/org/apache/tomcat/dbcp/dbcp2/managed/BasicManagedDataSource.java @@ -72,7 +72,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(); @@ -87,22 +87,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 0f3dc4c656..e3c22f49b9 100644 --- a/java/org/apache/tomcat/dbcp/dbcp2/managed/DataSourceXAConnectionFactory.java +++ b/java/org/apache/tomcat/dbcp/dbcp2/managed/DataSourceXAConnectionFactory.java @@ -114,9 +114,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; @@ -165,14 +163,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 a24f37bf0c..647ba733a7 100644 --- a/java/org/apache/tomcat/dbcp/dbcp2/managed/LocalXAConnectionFactory.java +++ b/java/org/apache/tomcat/dbcp/dbcp2/managed/LocalXAConnectionFactory.java @@ -59,7 +59,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. */ @@ -265,7 +265,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. * @@ -287,7 +287,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) { @@ -361,7 +361,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 21ac2dc3e7..3686cf5f5d 100644 --- a/java/org/apache/tomcat/dbcp/dbcp2/managed/TransactionRegistry.java +++ b/java/org/apache/tomcat/dbcp/dbcp2/managed/TransactionRegistry.java @@ -84,7 +84,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 4be89f34d1..5217123962 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -220,6 +220,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