You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2021/09/02 15:11:19 UTC
[tomcat] 02/02: Update internal fork of Commons DBCP to 2.9.0
(2021-08-03)
This is an automated email from the ASF dual-hosted git repository.
markt pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit d2e8a3b4c4046ef84fdc18475a652e3027854232
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Thu Sep 2 16:00:10 2021 +0100
Update internal fork of Commons DBCP to 2.9.0 (2021-08-03)
---
MERGE.txt | 2 +-
.../apache/tomcat/dbcp/dbcp2/AbandonedTrace.java | 33 +-
.../apache/tomcat/dbcp/dbcp2/BasicDataSource.java | 643 +++++++----
.../tomcat/dbcp/dbcp2/BasicDataSourceFactory.java | 521 +++------
.../tomcat/dbcp/dbcp2/BasicDataSourceMXBean.java | 330 +-----
.../dbcp/dbcp2/ConnectionFactoryFactory.java | 2 +-
java/org/apache/tomcat/dbcp/dbcp2/Constants.java | 16 +-
.../dbcp/dbcp2/DataSourceConnectionFactory.java | 2 +-
...DataSourceMXBean.java => DataSourceMXBean.java} | 284 +++--
.../tomcat/dbcp/dbcp2/DelegatingConnection.java | 866 +++++++-------
.../dbcp/dbcp2/DelegatingDatabaseMetaData.java | 19 +-
.../tomcat/dbcp/dbcp2/DelegatingResultSet.java | 24 +-
.../tomcat/dbcp/dbcp2/DelegatingStatement.java | 19 +-
.../org/apache/tomcat/dbcp/dbcp2/Jdbc41Bridge.java | 136 +--
java/org/apache/tomcat/dbcp/dbcp2/PStmtKey.java | 4 +-
.../dbcp/dbcp2/PoolableCallableStatement.java | 30 +-
.../tomcat/dbcp/dbcp2/PoolableConnection.java | 283 +++--
.../dbcp/dbcp2/PoolableConnectionFactory.java | 171 ++-
.../dbcp/dbcp2/PoolableConnectionMXBean.java | 44 +-
.../dbcp/dbcp2/PoolablePreparedStatement.java | 20 +-
.../tomcat/dbcp/dbcp2/PoolingConnection.java | 68 +-
.../tomcat/dbcp/dbcp2/PoolingDataSource.java | 183 +--
.../apache/tomcat/dbcp/dbcp2/PoolingDriver.java | 225 ++--
java/org/apache/tomcat/dbcp/dbcp2/Utils.java | 52 +-
.../dbcp/dbcp2/cpdsadapter/ConnectionImpl.java | 106 +-
.../dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java | 193 +++-
.../dbcp2/cpdsadapter/PooledConnectionImpl.java | 110 +-
.../dbcp2/datasources/CPDSConnectionFactory.java | 426 ++++---
.../tomcat/dbcp/dbcp2/datasources/CharArray.java | 88 ++
.../dbcp2/datasources/InstanceKeyDataSource.java | 1220 ++++++++++++--------
.../datasources/InstanceKeyDataSourceFactory.java | 226 ++--
.../datasources/KeyedCPDSConnectionFactory.java | 335 +++---
.../dbcp2/datasources/PerUserPoolDataSource.java | 343 ++++--
.../datasources/PerUserPoolDataSourceFactory.java | 65 +-
.../tomcat/dbcp/dbcp2/datasources/PoolKey.java | 2 +-
.../dbcp2/datasources/PooledConnectionAndInfo.java | 55 +-
.../dbcp2/datasources/PooledConnectionManager.java | 30 +-
.../dbcp2/datasources/SharedPoolDataSource.java | 104 +-
.../datasources/SharedPoolDataSourceFactory.java | 10 +-
.../tomcat/dbcp/dbcp2/datasources/UserPassKey.java | 53 +-
.../dbcp/dbcp2/managed/BasicManagedDataSource.java | 227 ++--
.../managed/DataSourceXAConnectionFactory.java | 45 +-
.../dbcp2/managed/LocalXAConnectionFactory.java | 39 +-
.../dbcp/dbcp2/managed/ManagedConnection.java | 36 +-
.../dbcp/dbcp2/managed/ManagedDataSource.java | 29 +-
.../managed/PoolableManagedConnectionFactory.java | 3 +-
.../dbcp/dbcp2/managed/TransactionContext.java | 181 ++-
.../dbcp2/managed/TransactionContextListener.java | 29 +-
.../dbcp/dbcp2/managed/TransactionRegistry.java | 134 ++-
.../dbcp/dbcp2/managed/XAConnectionFactory.java | 45 +-
webapps/docs/changelog.xml | 4 +
51 files changed, 4376 insertions(+), 3739 deletions(-)
diff --git a/MERGE.txt b/MERGE.txt
index 4682268..e1403d4 100644
--- a/MERGE.txt
+++ b/MERGE.txt
@@ -69,4 +69,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:
-e24196a95bbbc531eb3c5f1b19e1dc42fd78a783 (2021-01-15)
+rel/commons-dbcp-2.9.0 (2021-08-03)
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/AbandonedTrace.java b/java/org/apache/tomcat/dbcp/dbcp2/AbandonedTrace.java
index 671e3e6..c107580 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/AbandonedTrace.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/AbandonedTrace.java
@@ -17,6 +17,7 @@
package org.apache.tomcat.dbcp.dbcp2;
import java.lang.ref.WeakReference;
+import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
@@ -25,7 +26,7 @@ import java.util.List;
import org.apache.tomcat.dbcp.pool2.TrackedUse;
/**
- * Tracks db connection usage for recovering and reporting abandoned db connections.
+ * Tracks connection usage for recovering and reporting abandoned connections.
* <p>
* The JDBC Connection, Statement, and ResultSet classes extend this class.
* </p>
@@ -38,7 +39,7 @@ public class AbandonedTrace implements TrackedUse {
private final List<WeakReference<AbandonedTrace>> traceList = new ArrayList<>();
/** Last time this connection was used. */
- private volatile long lastUsedMillis = 0;
+ private volatile Instant lastUsedInstant = Instant.EPOCH;
/**
* Creates a new AbandonedTrace without config and without doing abandoned tracing.
@@ -85,8 +86,14 @@ public class AbandonedTrace implements TrackedUse {
* @return long time in milliseconds.
*/
@Override
+ @Deprecated
public long getLastUsed() {
- return lastUsedMillis;
+ return lastUsedInstant.toEpochMilli();
+ }
+
+ @Override
+ public Instant getLastUsedInstant() {
+ return lastUsedInstant;
}
/**
@@ -153,7 +160,8 @@ public class AbandonedTrace implements TrackedUse {
if (trace != null && trace.equals(traceInList)) {
iter.remove();
break;
- } else if (traceInList == null) {
+ }
+ if (traceInList == null) {
// Clean-up since we are here anyway
iter.remove();
}
@@ -165,7 +173,18 @@ public class AbandonedTrace implements TrackedUse {
* Sets the time this object was last used to the current time in milliseconds.
*/
protected void setLastUsed() {
- lastUsedMillis = System.currentTimeMillis();
+ lastUsedInstant = Instant.now();
+ }
+
+ /**
+ * Sets the instant this object was last used.
+ *
+ * @param lastUsedInstant
+ * instant.
+ * @since 2.10.0
+ */
+ protected void setLastUsed(final Instant lastUsedInstant) {
+ this.lastUsedInstant = lastUsedInstant;
}
/**
@@ -173,8 +192,10 @@ public class AbandonedTrace implements TrackedUse {
*
* @param lastUsedMillis
* time in milliseconds.
+ * @deprecated Use {@link #setLastUsed(Instant)}
*/
+ @Deprecated
protected void setLastUsed(final long lastUsedMillis) {
- this.lastUsedMillis = lastUsedMillis;
+ this.lastUsedInstant = Instant.ofEpochMilli(lastUsedMillis);
}
}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSource.java b/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSource.java
index 08762f0..f260a53 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSource.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSource.java
@@ -27,6 +27,7 @@ import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
+import java.time.Duration;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -40,7 +41,9 @@ import java.util.logging.Logger;
import javax.management.MBeanRegistration;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
+import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
+import javax.management.StandardMBean;
import javax.sql.DataSource;
import org.apache.juli.logging.Log;
@@ -53,10 +56,11 @@ import org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool;
import org.apache.tomcat.dbcp.pool2.impl.GenericObjectPoolConfig;
/**
+ * Basic implementation of <code>javax.sql.DataSource</code> that is configured via JavaBeans properties.
+ *
* <p>
- * Basic implementation of <code>javax.sql.DataSource</code> that is configured via JavaBeans properties. This is not
- * the only way to combine the <em>commons-dbcp2</em> and <em>commons-pool2</em> packages, but provides a "one stop
- * shopping" solution for basic requirements.
+ * This is not the only way to combine the <em>commons-dbcp2</em> and <em>commons-pool2</em> packages, but provides a
+ * one-stop solution for basic requirements.
* </p>
*
* @since 2.0
@@ -73,7 +77,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
// A number of classes are loaded when getConnection() is called
// but the following classes are not loaded and therefore require
// explicit loading.
- if (Utils.IS_SECURITY_ENABLED) {
+ if (Utils.isSecurityEnabled()) {
final ClassLoader loader = BasicDataSource.class.getClassLoader();
final String dbcpPackageName = BasicDataSource.class.getPackage().getName();
loader.loadClass(dbcpPackageName + ".DelegatingCallableStatement");
@@ -94,8 +98,13 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
}
- protected static void validateConnectionFactory(final PoolableConnectionFactory connectionFactory)
- throws Exception {
+ /**
+ * Validates the given factory.
+ *
+ * @param connectionFactory the factory
+ * @throws Exception Thrown by one of the factory methods while managing a temporary pooled object.
+ */
+ protected static void validateConnectionFactory(final PoolableConnectionFactory connectionFactory) throws Exception {
PoolableConnection conn = null;
PooledObject<PoolableConnection> p = null;
try {
@@ -126,7 +135,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
*/
private volatile int defaultTransactionIsolation = PoolableConnectionFactory.UNKNOWN_TRANSACTION_ISOLATION;
- private Integer defaultQueryTimeoutSeconds;
+ private Duration defaultQueryTimeoutDuration;
/**
* The default "catalog" of connections created by this pool.
@@ -187,28 +196,28 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
* The minimum number of active connections that can remain idle in the pool, without extra ones being created when
* the evictor runs, or 0 to create none. The pool attempts to ensure that minIdle connections are available when
* the idle object evictor runs. The value of this property has no effect unless
- * {@link #timeBetweenEvictionRunsMillis} has a positive value.
+ * {@link #durationBetweenEvictionRuns} has a positive value.
*/
private int minIdle = GenericObjectPoolConfig.DEFAULT_MIN_IDLE;
/**
* The initial number of connections that are created when the pool is started.
*/
- private int initialSize = 0;
+ private int initialSize;
/**
- * The maximum number of milliseconds that the pool will wait (when there are no available connections) for a
+ * The maximum Duration that the pool will wait (when there are no available connections) for a
* connection to be returned before throwing an exception, or <= 0 to wait indefinitely.
*/
- private long maxWaitMillis = BaseObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS;
+ private Duration maxWaitDuration = BaseObjectPoolConfig.DEFAULT_MAX_WAIT;
/**
* Prepared statement pooling for this pool. When this property is set to <code>true</code> both PreparedStatements
* and CallableStatements are pooled.
*/
- private boolean poolPreparedStatements = false;
+ private boolean poolPreparedStatements;
- private boolean clearStatementPoolOnReturn = false;
+ private boolean clearStatementPoolOnReturn;
/**
* <p>
@@ -229,7 +238,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
* The indication of whether objects will be validated as soon as they have been created by the pool. If the object
* fails to validate, the borrow operation that triggered the creation will fail.
*/
- private boolean testOnCreate = false;
+ private boolean testOnCreate;
/**
* The indication of whether objects will be validated before being borrowed from the pool. If the object fails to
@@ -240,13 +249,13 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
/**
* The indication of whether objects will be validated before being returned to the pool.
*/
- private boolean testOnReturn = false;
+ private boolean testOnReturn;
/**
* The number of milliseconds to sleep between runs of the idle object evictor thread. When non-positive, no idle
* object evictor thread will be run.
*/
- private long timeBetweenEvictionRunsMillis = BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
+ private Duration durationBetweenEvictionRuns = BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS;
/**
* The number of objects to examine during each run of the idle object evictor thread (if any).
@@ -257,15 +266,15 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
* The minimum amount of time an object may sit idle in the pool before it is eligible for eviction by the idle
* object evictor (if any).
*/
- private long minEvictableIdleTimeMillis = BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
+ private Duration minEvictableIdleDuration = BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_DURATION;
/**
* The minimum amount of time a connection may sit idle in the pool before it is eligible for eviction by the idle
* object evictor, with the extra condition that at least "minIdle" connections remain in the pool. Note that
* {@code minEvictableIdleTimeMillis} takes precedence over this parameter. See
- * {@link #getSoftMinEvictableIdleTimeMillis()}.
+ * {@link #getSoftMinEvictableIdleDuration()}.
*/
- private long softMinEvictableIdleTimeMillis = BaseObjectPoolConfig.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
+ private Duration softMinEvictableIdleDuration = BaseObjectPoolConfig.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_DURATION;
private String evictionPolicyClassName = BaseObjectPoolConfig.DEFAULT_EVICTION_POLICY_CLASS_NAME;
@@ -273,7 +282,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
* The indication of whether objects will be validated by the idle object evictor (if any). If an object fails to
* validate, it will be dropped from the pool.
*/
- private boolean testWhileIdle = false;
+ private boolean testWhileIdle;
/**
* The connection password to be passed to our JDBC driver to establish a connection.
@@ -300,7 +309,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
/**
* Timeout in seconds before connection validation queries fail.
*/
- private volatile int validationQueryTimeoutSeconds = -1;
+ private volatile Duration validationQueryTimeoutDuration = Duration.ofSeconds(-1);
/**
* The fully qualified Java class name of a {@link ConnectionFactory} implementation.
@@ -319,9 +328,9 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
/**
* Controls access to the underlying connection.
*/
- private boolean accessToUnderlyingConnectionAllowed = false;
+ private boolean accessToUnderlyingConnectionAllowed;
- private long maxConnLifetimeMillis = -1;
+ private Duration maxConnDuration = Duration.ofMillis(-1);
private boolean logExpiredConnections = true;
@@ -381,10 +390,8 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * <p>
* Closes and releases all idle connections that are currently stored in the connection pool associated with this
* data source.
- * </p>
* <p>
* Connections that are checked out to clients when this method is invoked are not affected. When client
* applications subsequently invoke {@link Connection#close()} to return these connections to the pool, the
@@ -428,25 +435,19 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
private void closeConnectionPool() {
final GenericObjectPool<?> oldPool = connectionPool;
connectionPool = null;
- try {
- if (oldPool != null) {
- oldPool.close();
- }
- } catch (final Exception e) {
- /* Ignore */
- }
+ Utils.closeQuietly(oldPool);
}
/**
* Creates a JDBC connection factory for this data source. The JDBC driver is loaded using the following algorithm:
* <ol>
* <li>If a Driver instance has been specified via {@link #setDriver(Driver)} use it</li>
- * <li>If no Driver instance was specified and {@link #driverClassName} is specified that class is loaded using the
- * {@link ClassLoader} of this class or, if {@link #driverClassLoader} is set, {@link #driverClassName} is loaded
+ * <li>If no Driver instance was specified and {code driverClassName} is specified that class is loaded using the
+ * {@link ClassLoader} of this class or, if {code driverClassLoader} is set, {code driverClassName} is loaded
* with the specified {@link ClassLoader}.</li>
- * <li>If {@link #driverClassName} is specified and the previous attempt fails, the class is loaded using the
+ * <li>If {code driverClassName} is specified and the previous attempt fails, the class is loaded using the
* context class loader of the current thread.</li>
- * <li>If a driver still isn't loaded one is loaded via the {@link DriverManager} using the specified {@link #url}.
+ * <li>If a driver still isn't loaded one is loaded via the {@link DriverManager} using the specified {code url}.
* </ol>
* <p>
* This method exists so subclasses can replace the implementation class.
@@ -483,13 +484,13 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
gop.setMaxTotal(maxTotal);
gop.setMaxIdle(maxIdle);
gop.setMinIdle(minIdle);
- gop.setMaxWaitMillis(maxWaitMillis);
+ gop.setMaxWait(maxWaitDuration);
gop.setTestOnCreate(testOnCreate);
gop.setTestOnBorrow(testOnBorrow);
gop.setTestOnReturn(testOnReturn);
gop.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
- gop.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
- gop.setSoftMinEvictableIdleTimeMillis(softMinEvictableIdleTimeMillis);
+ gop.setMinEvictableIdle(minEvictableIdleDuration);
+ gop.setSoftMinEvictableIdle(softMinEvictableIdleDuration);
gop.setTestWhileIdle(testWhileIdle);
gop.setLifo(lifo);
gop.setSwallowedExceptionListener(new SwallowedExceptionLogger(log, logExpiredConnections));
@@ -499,9 +500,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * <p>
* Creates (if necessary) and return the internal data source we are using to manage our connections.
- * </p>
*
* @return The current internal DataSource or a newly created instance if it has not yet been created.
* @throws SQLException if the object pool cannot be created.
@@ -628,10 +627,9 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
throws SQLException {
PoolableConnectionFactory connectionFactory = null;
try {
- connectionFactory = new PoolableConnectionFactory(driverConnectionFactory,
- ObjectNameWrapper.unwrap(registeredJmxObjectName));
+ connectionFactory = new PoolableConnectionFactory(driverConnectionFactory, ObjectNameWrapper.unwrap(registeredJmxObjectName));
connectionFactory.setValidationQuery(validationQuery);
- connectionFactory.setValidationQueryTimeout(validationQueryTimeoutSeconds);
+ connectionFactory.setValidationQueryTimeout(validationQueryTimeoutDuration);
connectionFactory.setConnectionInitSql(connectionInitSqls);
connectionFactory.setDefaultReadOnly(defaultReadOnly);
connectionFactory.setDefaultAutoCommit(defaultAutoCommit);
@@ -642,10 +640,10 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
connectionFactory.setPoolStatements(poolPreparedStatements);
connectionFactory.setClearStatementPoolOnReturn(clearStatementPoolOnReturn);
connectionFactory.setMaxOpenPreparedStatements(maxOpenPreparedStatements);
- connectionFactory.setMaxConnLifetimeMillis(maxConnLifetimeMillis);
+ connectionFactory.setMaxConn(maxConnDuration);
connectionFactory.setRollbackOnReturn(getRollbackOnReturn());
connectionFactory.setAutoCommitOnReturn(getAutoCommitOnReturn());
- connectionFactory.setDefaultQueryTimeout(getDefaultQueryTimeout());
+ connectionFactory.setDefaultQueryTimeout(getDefaultQueryTimeoutDuration());
connectionFactory.setFastFailValidation(fastFailValidation);
connectionFactory.setDisconnectionSqlCodes(disconnectionSqlCodes);
validateConnectionFactory(connectionFactory);
@@ -690,7 +688,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * Returns the value of the flag that controls whether or not connections being returned to the pool will be checked
+ * 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
* setting is {@code false} when the connection is returned. It is <code>true</code> by default.
*
@@ -701,7 +699,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * Returns the state caching flag.
+ * Gets the state caching flag.
*
* @return the state caching flag
*/
@@ -718,7 +716,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
*/
@Override
public Connection getConnection() throws SQLException {
- if (Utils.IS_SECURITY_ENABLED) {
+ if (Utils.isSecurityEnabled()) {
final PrivilegedExceptionAction<Connection> action = () -> createDataSource().getConnection();
try {
return AccessController.doPrivileged(action);
@@ -751,7 +749,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * Returns the ConnectionFactoryClassName that has been configured for use by this pool.
+ * Gets the ConnectionFactoryClassName that has been configured for use by this pool.
* <p>
* Note: This getter only returns the last value set by a call to {@link #setConnectionFactoryClassName(String)}.
* </p>
@@ -764,7 +762,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * Returns the list of SQL statements executed when a physical connection is first created. Returns an empty list if
+ * Gets the list of SQL statements executed when a physical connection is first created. Returns an empty list if
* there are no initialization statements configured.
*
* @return initialization SQL statements
@@ -782,6 +780,11 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
return getConnectionInitSqls().toArray(Utils.EMPTY_STRING_ARRAY);
}
+ /**
+ * Gets the underlying connection pool.
+ *
+ * @return the underlying connection pool.
+ */
protected GenericObjectPool<PoolableConnection> getConnectionPool() {
return connectionPool;
}
@@ -791,7 +794,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * Returns the default auto-commit property.
+ * Gets the default auto-commit property.
*
* @return true if default auto-commit is enabled
*/
@@ -801,7 +804,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * Returns the default catalog.
+ * Gets the default catalog.
*
* @return the default catalog
*/
@@ -815,13 +818,26 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
* connection. <code>null</code> means that the driver default will be used.
*
* @return The default query timeout in seconds.
+ * @deprecated Use {@link #getDefaultQueryTimeoutDuration()}.
*/
+ @Deprecated
public Integer getDefaultQueryTimeout() {
- return defaultQueryTimeoutSeconds;
+ return defaultQueryTimeoutDuration == null ? null : Integer.valueOf((int) defaultQueryTimeoutDuration.getSeconds());
}
/**
- * Returns the default readOnly property.
+ * Gets the default query timeout that will be used for {@link java.sql.Statement Statement}s created from this
+ * connection. <code>null</code> means that the driver default will be used.
+ *
+ * @return The default query timeout Duration.
+ * @since 2.10.0
+ */
+ public Duration getDefaultQueryTimeoutDuration() {
+ return defaultQueryTimeoutDuration;
+ }
+
+ /**
+ * Gets the default readOnly property.
*
* @return true if connections are readOnly by default
*/
@@ -831,7 +847,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * Returns the default schema.
+ * Gets the default schema.
*
* @return the default schema.
* @since 2.5.0
@@ -842,7 +858,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * Returns the default transaction isolation state of returned connections.
+ * Gets the default transaction isolation state of returned connections.
*
* @return the default value for transaction isolation state
* @see Connection#getTransactionIsolation
@@ -853,7 +869,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * Returns the set of SQL_STATE codes considered to signal fatal conditions.
+ * Gets the set of SQL_STATE codes considered to signal fatal conditions.
*
* @return fatal disconnection state codes
* @see #setDisconnectionSqlCodes(Collection)
@@ -875,7 +891,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * Returns the JDBC Driver that has been configured for use by this pool.
+ * Gets the JDBC Driver that has been configured for use by this pool.
* <p>
* Note: This getter only returns the last value set by a call to {@link #setDriver(Driver)}. It does not return any
* driver instance that may have been created from the value set via {@link #setDriverClassName(String)}.
@@ -888,7 +904,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * Returns the class loader specified for loading the JDBC driver. Returns <code>null</code> if no class loader has
+ * Gets the class loader specified for loading the JDBC driver. Returns <code>null</code> if no class loader has
* been explicitly specified.
* <p>
* Note: This getter only returns the last value set by a call to {@link #setDriverClassLoader(ClassLoader)}. It
@@ -902,7 +918,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * Returns the JDBC driver class name.
+ * Gets the JDBC driver class name.
* <p>
* Note: This getter only returns the last value set by a call to {@link #setDriverClassName(String)}. It does not
* return the class name of any driver that may have been set via {@link #setDriver(Driver)}.
@@ -916,7 +932,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * Returns the value of the flag that controls whether or not connections being returned to the pool will be checked
+ * 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
* setting is {@code false} when the connection is returned. It is <code>true</code> by default.
*
@@ -951,7 +967,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * Returns the initial size of the connection pool.
+ * Gets the initial size of the connection pool.
*
* @return the number of connections created when the pool is initialized
*/
@@ -961,7 +977,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * Returns the JMX name that has been requested for this DataSource. If the requested name is not valid, an
+ * Gets the JMX name that has been requested for this DataSource. If the requested name is not valid, an
* alternative may be chosen.
*
* @return The JMX name that has been requested for this DataSource.
@@ -971,7 +987,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * Returns the LIFO property.
+ * Gets the LIFO property.
*
* @return true if connection pool behaves as a LIFO queue.
*/
@@ -981,9 +997,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * <p>
* Flag to log stack traces for application code which abandoned a Statement or Connection.
- * </p>
* <p>
* Defaults to false.
* </p>
@@ -998,7 +1012,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * When {@link #getMaxConnLifetimeMillis()} is set to limit connection lifetime, this property determines whether or
+ * When {@link #getMaxConnDuration()} is set to limit connection lifetime, this property determines whether or
* not log messages are generated when the pool closes connections due to maximum lifetime exceeded.
*
* @since 2.1
@@ -1012,7 +1026,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
* <strong>BasicDataSource does NOT support this method.</strong>
*
* <p>
- * Returns the login timeout (in seconds) for connecting to the database.
+ * Gets 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.
@@ -1030,9 +1044,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * <p>
- * Returns the log writer being used by this data source.
- * </p>
+ * Gets the log writer being used by this data source.
* <p>
* Calls {@link #createDataSource()}, so has the side effect of initializing the connection pool.
* </p>
@@ -1046,19 +1058,29 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * Returns the maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an
+ * Gets the maximum permitted duration of a connection. A value of zero or less indicates an
+ * infinite lifetime.
+ * @return the maximum permitted duration of a connection.
+ * @since 2.10.0
+ */
+ public Duration getMaxConnDuration() {
+ return maxConnDuration;
+ }
+
+ /**
+ * Gets the maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an
* infinite lifetime.
+ * @deprecated Use {@link #getMaxConnDuration()}.
*/
@Override
+ @Deprecated
public long getMaxConnLifetimeMillis() {
- return maxConnLifetimeMillis;
+ return maxConnDuration.toMillis();
}
/**
- * <p>
- * Returns the maximum number of connections that can remain idle in the pool. Excess idle connections are destroyed
+ * Gets the maximum number of connections that can remain idle in the pool. Excess idle connections are destroyed
* on return to the pool.
- * </p>
* <p>
* A negative value indicates that there is no limit
* </p>
@@ -1081,9 +1103,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * <p>
- * Returns the maximum number of active connections that can be allocated at the same time.
- * </p>
+ * Gets the maximum number of active connections that can be allocated at the same time.
* <p>
* A negative number means that there is no limit.
* </p>
@@ -1096,31 +1116,57 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * Returns the maximum number of milliseconds that the pool will wait for a connection to be returned before
+ * Gets the maximum Duration that the pool will wait for a connection to be returned before throwing an exception. A
+ * value less than or equal to zero means the pool is set to wait indefinitely.
+ *
+ * @return the maxWaitDuration property value.
+ * @since 2.10.0
+ */
+ public synchronized Duration getMaxWaitDuration() {
+ return this.maxWaitDuration;
+ }
+
+ /**
+ * Gets the maximum number of milliseconds that the pool will wait for a connection to be returned before
* throwing an exception. A value less than or equal to zero means the pool is set to wait indefinitely.
*
- * @return the maxWaitMillis property value
+ * @return the maxWaitMillis property value.
+ * @deprecated Use {@link #getMaxWaitDuration()}.
*/
+ @Deprecated
@Override
public synchronized long getMaxWaitMillis() {
- return this.maxWaitMillis;
+ return this.maxWaitDuration.toMillis();
}
/**
- * Returns the {@link #minEvictableIdleTimeMillis} property.
+ * Gets the {code minEvictableIdleDuration} property.
*
- * @return the value of the {@link #minEvictableIdleTimeMillis} property
- * @see #minEvictableIdleTimeMillis
+ * @return the value of the {code minEvictableIdleDuration} property
+ * @see #setMinEvictableIdle(Duration)
+ * @since 2.10.0
*/
+ public synchronized Duration getMinEvictableIdleDuration() {
+ return this.minEvictableIdleDuration;
+ }
+
+ /**
+ * Gets the {code minEvictableIdleDuration} property.
+ *
+ * @return the value of the {code minEvictableIdleDuration} property
+ * @see #setMinEvictableIdle(Duration)
+ * @deprecated Use {@link #getMinEvictableIdleDuration()}.
+ */
+ @Deprecated
@Override
public synchronized long getMinEvictableIdleTimeMillis() {
- return this.minEvictableIdleTimeMillis;
+ return this.minEvictableIdleDuration.toMillis();
}
/**
- * Returns the minimum number of idle connections in the pool. The pool attempts to ensure that minIdle connections
+ * Gets the minimum number of idle connections in the pool. The pool attempts to ensure that minIdle connections
* are available when the idle object evictor runs. The value of this property has no effect unless
- * {@link #timeBetweenEvictionRunsMillis} has a positive value.
+ * {code durationBetweenEvictionRuns} has a positive value.
*
* @return the minimum number of idle connections
* @see GenericObjectPool#getMinIdle()
@@ -1155,10 +1201,10 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * Returns the value of the {@link #numTestsPerEvictionRun} property.
+ * Gets the value of the {code numTestsPerEvictionRun} property.
*
* @return the number of objects to examine during idle object evictor runs
- * @see #numTestsPerEvictionRun
+ * @see #setNumTestsPerEvictionRun(int)
*/
@Override
public synchronized int getNumTestsPerEvictionRun() {
@@ -1171,7 +1217,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * Returns the password passed to the JDBC driver to establish connections.
+ * Gets the password passed to the JDBC driver to establish connections.
*
* @return the connection password
*/
@@ -1180,20 +1226,23 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
return this.password;
}
+ /**
+ * Gets the registered JMX ObjectName.
+ *
+ * @return the registered JMX ObjectName.
+ */
protected ObjectName getRegisteredJmxName() {
return ObjectNameWrapper.unwrap(registeredJmxObjectName);
}
/**
- * <p>
* Flag to remove abandoned connections if they exceed the removeAbandonedTimeout when borrowObject is invoked.
- * </p>
* <p>
* The default value is false.
* </p>
* <p>
* If set to true a connection is considered abandoned and eligible for removal if it has not been used for more
- * than {@link #getRemoveAbandonedTimeout() removeAbandonedTimeout} seconds.
+ * than {@link #getRemoveAbandonedTimeoutDuration() removeAbandonedTimeout} seconds.
* </p>
* <p>
* Abandoned connections are identified and removed when {@link #getConnection()} is invoked and all of the
@@ -1205,7 +1254,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
* <li>{@link #getNumIdle()} < 2</li>
* </ul>
*
- * @see #getRemoveAbandonedTimeout()
+ * @see #getRemoveAbandonedTimeoutDuration()
*/
@Override
public boolean getRemoveAbandonedOnBorrow() {
@@ -1213,20 +1262,16 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * <p>
* Flag to remove abandoned connections if they exceed the removeAbandonedTimeout during pool maintenance.
- * </p>
- *
* <p>
* The default value is false.
* </p>
- *
* <p>
* If set to true a connection is considered abandoned and eligible for removal if it has not been used for more
- * than {@link #getRemoveAbandonedTimeout() removeAbandonedTimeout} seconds.
+ * than {@link #getRemoveAbandonedTimeoutDuration() removeAbandonedTimeout} seconds.
* </p>
*
- * @see #getRemoveAbandonedTimeout()
+ * @see #getRemoveAbandonedTimeoutDuration()
*/
@Override
public boolean getRemoveAbandonedOnMaintenance() {
@@ -1234,9 +1279,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * <p>
- * Timeout in seconds before an abandoned connection can be removed.
- * </p>
+ * Gets the timeout in seconds before an abandoned connection can be removed.
* <p>
* Creating a Statement, PreparedStatement or CallableStatement or using one of these to execute a query (using one
* of the execute methods) resets the lastUsed property of the parent connection.
@@ -1252,10 +1295,36 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
* <p>
* The default value is 300 seconds.
* </p>
+ * @deprecated Use {@link #getRemoveAbandonedTimeoutDuration()}.
*/
+ @Deprecated
@Override
public int getRemoveAbandonedTimeout() {
- return abandonedConfig == null ? 300 : abandonedConfig.getRemoveAbandonedTimeout();
+ return (int) getRemoveAbandonedTimeoutDuration().getSeconds();
+ }
+
+ /**
+ * Gets the timeout before an abandoned connection can be removed.
+ * <p>
+ * Creating a Statement, PreparedStatement or CallableStatement or using one of these to execute a query (using one
+ * of the execute methods) resets the lastUsed property of the parent connection.
+ * </p>
+ * <p>
+ * Abandoned connection cleanup happens when:
+ * </p>
+ * <ul>
+ * <li>{@link #getRemoveAbandonedOnBorrow()} or {@link #getRemoveAbandonedOnMaintenance()} = true</li>
+ * <li>{@link #getNumIdle() numIdle} < 2</li>
+ * <li>{@link #getNumActive() numActive} > {@link #getMaxTotal() maxTotal} - 3</li>
+ * </ul>
+ * <p>
+ * The default value is 300 seconds.
+ * </p>
+ * @return Timeout before an abandoned connection can be removed.
+ * @since 2.10.0
+ */
+ public Duration getRemoveAbandonedTimeoutDuration() {
+ return abandonedConfig == null ? Duration.ofSeconds(300) : abandonedConfig.getRemoveAbandonedTimeoutDuration();
}
/**
@@ -1269,11 +1338,27 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * <p>
- * Returns the minimum amount of time a connection may sit idle in the pool before it is eligible for eviction by
+ * Gets the minimum amount of time a connection may sit idle in the pool before it is eligible for eviction by
* the idle object evictor, with the extra condition that at least "minIdle" connections remain in the pool.
+ * <p>
+ * When {@link #getMinEvictableIdleTimeMillis() minEvictableIdleTimeMillis} is set to a positive value,
+ * minEvictableIdleTimeMillis is examined first by the idle connection evictor - i.e. when idle connections are
+ * visited by the evictor, idle time is first compared against {@code minEvictableIdleTimeMillis} (without
+ * considering the number of idle connections in the pool) and then against {@code softMinEvictableIdleTimeMillis},
+ * including the {@code minIdle}, constraint.
* </p>
*
+ * @return minimum amount of time a connection may sit idle in the pool before it is eligible for eviction, assuming
+ * there are minIdle idle connections in the pool
+ * @since 2.10.0
+ */
+ public synchronized Duration getSoftMinEvictableIdleDuration() {
+ return softMinEvictableIdleDuration;
+ }
+
+ /**
+ * Gets the minimum amount of time a connection may sit idle in the pool before it is eligible for eviction by
+ * the idle object evictor, with the extra condition that at least "minIdle" connections remain in the pool.
* <p>
* When {@link #getMinEvictableIdleTimeMillis() minEvictableIdleTimeMillis} is set to a positive value,
* minEvictableIdleTimeMillis is examined first by the idle connection evictor - i.e. when idle connections are
@@ -1284,18 +1369,20 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
*
* @return minimum amount of time a connection may sit idle in the pool before it is eligible for eviction, assuming
* there are minIdle idle connections in the pool
+ * @deprecated Use {@link #getSoftMinEvictableIdleDuration()}.
*/
+ @Deprecated
@Override
public synchronized long getSoftMinEvictableIdleTimeMillis() {
- return softMinEvictableIdleTimeMillis;
+ return softMinEvictableIdleDuration.toMillis();
}
/**
- * Returns the {@link #testOnBorrow} property.
+ * Gets the {code testOnBorrow} property.
*
* @return true if objects are validated before being borrowed from the pool
*
- * @see #testOnBorrow
+ * @see #setTestOnBorrow(boolean)
*/
@Override
public synchronized boolean getTestOnBorrow() {
@@ -1303,10 +1390,10 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * Returns the {@link #testOnCreate} property.
+ * Gets the {code testOnCreate} property.
*
* @return true if objects are validated immediately after they are created by the pool
- * @see #testOnCreate
+ * @see #setTestOnCreate(boolean)
*/
@Override
public synchronized boolean getTestOnCreate() {
@@ -1314,20 +1401,20 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * Returns the value of the {@link #testOnReturn} property.
+ * Gets the value of the {code testOnReturn} property.
*
* @return true if objects are validated before being returned to the pool
- * @see #testOnReturn
+ * @see #setTestOnReturn(boolean)
*/
public synchronized boolean getTestOnReturn() {
return this.testOnReturn;
}
/**
- * Returns the value of the {@link #testWhileIdle} property.
+ * Gets the value of the {code testWhileIdle} property.
*
* @return true if objects examined by the idle object evictor are validated
- * @see #testWhileIdle
+ * @see #setTestWhileIdle(boolean)
*/
@Override
public synchronized boolean getTestWhileIdle() {
@@ -1335,20 +1422,33 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * Returns the value of the {@link #timeBetweenEvictionRunsMillis} property.
+ * Gets the value of the {code durationBetweenEvictionRuns} property.
*
* @return the time (in milliseconds) between evictor runs
- * @see #timeBetweenEvictionRunsMillis
+ * @see #setDurationBetweenEvictionRuns(Duration)
+ * @since 2.10.0
*/
+ public synchronized Duration getDurationBetweenEvictionRuns() {
+ return this.durationBetweenEvictionRuns;
+ }
+
+ /**
+ * Gets the value of the {code durationBetweenEvictionRuns} property.
+ *
+ * @return the time (in milliseconds) between evictor runs
+ * @see #setDurationBetweenEvictionRuns(Duration)
+ * @deprecated Use {@link #getDurationBetweenEvictionRuns()}.
+ */
+ @Deprecated
@Override
public synchronized long getTimeBetweenEvictionRunsMillis() {
- return this.timeBetweenEvictionRunsMillis;
+ return this.durationBetweenEvictionRuns.toMillis();
}
/**
- * Returns the JDBC connection {@link #url} property.
+ * Gets the JDBC connection {code url} property.
*
- * @return the {@link #url} passed to the JDBC driver to establish connections
+ * @return the {code url} passed to the JDBC driver to establish connections
*/
@Override
public synchronized String getUrl() {
@@ -1356,9 +1456,9 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * Returns the JDBC connection {@link #userName} property.
+ * Gets the JDBC connection {code userName} property.
*
- * @return the {@link #userName} passed to the JDBC driver to establish connections
+ * @return the {code userName} passed to the JDBC driver to establish connections
*/
@Override
public String getUsername() {
@@ -1366,10 +1466,10 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * Returns the validation query used to validate connections before returning them.
+ * Gets the validation query used to validate connections before returning them.
*
* @return the SQL validation query
- * @see #validationQuery
+ * @see #setValidationQuery(String)
*/
@Override
public String getValidationQuery() {
@@ -1377,13 +1477,24 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * Returns the validation query timeout.
+ * Gets the validation query timeout.
+ *
+ * @return the timeout in seconds before connection validation queries fail.
+ */
+ public Duration getValidationQueryTimeoutDuration() {
+ return validationQueryTimeoutDuration;
+ }
+
+ /**
+ * 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 validationQueryTimeoutSeconds;
+ return (int) validationQueryTimeoutDuration.getSeconds();
}
/**
@@ -1422,7 +1533,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * Returns the value of the accessToUnderlyingConnectionAllowed property.
+ * Gets the value of the accessToUnderlyingConnectionAllowed property.
*
* @return true if access to the underlying connection is allowed, false otherwise.
*/
@@ -1474,7 +1585,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
@Override
public boolean isWrapperFor(final Class<?> iface) throws SQLException {
- return false;
+ return iface != null && iface.isInstance(this);
}
private void jmxRegister() {
@@ -1487,13 +1598,20 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
if (requestedName == null) {
return;
}
+ registeredJmxObjectName = registerJmxObjectName(requestedName, null);
try {
- ObjectNameWrapper.wrap(requestedName).registerMBean(this);
- } catch (final MalformedObjectNameException e) {
+ final StandardMBean standardMBean = new StandardMBean(this, DataSourceMXBean.class);
+ registeredJmxObjectName.registerMBean(standardMBean);
+ } catch (final NotCompliantMBeanException e) {
log.warn("The requested JMX name [" + requestedName + "] was not valid and will be ignored.");
}
}
+ /**
+ * Logs the given message.
+ *
+ * @param message the message to log.
+ */
protected void log(final String message) {
if (logWriter != null) {
logWriter.println(message);
@@ -1531,18 +1649,23 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
@Override
public ObjectName preRegister(final MBeanServer server, final ObjectName objectName) {
- final String requestedName = getJmxName();
+ registeredJmxObjectName = registerJmxObjectName(getJmxName(), objectName);
+ return ObjectNameWrapper.unwrap(registeredJmxObjectName);
+ }
+
+ private ObjectNameWrapper registerJmxObjectName(final String requestedName, final ObjectName objectName) {
+ ObjectNameWrapper objectNameWrapper = null;
if (requestedName != null) {
try {
- registeredJmxObjectName = ObjectNameWrapper.wrap(requestedName);
+ objectNameWrapper = ObjectNameWrapper.wrap(requestedName);
} catch (final MalformedObjectNameException e) {
- log.warn("The requested JMX name [" + requestedName + "] was not valid and will be ignored.");
+ log.warn("The requested JMX name '" + requestedName + "' was not valid and will be ignored.");
}
}
- if (registeredJmxObjectName == null) {
- registeredJmxObjectName = ObjectNameWrapper.wrap(objectName);
+ if (objectNameWrapper == null) {
+ objectNameWrapper = ObjectNameWrapper.wrap(objectName);
}
- return ObjectNameWrapper.unwrap(registeredJmxObjectName);
+ return objectNameWrapper;
}
/**
@@ -1616,10 +1739,8 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * <p>
* Sets the value of the accessToUnderlyingConnectionAllowed property. It controls if the PoolGuard allows access to
* the underlying connection. (Default: false)
- * </p>
* <p>
* Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
* time one of the following methods is invoked: <code>getConnection, setLogwriter,
@@ -1686,7 +1807,7 @@ 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.size() > 0) {
+ if (connectionInitSqls != null && !connectionInitSqls.isEmpty()) {
ArrayList<String> newVal = null;
for (final String s : connectionInitSqls) {
if (!isEmpty(s)) {
@@ -1718,7 +1839,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
final String[] entries = connectionProperties.split(";");
final Properties properties = new Properties();
for (final String entry : entries) {
- if (entry.length() > 0) {
+ if (!entry.isEmpty()) {
final int index = entry.indexOf('=');
if (index > 0) {
final String name = entry.substring(0, index);
@@ -1735,9 +1856,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * <p>
* Sets default auto-commit state of connections returned by this datasource.
- * </p>
* <p>
* Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
* time one of the following methods is invoked: <code>getConnection, setLogwriter,
@@ -1751,9 +1870,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * <p>
* Sets the default catalog.
- * </p>
* <p>
* Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
* time one of the following methods is invoked: <code>getConnection, setLogwriter,
@@ -1770,16 +1887,27 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
* Sets the default query timeout that will be used for {@link java.sql.Statement Statement}s created from this
* connection. <code>null</code> means that the driver default will be used.
*
+ * @param defaultQueryTimeoutDuration The default query timeout Duration.
+ * @since 2.10.0
+ */
+ public void setDefaultQueryTimeout(final Duration defaultQueryTimeoutDuration) {
+ this.defaultQueryTimeoutDuration = defaultQueryTimeoutDuration;
+ }
+
+ /**
+ * Sets the default query timeout that will be used for {@link java.sql.Statement Statement}s created from this
+ * connection. <code>null</code> means that the driver default will be used.
+ *
* @param defaultQueryTimeoutSeconds The default query timeout in seconds.
+ * @deprecated Use {@link #setDefaultQueryTimeout(Duration)}.
*/
+ @Deprecated
public void setDefaultQueryTimeout(final Integer defaultQueryTimeoutSeconds) {
- this.defaultQueryTimeoutSeconds = defaultQueryTimeoutSeconds;
+ this.defaultQueryTimeoutDuration = defaultQueryTimeoutSeconds == null ? null : Duration.ofSeconds(defaultQueryTimeoutSeconds.longValue());
}
/**
- * <p>
* Sets defaultReadonly property.
- * </p>
* <p>
* Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
* time one of the following methods is invoked: <code>getConnection, setLogwriter,
@@ -1793,9 +1921,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * <p>
* Sets the default schema.
- * </p>
* <p>
* Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
* time one of the following methods is invoked: <code>getConnection, setLogwriter,
@@ -1810,9 +1936,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * <p>
* Sets the default transaction isolation state for returned connections.
- * </p>
* <p>
* Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
* time one of the following methods is invoked: <code>getConnection, setLogwriter,
@@ -1848,7 +1972,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
* @since 2.1
*/
public void setDisconnectionSqlCodes(final Collection<String> disconnectionSqlCodes) {
- if (disconnectionSqlCodes != null && disconnectionSqlCodes.size() > 0) {
+ if (disconnectionSqlCodes != null && !disconnectionSqlCodes.isEmpty()) {
HashSet<String> newVal = null;
for (final String s : disconnectionSqlCodes) {
if (!isEmpty(s)) {
@@ -1879,9 +2003,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * <p>
* Sets the class loader to be used to load the JDBC driver.
- * </p>
* <p>
* Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
* time one of the following methods is invoked: <code>getConnection, setLogwriter,
@@ -1895,9 +2017,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * <p>
* Sets the JDBC driver class name.
- * </p>
* <p>
* Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
* time one of the following methods is invoked: <code>getConnection, setLogwriter,
@@ -1946,9 +2066,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * <p>
* Sets the initial size of the connection pool.
- * </p>
* <p>
* Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
* time one of the following methods is invoked: <code>getConnection, setLogwriter,
@@ -2000,7 +2118,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * When {@link #getMaxConnLifetimeMillis()} is set to limit connection lifetime, this property determines whether or
+ * When {@link #getMaxConnDuration()} is set to limit connection lifetime, this property determines whether or
* not log messages are generated when the pool closes connections due to maximum lifetime exceeded. Set this
* property to false to suppress log messages when connections expire.
*
@@ -2034,9 +2152,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * <p>
* Sets the log writer being used by this data source.
- * </p>
* <p>
* Calls {@link #createDataSource()}, so has the side effect of initializing the connection pool.
* </p>
@@ -2051,10 +2167,24 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
+ * Sets the maximum permitted lifetime of a connection. A value of zero or less indicates an
+ * infinite lifetime.
* <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 maxConnDuration The maximum permitted lifetime of a connection.
+ * @since 2.10.0
+ */
+ public void setMaxConn(final Duration maxConnDuration) {
+ this.maxConnDuration = maxConnDuration;
+ }
+
+ /**
* Sets the maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an
* infinite lifetime.
- * </p>
* <p>
* Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
* time one of the following methods is invoked: <code>getConnection, setLogwriter,
@@ -2062,9 +2192,11 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
* </p>
*
* @param maxConnLifetimeMillis The maximum permitted lifetime of a connection in milliseconds.
+ * @deprecated Use {@link #setMaxConn(Duration)}.
*/
+ @Deprecated
public void setMaxConnLifetimeMillis(final long maxConnLifetimeMillis) {
- this.maxConnLifetimeMillis = maxConnLifetimeMillis;
+ this.maxConnDuration = Duration.ofMillis(maxConnLifetimeMillis);
}
/**
@@ -2082,9 +2214,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * <p>
* Sets the value of the <code>maxOpenPreparedStatements</code> property.
- * </p>
* <p>
* Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
* time one of the following methods is invoked: <code>getConnection, setLogwriter,
@@ -2114,35 +2244,59 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
/**
* Sets the MaxWaitMillis property. Use -1 to make the pool wait indefinitely.
*
+ * @param maxWaitDuration the new value for MaxWaitMillis
+ * @see #getMaxWaitDuration()
+ * @since 2.10.0
+ */
+ public synchronized void setMaxWait(final Duration maxWaitDuration) {
+ this.maxWaitDuration = maxWaitDuration;
+ if (connectionPool != null) {
+ connectionPool.setMaxWait(maxWaitDuration);
+ }
+ }
+
+ /**
+ * Sets the MaxWaitMillis property. Use -1 to make the pool wait indefinitely.
+ *
* @param maxWaitMillis the new value for MaxWaitMillis
- * @see #getMaxWaitMillis()
+ * @see #getMaxWaitDuration()
+ * @deprecated {@link #setMaxWait(Duration)}.
*/
+ @Deprecated
public synchronized void setMaxWaitMillis(final long maxWaitMillis) {
- this.maxWaitMillis = maxWaitMillis;
+ setMaxWait(Duration.ofMillis(maxWaitMillis));
+ }
+
+ /**
+ * Sets the {code minEvictableIdleDuration} property.
+ *
+ * @param minEvictableIdleDuration the minimum amount of time an object may sit idle in the pool
+ * @see #setMinEvictableIdle(Duration)
+ * @since 2.10.0
+ */
+ public synchronized void setMinEvictableIdle(final Duration minEvictableIdleDuration) {
+ this.minEvictableIdleDuration = minEvictableIdleDuration;
if (connectionPool != null) {
- connectionPool.setMaxWaitMillis(maxWaitMillis);
+ connectionPool.setMinEvictableIdle(minEvictableIdleDuration);
}
}
/**
- * Sets the {@link #minEvictableIdleTimeMillis} property.
+ * Sets the {code minEvictableIdleDuration} property.
*
* @param minEvictableIdleTimeMillis the minimum amount of time an object may sit idle in the pool
- * @see #minEvictableIdleTimeMillis
+ * @see #setMinEvictableIdle(Duration)
+ * @deprecated Use {@link #setMinEvictableIdle(Duration)}.
*/
+ @Deprecated
public synchronized void setMinEvictableIdleTimeMillis(final long minEvictableIdleTimeMillis) {
- this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
- if (connectionPool != null) {
- connectionPool.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
- }
+ setMinEvictableIdle(Duration.ofMillis(minEvictableIdleTimeMillis));
}
- // ------------------------------------------------------ Protected Methods
-
/**
* Sets the minimum number of idle connections in the pool. The pool attempts to ensure that minIdle connections are
* available when the idle object evictor runs. The value of this property has no effect unless
- * {@link #timeBetweenEvictionRunsMillis} has a positive value.
+ * {code durationBetweenEvictionRuns} has a positive value.
*
* @param minIdle the new value for minIdle
* @see GenericObjectPool#setMinIdle(int)
@@ -2155,10 +2309,10 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * Sets the value of the {@link #numTestsPerEvictionRun} property.
+ * Sets the value of the {code numTestsPerEvictionRun} property.
*
- * @param numTestsPerEvictionRun the new {@link #numTestsPerEvictionRun} value
- * @see #numTestsPerEvictionRun
+ * @param numTestsPerEvictionRun the new {code numTestsPerEvictionRun} value
+ * @see #setNumTestsPerEvictionRun(int)
*/
public synchronized void setNumTestsPerEvictionRun(final int numTestsPerEvictionRun) {
this.numTestsPerEvictionRun = numTestsPerEvictionRun;
@@ -2168,9 +2322,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * <p>
- * Sets the {@link #password}.
- * </p>
+ * Sets the {code password}.
* <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,
@@ -2184,9 +2336,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * <p>
* Sets whether to pool statements or not.
- * </p>
* <p>
* Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
* time one of the following methods is invoked: <code>getConnection, setLogwriter,
@@ -2231,25 +2381,48 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
+ * Sets the timeout before an abandoned connection can be removed.
* <p>
- * Sets the timeout in seconds before an abandoned connection can be removed.
+ * Setting this property has no effect if {@link #getRemoveAbandonedOnBorrow()} and
+ * {code getRemoveAbandonedOnMaintenance()} are false.
* </p>
*
+ * @param removeAbandonedTimeout new abandoned timeout
+ * @see #getRemoveAbandonedTimeoutDuration()
+ * @see #getRemoveAbandonedOnBorrow()
+ * @see #getRemoveAbandonedOnMaintenance()
+ * @since 2.10.0
+ */
+ public void setRemoveAbandonedTimeout(final Duration removeAbandonedTimeout) {
+ if (abandonedConfig == null) {
+ abandonedConfig = new AbandonedConfig();
+ }
+ abandonedConfig.setRemoveAbandonedTimeout(removeAbandonedTimeout);
+ final GenericObjectPool<?> gop = this.connectionPool;
+ if (gop != null) {
+ gop.setAbandonedConfig(abandonedConfig);
+ }
+ }
+
+ /**
+ * Sets the timeout in seconds before an abandoned connection can be removed.
* <p>
* Setting this property has no effect if {@link #getRemoveAbandonedOnBorrow()} and
* {@link #getRemoveAbandonedOnMaintenance()} are false.
* </p>
*
* @param removeAbandonedTimeout new abandoned timeout in seconds
- * @see #getRemoveAbandonedTimeout()
+ * @see #getRemoveAbandonedTimeoutDuration()
* @see #getRemoveAbandonedOnBorrow()
* @see #getRemoveAbandonedOnMaintenance()
+ * @deprecated Use {@link #setRemoveAbandonedTimeout(Duration)}.
*/
+ @Deprecated
public void setRemoveAbandonedTimeout(final int removeAbandonedTimeout) {
if (abandonedConfig == null) {
abandonedConfig = new AbandonedConfig();
}
- abandonedConfig.setRemoveAbandonedTimeout(removeAbandonedTimeout);
+ abandonedConfig.setRemoveAbandonedTimeout(Duration.ofSeconds(removeAbandonedTimeout));
final GenericObjectPool<?> gop = this.connectionPool;
if (gop != null) {
gop.setAbandonedConfig(abandonedConfig);
@@ -2274,16 +2447,32 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
* eligible for eviction, assuming there are minIdle idle connections in the
* pool.
* @see #getSoftMinEvictableIdleTimeMillis
+ * @since 2.10.0
*/
- public synchronized void setSoftMinEvictableIdleTimeMillis(final long softMinEvictableIdleTimeMillis) {
- this.softMinEvictableIdleTimeMillis = softMinEvictableIdleTimeMillis;
+ public synchronized void setSoftMinEvictableIdle(final Duration softMinEvictableIdleTimeMillis) {
+ this.softMinEvictableIdleDuration = softMinEvictableIdleTimeMillis;
if (connectionPool != null) {
- connectionPool.setSoftMinEvictableIdleTimeMillis(softMinEvictableIdleTimeMillis);
+ connectionPool.setSoftMinEvictableIdle(softMinEvictableIdleTimeMillis);
}
}
/**
- * Sets the {@link #testOnBorrow} property. This property determines whether or not the pool will validate objects
+ * Sets the minimum amount of time a connection may sit idle in the pool before it is eligible for eviction by the
+ * idle object evictor, with the extra condition that at least "minIdle" connections remain in the pool.
+ *
+ * @param softMinEvictableIdleTimeMillis minimum amount of time a connection may sit idle in the pool before it is
+ * eligible for eviction, assuming there are minIdle idle connections in the
+ * pool.
+ * @see #getSoftMinEvictableIdleTimeMillis
+ * @deprecated Use {@link #setSoftMinEvictableIdle(Duration)}.
+ */
+ @Deprecated
+ public synchronized void setSoftMinEvictableIdleTimeMillis(final long softMinEvictableIdleTimeMillis) {
+ setSoftMinEvictableIdle(Duration.ofMillis(softMinEvictableIdleTimeMillis));
+ }
+
+ /**
+ * Sets the {code testOnBorrow} property. This property determines whether or not the pool will validate objects
* before they are borrowed from the pool.
*
* @param testOnBorrow new value for testOnBorrow property
@@ -2296,7 +2485,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * Sets the {@link #testOnCreate} property. This property determines whether or not the pool will validate objects
+ * Sets the {code testOnCreate} property. This property determines whether or not the pool will validate objects
* immediately after they are created by the pool
*
* @param testOnCreate new value for testOnCreate property
@@ -2335,22 +2524,33 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * Sets the {@link #timeBetweenEvictionRunsMillis} property.
+ * Sets the {code durationBetweenEvictionRuns} property.
*
* @param timeBetweenEvictionRunsMillis the new time between evictor runs
- * @see #timeBetweenEvictionRunsMillis
+ * @see #setDurationBetweenEvictionRuns(Duration)
+ * @since 2.10.0
*/
- public synchronized void setTimeBetweenEvictionRunsMillis(final long timeBetweenEvictionRunsMillis) {
- this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
+ public synchronized void setDurationBetweenEvictionRuns(final Duration timeBetweenEvictionRunsMillis) {
+ this.durationBetweenEvictionRuns = timeBetweenEvictionRunsMillis;
if (connectionPool != null) {
- connectionPool.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
+ connectionPool.setTimeBetweenEvictionRuns(timeBetweenEvictionRunsMillis);
}
}
/**
- * <p>
- * Sets the {@link #url}.
- * </p>
+ * Sets the {code durationBetweenEvictionRuns} property.
+ *
+ * @param timeBetweenEvictionRunsMillis the new time between evictor runs
+ * @see #setDurationBetweenEvictionRuns(Duration)
+ * @deprecated Use {@link #setDurationBetweenEvictionRuns(Duration)}.
+ */
+ @Deprecated
+ public synchronized void setTimeBetweenEvictionRunsMillis(final long timeBetweenEvictionRunsMillis) {
+ setDurationBetweenEvictionRuns(Duration.ofMillis(timeBetweenEvictionRunsMillis));
+ }
+
+ /**
+ * Sets the {code url}.
* <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,
@@ -2364,9 +2564,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * <p>
- * Sets the {@link #userName}.
- * </p>
+ * Sets the {code userName}.
* <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,
@@ -2380,9 +2578,7 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * <p>
- * Sets the {@link #validationQuery}.
- * </p>
+ * Sets the {code validationQuery}.
* <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,
@@ -2404,10 +2600,28 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
* setLoginTimeout, getLoginTimeout, getLogWriter.</code>
* </p>
*
+ * @param validationQueryTimeoutDuration new validation query timeout value in seconds
+ * @since 2.10.0
+ */
+ public void setValidationQueryTimeout(final Duration validationQueryTimeoutDuration) {
+ this.validationQueryTimeoutDuration = validationQueryTimeoutDuration;
+ }
+
+ /**
+ * Sets the validation query timeout, the amount of time, in seconds, that connection validation will wait for a
+ * response from the database when executing a validation query. Use a value less than or equal to 0 for no timeout.
+ * <p>
+ * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+ * time one of the following methods is invoked: <code>getConnection, setLogwriter,
+ * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+ * </p>
+ *
* @param validationQueryTimeoutSeconds new validation query timeout value in seconds
+ * @deprecated Use {@link #setValidationQueryTimeout(Duration)}.
*/
+ @Deprecated
public void setValidationQueryTimeout(final int validationQueryTimeoutSeconds) {
- this.validationQueryTimeoutSeconds = validationQueryTimeoutSeconds;
+ this.validationQueryTimeoutDuration = Duration.ofSeconds(validationQueryTimeoutSeconds);
}
/**
@@ -2437,14 +2651,17 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
* Starts the connection pool maintenance task, if configured.
*/
protected void startPoolMaintenance() {
- if (connectionPool != null && timeBetweenEvictionRunsMillis > 0) {
- connectionPool.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
+ if (connectionPool != null && durationBetweenEvictionRuns.compareTo(Duration.ZERO) > 0) {
+ connectionPool.setTimeBetweenEvictionRuns(durationBetweenEvictionRuns);
}
}
@Override
public <T> T unwrap(final Class<T> iface) throws SQLException {
- throw new SQLException("BasicDataSource is not a wrapper.");
+ if (isWrapperFor(iface)) {
+ return iface.cast(this);
+ }
+ throw new SQLException(this + " is not a wrapper for " + iface);
}
private void updateJmxName(final GenericObjectPoolConfig<?> config) {
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceFactory.java b/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceFactory.java
index 7f63be4..a71f8ff 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceFactory.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceFactory.java
@@ -17,8 +17,10 @@
package org.apache.tomcat.dbcp.dbcp2;
import java.io.ByteArrayInputStream;
+import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.sql.Connection;
+import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -26,9 +28,14 @@ import java.util.Enumeration;
import java.util.Hashtable;
import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
import java.util.Properties;
import java.util.StringTokenizer;
+import java.util.function.Consumer;
+import java.util.function.Function;
import javax.naming.Context;
import javax.naming.Name;
@@ -42,11 +49,9 @@ import org.apache.tomcat.dbcp.pool2.impl.BaseObjectPoolConfig;
import org.apache.tomcat.dbcp.pool2.impl.GenericObjectPoolConfig;
/**
- * <p>
* JNDI object factory that creates an instance of <code>BasicDataSource</code> that has been configured based on the
* <code>RefAddr</code> values of the specified <code>Reference</code>, which must match the names and data types of the
* <code>BasicDataSource</code> bean properties with the following exceptions:
- * </p>
* <ul>
* <li><code>connectionInitSqls</code> must be passed to this factory as a single String using semicolon to delimit the
* statements whereas <code>BasicDataSource</code> requires a collection of Strings.</li>
@@ -162,7 +167,7 @@ public class BasicDataSourceFactory implements ObjectFactory {
+ "Both have default value set to false.");
NUPROP_WARNTEXT.put(NUPROP_MAXWAIT,
"Property " + NUPROP_MAXWAIT + " is not used in DBCP2" + " , use " + PROP_MAX_WAIT_MILLIS + " instead. "
- + PROP_MAX_WAIT_MILLIS + " default value is " + BaseObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS
+ + PROP_MAX_WAIT_MILLIS + " default value is " + BaseObjectPoolConfig.DEFAULT_MAX_WAIT
+ ".");
}
@@ -180,13 +185,173 @@ public class BasicDataSourceFactory implements ObjectFactory {
}
- // -------------------------------------------------- ObjectFactory Methods
+ private static <V> void accept(final Properties properties, final String name, final Function<String, V> parser, final Consumer<V> consumer) {
+ getOptional(properties, name).ifPresent(v -> consumer.accept(parser.apply(v)));
+ }
+
+ private static void acceptBoolean(final Properties properties, final String name, final Consumer<Boolean> consumer) {
+ accept(properties, name, Boolean::parseBoolean, consumer);
+ }
+
+ private static void acceptDurationOfMillis(final Properties properties, final String name, final Consumer<Duration> consumer) {
+ accept(properties, name, s -> Duration.ofMillis(Long.parseLong(s)), consumer);
+ }
+
+ private static void acceptDurationOfSeconds(final Properties properties, final String name, final Consumer<Duration> consumer) {
+ accept(properties, name, s -> Duration.ofSeconds(Long.parseLong(s)), consumer);
+ }
+
+ private static void acceptInt(final Properties properties, final String name, final Consumer<Integer> consumer) {
+ accept(properties, name, Integer::parseInt, consumer);
+ }
+
+ private static void acceptString(final Properties properties, final String name, final Consumer<String> consumer) {
+ accept(properties, name, Function.identity(), consumer);
+ }
+
+ /**
+ * Creates and configures a {@link BasicDataSource} instance based on the given properties.
+ *
+ * @param properties
+ * The data source configuration properties.
+ * @return A new a {@link BasicDataSource} instance based on the given properties.
+ * @throws Exception
+ * Thrown when an error occurs creating the data source.
+ */
+ public static BasicDataSource createDataSource(final Properties properties) throws Exception {
+ final BasicDataSource dataSource = new BasicDataSource();
+ acceptBoolean(properties, PROP_DEFAULT_AUTO_COMMIT, dataSource::setDefaultAutoCommit);
+ acceptBoolean(properties, PROP_DEFAULT_READ_ONLY, dataSource::setDefaultReadOnly);
+
+ getOptional(properties, PROP_DEFAULT_TRANSACTION_ISOLATION).ifPresent(value -> {
+ value = value.toUpperCase(Locale.ROOT);
+ int level = PoolableConnectionFactory.UNKNOWN_TRANSACTION_ISOLATION;
+ if ("NONE".equals(value)) {
+ level = Connection.TRANSACTION_NONE;
+ } else if ("READ_COMMITTED".equals(value)) {
+ level = Connection.TRANSACTION_READ_COMMITTED;
+ } else if ("READ_UNCOMMITTED".equals(value)) {
+ level = Connection.TRANSACTION_READ_UNCOMMITTED;
+ } else if ("REPEATABLE_READ".equals(value)) {
+ level = Connection.TRANSACTION_REPEATABLE_READ;
+ } else if ("SERIALIZABLE".equals(value)) {
+ level = Connection.TRANSACTION_SERIALIZABLE;
+ } else {
+ try {
+ level = Integer.parseInt(value);
+ } catch (final NumberFormatException e) {
+ System.err.println("Could not parse defaultTransactionIsolation: " + value);
+ System.err.println("WARNING: defaultTransactionIsolation not set");
+ System.err.println("using default value of database driver");
+ level = PoolableConnectionFactory.UNKNOWN_TRANSACTION_ISOLATION;
+ }
+ }
+ dataSource.setDefaultTransactionIsolation(level);
+ });
+
+ acceptString(properties, PROP_DEFAULT_SCHEMA, dataSource::setDefaultSchema);
+ acceptString(properties, PROP_DEFAULT_CATALOG, dataSource::setDefaultCatalog);
+ acceptBoolean(properties, PROP_CACHE_STATE, dataSource::setCacheState);
+ acceptString(properties, PROP_DRIVER_CLASS_NAME, dataSource::setDriverClassName);
+ acceptBoolean(properties, PROP_LIFO, dataSource::setLifo);
+ acceptInt(properties, PROP_MAX_TOTAL, dataSource::setMaxTotal);
+ acceptInt(properties, PROP_MAX_IDLE, dataSource::setMaxIdle);
+ acceptInt(properties, PROP_MIN_IDLE, dataSource::setMinIdle);
+ acceptInt(properties, PROP_INITIAL_SIZE, dataSource::setInitialSize);
+ acceptDurationOfMillis(properties, PROP_MAX_WAIT_MILLIS, dataSource::setMaxWait);
+ acceptBoolean(properties, PROP_TEST_ON_CREATE, dataSource::setTestOnCreate);
+ acceptBoolean(properties, PROP_TEST_ON_BORROW, dataSource::setTestOnBorrow);
+ acceptBoolean(properties, PROP_TEST_ON_RETURN, dataSource::setTestOnReturn);
+ acceptDurationOfMillis(properties, PROP_TIME_BETWEEN_EVICTION_RUNS_MILLIS, dataSource::setDurationBetweenEvictionRuns);
+ acceptInt(properties, PROP_NUM_TESTS_PER_EVICTION_RUN, dataSource::setNumTestsPerEvictionRun);
+ acceptDurationOfMillis(properties, PROP_MIN_EVICTABLE_IDLE_TIME_MILLIS, dataSource::setMinEvictableIdle);
+ acceptDurationOfMillis(properties, PROP_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS, dataSource::setSoftMinEvictableIdle);
+ acceptString(properties, PROP_EVICTION_POLICY_CLASS_NAME, dataSource::setEvictionPolicyClassName);
+ acceptBoolean(properties, PROP_TEST_WHILE_IDLE, dataSource::setTestWhileIdle);
+ acceptString(properties, PROP_PASSWORD, dataSource::setPassword);
+ acceptString(properties, PROP_URL, dataSource::setUrl);
+ acceptString(properties, PROP_USER_NAME, dataSource::setUsername);
+ acceptString(properties, PROP_VALIDATION_QUERY, dataSource::setValidationQuery);
+ acceptDurationOfSeconds(properties, PROP_VALIDATION_QUERY_TIMEOUT, dataSource::setValidationQueryTimeout);
+ acceptBoolean(properties, PROP_ACCESS_TO_UNDERLYING_CONNECTION_ALLOWED, dataSource::setAccessToUnderlyingConnectionAllowed);
+ acceptBoolean(properties, PROP_REMOVE_ABANDONED_ON_BORROW, dataSource::setRemoveAbandonedOnBorrow);
+ acceptBoolean(properties, PROP_REMOVE_ABANDONED_ON_MAINTENANCE, dataSource::setRemoveAbandonedOnMaintenance);
+ acceptDurationOfSeconds(properties, PROP_REMOVE_ABANDONED_TIMEOUT, dataSource::setRemoveAbandonedTimeout);
+ acceptBoolean(properties, PROP_LOG_ABANDONED, dataSource::setLogAbandoned);
+ acceptBoolean(properties, PROP_ABANDONED_USAGE_TRACKING, dataSource::setAbandonedUsageTracking);
+ acceptBoolean(properties, PROP_POOL_PREPARED_STATEMENTS, dataSource::setPoolPreparedStatements);
+ acceptBoolean(properties, PROP_CLEAR_STATEMENT_POOL_ON_RETURN, dataSource::setClearStatementPoolOnReturn);
+ acceptInt(properties, PROP_MAX_OPEN_PREPARED_STATEMENTS, dataSource::setMaxOpenPreparedStatements);
+ getOptional(properties, PROP_CONNECTION_INIT_SQLS).ifPresent(v -> dataSource.setConnectionInitSqls(parseList(v, ';')));
+
+ final String value = properties.getProperty(PROP_CONNECTION_PROPERTIES);
+ if (value != null) {
+ for (final Object key : getProperties(value).keySet()) {
+ final String propertyName = Objects.toString(key, null);
+ dataSource.addConnectionProperty(propertyName, getProperties(value).getProperty(propertyName));
+ }
+ }
+
+ acceptDurationOfMillis(properties, PROP_MAX_CONN_LIFETIME_MILLIS, dataSource::setMaxConn);
+ acceptBoolean(properties, PROP_LOG_EXPIRED_CONNECTIONS, dataSource::setLogExpiredConnections);
+ acceptString(properties, PROP_JMX_NAME, dataSource::setJmxName);
+ acceptBoolean(properties, PROP_ENABLE_AUTO_COMMIT_ON_RETURN, dataSource::setAutoCommitOnReturn);
+ acceptBoolean(properties, PROP_ROLLBACK_ON_RETURN, dataSource::setRollbackOnReturn);
+ acceptDurationOfSeconds(properties, PROP_DEFAULT_QUERY_TIMEOUT, dataSource::setDefaultQueryTimeout);
+ acceptBoolean(properties, PROP_FAST_FAIL_VALIDATION, dataSource::setFastFailValidation);
+ getOptional(properties, PROP_DISCONNECTION_SQL_CODES).ifPresent(v -> dataSource.setDisconnectionSqlCodes(parseList(v, ',')));
+ acceptString(properties, PROP_CONNECTION_FACTORY_CLASS_NAME, dataSource::setConnectionFactoryClassName);
+
+ // DBCP-215
+ // Trick to make sure that initialSize connections are created
+ if (dataSource.getInitialSize() > 0) {
+ dataSource.getLogWriter();
+ }
+
+ // Return the configured DataSource instance
+ return dataSource;
+ }
+
+ private static Optional<String> getOptional(final Properties properties, final String name) {
+ return Optional.ofNullable(properties.getProperty(name));
+ }
+
+ /**
+ * Parse properties from the string. Format of the string must be [propertyName=property;]*
+ *
+ * @param propText
+ * @return Properties
+ * @throws IOException
+ */
+ private static Properties getProperties(final String propText) throws IOException {
+ final Properties p = new Properties();
+ if (propText != null) {
+ p.load(new ByteArrayInputStream(propText.replace(';', '\n').getBytes(StandardCharsets.ISO_8859_1)));
+ }
+ return p;
+ }
/**
- * <p>
- * Create and return a new <code>BasicDataSource</code> instance. If no instance can be created, return
+ * Parse list of property values from a delimited string
+ *
+ * @param value
+ * delimited list of values
+ * @param delimiter
+ * character used to separate values in the list
+ * @return String Collection of values
+ */
+ private static Collection<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());
+ while (tokenizer.hasMoreTokens()) {
+ tokens.add(tokenizer.nextToken());
+ }
+ return tokens;
+ }
+
+ /**
+ * Creates and return a new <code>BasicDataSource</code> instance. If no instance can be created, return
* <code>null</code> instead.
- * </p>
*
* @param obj
* The possibly null object containing location or reference information that can be used in creating an
@@ -217,22 +382,17 @@ public class BasicDataSourceFactory implements ObjectFactory {
}
// Check property names and log warnings about obsolete and / or unknown properties
- final List<String> warnings = new ArrayList<>();
+ final List<String> warnMessages = new ArrayList<>();
final List<String> infoMessages = new ArrayList<>();
- validatePropertyNames(ref, name, warnings, infoMessages);
- for (final String warning : warnings) {
- log.warn(warning);
- }
- for (final String infoMessage : infoMessages) {
- log.info(infoMessage);
- }
+ validatePropertyNames(ref, name, warnMessages, infoMessages);
+ warnMessages.forEach(log::warn);
+ infoMessages.forEach(log::info);
final Properties properties = new Properties();
for (final String propertyName : ALL_PROPERTIES) {
final RefAddr ra = ref.get(propertyName);
if (ra != null) {
- final String propertyValue = ra.getContent().toString();
- properties.setProperty(propertyName, propertyValue);
+ properties.setProperty(propertyName, Objects.toString(ra.getContent(), null));
}
}
@@ -247,12 +407,12 @@ public class BasicDataSourceFactory implements ObjectFactory {
* Reference to check properties of
* @param name
* Name provided to getObject
- * @param warnings
+ * @param warnMessages
* container for warning messages
* @param infoMessages
* container for info messages
*/
- private void validatePropertyNames(final Reference ref, final Name name, final List<String> warnings,
+ private void validatePropertyNames(final Reference ref, final Name name, final List<String> warnMessages,
final List<String> infoMessages) {
final List<String> allPropsAsList = Arrays.asList(ALL_PROPERTIES);
final String nameString = name != null ? "Name = " + name.toString() + " " : "";
@@ -261,11 +421,11 @@ public class BasicDataSourceFactory implements ObjectFactory {
final RefAddr ra = ref.get(propertyName);
if (ra != null && !allPropsAsList.contains(ra.getType())) {
final StringBuilder stringBuilder = new StringBuilder(nameString);
- final String propertyValue = ra.getContent().toString();
+ final String propertyValue = Objects.toString(ra.getContent(), null);
stringBuilder.append(NUPROP_WARNTEXT.get(propertyName)).append(" You have set value of \"")
.append(propertyValue).append("\" for \"").append(propertyName)
.append("\" property, which is being ignored.");
- warnings.add(stringBuilder.toString());
+ warnMessages.add(stringBuilder.toString());
}
}
}
@@ -278,7 +438,7 @@ public class BasicDataSourceFactory implements ObjectFactory {
// and it is not in the "silent" list, tell user we are ignoring it.
if (!(allPropsAsList.contains(propertyName) || NUPROP_WARNTEXT.containsKey(propertyName)
|| SILENT_PROPERTIES.contains(propertyName))) {
- final String propertyValue = ra.getContent().toString();
+ 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");
@@ -286,321 +446,4 @@ public class BasicDataSourceFactory implements ObjectFactory {
}
}
}
-
- /**
- * Creates and configures a {@link BasicDataSource} instance based on the given properties.
- *
- * @param properties
- * The data source configuration properties.
- * @return A new a {@link BasicDataSource} instance based on the given properties.
- * @throws Exception
- * Thrown when an error occurs creating the data source.
- */
- public static BasicDataSource createDataSource(final Properties properties) throws Exception {
- final BasicDataSource dataSource = new BasicDataSource();
- String value = properties.getProperty(PROP_DEFAULT_AUTO_COMMIT);
- if (value != null) {
- dataSource.setDefaultAutoCommit(Boolean.valueOf(value));
- }
-
- value = properties.getProperty(PROP_DEFAULT_READ_ONLY);
- if (value != null) {
- dataSource.setDefaultReadOnly(Boolean.valueOf(value));
- }
-
- value = properties.getProperty(PROP_DEFAULT_TRANSACTION_ISOLATION);
- if (value != null) {
- int level = PoolableConnectionFactory.UNKNOWN_TRANSACTION_ISOLATION;
- if ("NONE".equalsIgnoreCase(value)) {
- level = Connection.TRANSACTION_NONE;
- } else if ("READ_COMMITTED".equalsIgnoreCase(value)) {
- level = Connection.TRANSACTION_READ_COMMITTED;
- } else if ("READ_UNCOMMITTED".equalsIgnoreCase(value)) {
- level = Connection.TRANSACTION_READ_UNCOMMITTED;
- } else if ("REPEATABLE_READ".equalsIgnoreCase(value)) {
- level = Connection.TRANSACTION_REPEATABLE_READ;
- } else if ("SERIALIZABLE".equalsIgnoreCase(value)) {
- level = Connection.TRANSACTION_SERIALIZABLE;
- } else {
- try {
- level = Integer.parseInt(value);
- } catch (final NumberFormatException e) {
- System.err.println("Could not parse defaultTransactionIsolation: " + value);
- System.err.println("WARNING: defaultTransactionIsolation not set");
- System.err.println("using default value of database driver");
- level = PoolableConnectionFactory.UNKNOWN_TRANSACTION_ISOLATION;
- }
- }
- dataSource.setDefaultTransactionIsolation(level);
- }
-
- value = properties.getProperty(PROP_DEFAULT_CATALOG);
- if (value != null) {
- dataSource.setDefaultCatalog(value);
- }
-
- value = properties.getProperty(PROP_DEFAULT_SCHEMA);
- if (value != null) {
- dataSource.setDefaultSchema(value);
- }
-
- value = properties.getProperty(PROP_CACHE_STATE);
- if (value != null) {
- dataSource.setCacheState(Boolean.parseBoolean(value));
- }
-
- value = properties.getProperty(PROP_DRIVER_CLASS_NAME);
- if (value != null) {
- dataSource.setDriverClassName(value);
- }
-
- value = properties.getProperty(PROP_LIFO);
- if (value != null) {
- dataSource.setLifo(Boolean.parseBoolean(value));
- }
-
- value = properties.getProperty(PROP_MAX_TOTAL);
- if (value != null) {
- dataSource.setMaxTotal(Integer.parseInt(value));
- }
-
- value = properties.getProperty(PROP_MAX_IDLE);
- if (value != null) {
- dataSource.setMaxIdle(Integer.parseInt(value));
- }
-
- value = properties.getProperty(PROP_MIN_IDLE);
- if (value != null) {
- dataSource.setMinIdle(Integer.parseInt(value));
- }
-
- value = properties.getProperty(PROP_INITIAL_SIZE);
- if (value != null) {
- dataSource.setInitialSize(Integer.parseInt(value));
- }
-
- value = properties.getProperty(PROP_MAX_WAIT_MILLIS);
- if (value != null) {
- dataSource.setMaxWaitMillis(Long.parseLong(value));
- }
-
- value = properties.getProperty(PROP_TEST_ON_CREATE);
- if (value != null) {
- dataSource.setTestOnCreate(Boolean.parseBoolean(value));
- }
-
- value = properties.getProperty(PROP_TEST_ON_BORROW);
- if (value != null) {
- dataSource.setTestOnBorrow(Boolean.parseBoolean(value));
- }
-
- value = properties.getProperty(PROP_TEST_ON_RETURN);
- if (value != null) {
- dataSource.setTestOnReturn(Boolean.parseBoolean(value));
- }
-
- value = properties.getProperty(PROP_TIME_BETWEEN_EVICTION_RUNS_MILLIS);
- if (value != null) {
- dataSource.setTimeBetweenEvictionRunsMillis(Long.parseLong(value));
- }
-
- value = properties.getProperty(PROP_NUM_TESTS_PER_EVICTION_RUN);
- if (value != null) {
- dataSource.setNumTestsPerEvictionRun(Integer.parseInt(value));
- }
-
- value = properties.getProperty(PROP_MIN_EVICTABLE_IDLE_TIME_MILLIS);
- if (value != null) {
- dataSource.setMinEvictableIdleTimeMillis(Long.parseLong(value));
- }
-
- value = properties.getProperty(PROP_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS);
- if (value != null) {
- dataSource.setSoftMinEvictableIdleTimeMillis(Long.parseLong(value));
- }
-
- value = properties.getProperty(PROP_EVICTION_POLICY_CLASS_NAME);
- if (value != null) {
- dataSource.setEvictionPolicyClassName(value);
- }
-
- value = properties.getProperty(PROP_TEST_WHILE_IDLE);
- if (value != null) {
- dataSource.setTestWhileIdle(Boolean.parseBoolean(value));
- }
-
- value = properties.getProperty(PROP_PASSWORD);
- if (value != null) {
- dataSource.setPassword(value);
- }
-
- value = properties.getProperty(PROP_URL);
- if (value != null) {
- dataSource.setUrl(value);
- }
-
- value = properties.getProperty(PROP_USER_NAME);
- if (value != null) {
- dataSource.setUsername(value);
- }
-
- value = properties.getProperty(PROP_VALIDATION_QUERY);
- if (value != null) {
- dataSource.setValidationQuery(value);
- }
-
- value = properties.getProperty(PROP_VALIDATION_QUERY_TIMEOUT);
- if (value != null) {
- dataSource.setValidationQueryTimeout(Integer.parseInt(value));
- }
-
- value = properties.getProperty(PROP_ACCESS_TO_UNDERLYING_CONNECTION_ALLOWED);
- if (value != null) {
- dataSource.setAccessToUnderlyingConnectionAllowed(Boolean.parseBoolean(value));
- }
-
- value = properties.getProperty(PROP_REMOVE_ABANDONED_ON_BORROW);
- if (value != null) {
- dataSource.setRemoveAbandonedOnBorrow(Boolean.parseBoolean(value));
- }
-
- value = properties.getProperty(PROP_REMOVE_ABANDONED_ON_MAINTENANCE);
- if (value != null) {
- dataSource.setRemoveAbandonedOnMaintenance(Boolean.parseBoolean(value));
- }
-
- value = properties.getProperty(PROP_REMOVE_ABANDONED_TIMEOUT);
- if (value != null) {
- dataSource.setRemoveAbandonedTimeout(Integer.parseInt(value));
- }
-
- value = properties.getProperty(PROP_LOG_ABANDONED);
- if (value != null) {
- dataSource.setLogAbandoned(Boolean.parseBoolean(value));
- }
-
- value = properties.getProperty(PROP_ABANDONED_USAGE_TRACKING);
- if (value != null) {
- dataSource.setAbandonedUsageTracking(Boolean.parseBoolean(value));
- }
-
- value = properties.getProperty(PROP_POOL_PREPARED_STATEMENTS);
- if (value != null) {
- dataSource.setPoolPreparedStatements(Boolean.parseBoolean(value));
- }
-
- value = properties.getProperty(PROP_CLEAR_STATEMENT_POOL_ON_RETURN);
- if (value != null) {
- dataSource.setClearStatementPoolOnReturn(Boolean.parseBoolean(value));
- }
-
- value = properties.getProperty(PROP_MAX_OPEN_PREPARED_STATEMENTS);
- if (value != null) {
- dataSource.setMaxOpenPreparedStatements(Integer.parseInt(value));
- }
-
- value = properties.getProperty(PROP_CONNECTION_INIT_SQLS);
- if (value != null) {
- dataSource.setConnectionInitSqls(parseList(value, ';'));
- }
-
- value = properties.getProperty(PROP_CONNECTION_PROPERTIES);
- if (value != null) {
- final Properties p = getProperties(value);
- final Enumeration<?> e = p.propertyNames();
- while (e.hasMoreElements()) {
- final String propertyName = (String) e.nextElement();
- dataSource.addConnectionProperty(propertyName, p.getProperty(propertyName));
- }
- }
-
- value = properties.getProperty(PROP_MAX_CONN_LIFETIME_MILLIS);
- if (value != null) {
- dataSource.setMaxConnLifetimeMillis(Long.parseLong(value));
- }
-
- value = properties.getProperty(PROP_LOG_EXPIRED_CONNECTIONS);
- if (value != null) {
- dataSource.setLogExpiredConnections(Boolean.parseBoolean(value));
- }
-
- value = properties.getProperty(PROP_JMX_NAME);
- if (value != null) {
- dataSource.setJmxName(value);
- }
-
- value = properties.getProperty(PROP_ENABLE_AUTO_COMMIT_ON_RETURN);
- if (value != null) {
- dataSource.setAutoCommitOnReturn(Boolean.parseBoolean(value));
- }
-
- value = properties.getProperty(PROP_ROLLBACK_ON_RETURN);
- if (value != null) {
- dataSource.setRollbackOnReturn(Boolean.parseBoolean(value));
- }
-
- value = properties.getProperty(PROP_DEFAULT_QUERY_TIMEOUT);
- if (value != null) {
- dataSource.setDefaultQueryTimeout(Integer.valueOf(value));
- }
-
- value = properties.getProperty(PROP_FAST_FAIL_VALIDATION);
- if (value != null) {
- dataSource.setFastFailValidation(Boolean.parseBoolean(value));
- }
-
- value = properties.getProperty(PROP_DISCONNECTION_SQL_CODES);
- if (value != null) {
- dataSource.setDisconnectionSqlCodes(parseList(value, ','));
- }
-
- value = properties.getProperty(PROP_CONNECTION_FACTORY_CLASS_NAME);
- if (value != null) {
- dataSource.setConnectionFactoryClassName(value);
- }
-
- // DBCP-215
- // Trick to make sure that initialSize connections are created
- if (dataSource.getInitialSize() > 0) {
- dataSource.getLogWriter();
- }
-
- // Return the configured DataSource instance
- return dataSource;
- }
-
- /**
- * <p>
- * Parse properties from the string. Format of the string must be [propertyName=property;]*
- * <p>
- *
- * @param propText
- * @return Properties
- * @throws Exception
- */
- private static Properties getProperties(final String propText) throws Exception {
- final Properties p = new Properties();
- if (propText != null) {
- p.load(new ByteArrayInputStream(propText.replace(';', '\n').getBytes(StandardCharsets.ISO_8859_1)));
- }
- return p;
- }
-
- /**
- * Parse list of property values from a delimited string
- *
- * @param value
- * delimited list of values
- * @param delimiter
- * character used to separate values in the list
- * @return String Collection of values
- */
- private static Collection<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());
- while (tokenizer.hasMoreTokens()) {
- tokens.add(tokenizer.nextToken());
- }
- return tokens;
- }
}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceMXBean.java b/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceMXBean.java
index 5a637da..06798a3 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceMXBean.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceMXBean.java
@@ -16,337 +16,23 @@
*/
package org.apache.tomcat.dbcp.dbcp2;
-import java.sql.SQLException;
-
/**
- * Defines the methods that will be made available via JMX.
+ * Interface to keep API compatibility. Methods listed here are not made available to
+ * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/management/agent.html">JMX</a>.
+ * <p>
+ * As of 2.9.0, this interface extends {@link DataSourceMXBean}.
+ * </p>
*
* @since 2.0
*/
-public interface BasicDataSourceMXBean {
-
- /**
- * See {@link BasicDataSource#getAbandonedUsageTracking()}
- *
- * @return {@link BasicDataSource#getAbandonedUsageTracking()}
- */
- boolean getAbandonedUsageTracking();
-
- /**
- * See {@link BasicDataSource#getDefaultAutoCommit()}
- *
- * @return {@link BasicDataSource#getDefaultAutoCommit()}
- */
- Boolean getDefaultAutoCommit();
-
- /**
- * See {@link BasicDataSource#getDefaultReadOnly()}
- *
- * @return {@link BasicDataSource#getDefaultReadOnly()}
- */
- Boolean getDefaultReadOnly();
-
- /**
- * See {@link BasicDataSource#getDefaultTransactionIsolation()}
- *
- * @return {@link BasicDataSource#getDefaultTransactionIsolation()}
- */
- int getDefaultTransactionIsolation();
-
- /**
- * See {@link BasicDataSource#getDefaultCatalog()}
- *
- * @return {@link BasicDataSource#getDefaultCatalog()}
- */
- String getDefaultCatalog();
-
- /**
- * See {@link BasicDataSource#getDefaultSchema()}
- *
- * @return {@link BasicDataSource#getDefaultSchema()}
- * @since 2.5.0
- */
- default String getDefaultSchema() {
- return null;
- }
-
- /**
- * See {@link BasicDataSource#getCacheState()}
- *
- * @return {@link BasicDataSource#getCacheState()}
- */
- boolean getCacheState();
-
- /**
- * See {@link BasicDataSource#getDriverClassName()}
- *
- * @return {@link BasicDataSource#getDriverClassName()}
- */
- String getDriverClassName();
-
- /**
- * See {@link BasicDataSource#getLifo()}
- *
- * @return {@link BasicDataSource#getLifo()}
- */
- boolean getLifo();
-
- /**
- * See {@link BasicDataSource#getMaxTotal()}
- *
- * @return {@link BasicDataSource#getMaxTotal()}
- */
- int getMaxTotal();
-
- /**
- * See {@link BasicDataSource#getMaxIdle()}
- *
- * @return {@link BasicDataSource#getMaxIdle()}
- */
- int getMaxIdle();
-
- /**
- * See {@link BasicDataSource#getMinIdle()}
- *
- * @return {@link BasicDataSource#getMinIdle()}
- */
- int getMinIdle();
-
- /**
- * See {@link BasicDataSource#getInitialSize()}
- *
- * @return {@link BasicDataSource#getInitialSize()}
- */
- int getInitialSize();
-
- /**
- * See {@link BasicDataSource#getMaxWaitMillis()}
- *
- * @return {@link BasicDataSource#getMaxWaitMillis()}
- */
- long getMaxWaitMillis();
-
- /**
- * See {@link BasicDataSource#isPoolPreparedStatements()}
- *
- * @return {@link BasicDataSource#isPoolPreparedStatements()}
- */
- boolean isPoolPreparedStatements();
-
- /**
- * See {@link BasicDataSource#isClearStatementPoolOnReturn()}
- *
- * @return {@link BasicDataSource#isClearStatementPoolOnReturn()}
- * @since 2.8.0
- */
- default boolean isClearStatementPoolOnReturn() {
- return false;
- }
-
- /**
- * See {@link BasicDataSource#getMaxOpenPreparedStatements()}
- *
- * @return {@link BasicDataSource#getMaxOpenPreparedStatements()}
- */
- int getMaxOpenPreparedStatements();
-
- /**
- * See {@link BasicDataSource#getTestOnCreate()}
- *
- * @return {@link BasicDataSource#getTestOnCreate()}
- */
- boolean getTestOnCreate();
-
- /**
- * See {@link BasicDataSource#getTestOnBorrow()}
- *
- * @return {@link BasicDataSource#getTestOnBorrow()}
- */
- boolean getTestOnBorrow();
-
- /**
- * See {@link BasicDataSource#getTimeBetweenEvictionRunsMillis()}
- *
- * @return {@link BasicDataSource#getTimeBetweenEvictionRunsMillis()}
- */
- long getTimeBetweenEvictionRunsMillis();
-
- /**
- * See {@link BasicDataSource#getNumTestsPerEvictionRun()}
- *
- * @return {@link BasicDataSource#getNumTestsPerEvictionRun()}
- */
- int getNumTestsPerEvictionRun();
-
- /**
- * See {@link BasicDataSource#getMinEvictableIdleTimeMillis()}
- *
- * @return {@link BasicDataSource#getMinEvictableIdleTimeMillis()}
- */
- long getMinEvictableIdleTimeMillis();
-
- /**
- * See {@link BasicDataSource#getSoftMinEvictableIdleTimeMillis()}
- *
- * @return {@link BasicDataSource#getSoftMinEvictableIdleTimeMillis()}
- */
- long getSoftMinEvictableIdleTimeMillis();
-
- /**
- * See {@link BasicDataSource#getTestWhileIdle()}
- *
- * @return {@link BasicDataSource#getTestWhileIdle()}
- */
- boolean getTestWhileIdle();
-
- /**
- * See {@link BasicDataSource#getNumActive()}
- *
- * @return {@link BasicDataSource#getNumActive()}
- */
- int getNumActive();
-
- /**
- * See {@link BasicDataSource#getNumIdle()}
- *
- * @return {@link BasicDataSource#getNumIdle()}
- */
- int getNumIdle();
+public interface BasicDataSourceMXBean extends DataSourceMXBean {
/**
* See {@link BasicDataSource#getPassword()}
*
* @return {@link BasicDataSource#getPassword()}
+ * @deprecated exposing password via JMX is an Information Exposure issue.
*/
+ @Deprecated
String getPassword();
-
- /**
- * See {@link BasicDataSource#getUrl()}
- *
- * @return {@link BasicDataSource#getUrl()}
- */
- String getUrl();
-
- /**
- * See {@link BasicDataSource#getUsername()}
- *
- * @return {@link BasicDataSource#getUsername()}
- */
- String getUsername();
-
- /**
- * See {@link BasicDataSource#getValidationQuery()}
- *
- * @return {@link BasicDataSource#getValidationQuery()}
- */
- String getValidationQuery();
-
- /**
- * See {@link BasicDataSource#getValidationQueryTimeout()}
- *
- * @return {@link BasicDataSource#getValidationQueryTimeout()}
- */
- int getValidationQueryTimeout();
-
- /**
- * See {@link BasicDataSource#getConnectionInitSqlsAsArray()}
- *
- * @return {@link BasicDataSource#getConnectionInitSqlsAsArray()}
- */
- String[] getConnectionInitSqlsAsArray();
-
- /**
- * See {@link BasicDataSource#isAccessToUnderlyingConnectionAllowed()}
- *
- * @return {@link BasicDataSource#isAccessToUnderlyingConnectionAllowed()}
- */
- boolean isAccessToUnderlyingConnectionAllowed();
-
- /**
- * See {@link BasicDataSource#getMaxConnLifetimeMillis()}
- *
- * @return {@link BasicDataSource#getMaxConnLifetimeMillis()}
- */
- long getMaxConnLifetimeMillis();
-
- /**
- * See {@link BasicDataSource#getLogExpiredConnections()}
- *
- * @return {@link BasicDataSource#getLogExpiredConnections()}
- * @since 2.1
- */
- boolean getLogExpiredConnections();
-
- /**
- * See {@link BasicDataSource#getRemoveAbandonedOnBorrow()}
- *
- * @return {@link BasicDataSource#getRemoveAbandonedOnBorrow()}
- */
- boolean getRemoveAbandonedOnBorrow();
-
- /**
- * See {@link BasicDataSource#getRemoveAbandonedOnMaintenance()}
- *
- * @return {@link BasicDataSource#getRemoveAbandonedOnMaintenance()}
- */
- boolean getRemoveAbandonedOnMaintenance();
-
- /**
- * See {@link BasicDataSource#getRemoveAbandonedTimeout()}
- *
- * @return {@link BasicDataSource#getRemoveAbandonedTimeout()}
- */
- int getRemoveAbandonedTimeout();
-
- /**
- * See {@link BasicDataSource#getLogAbandoned()}
- *
- * @return {@link BasicDataSource#getLogAbandoned()}
- */
- boolean getLogAbandoned();
-
- /**
- * See {@link BasicDataSource#isClosed()}
- *
- * @return {@link BasicDataSource#isClosed()}
- */
- boolean isClosed();
-
- /**
- * See {@link BasicDataSource#getFastFailValidation()}
- *
- * @return {@link BasicDataSource#getFastFailValidation()}
- * @since 2.1
- */
- boolean getFastFailValidation();
-
- /**
- * See {@link BasicDataSource#getDisconnectionSqlCodesAsArray()}
- *
- * @return {@link BasicDataSource#getDisconnectionSqlCodesAsArray()}
- * @since 2.1
- */
- String[] getDisconnectionSqlCodesAsArray();
-
- /**
- * See {@link BasicDataSource#start()}
- *
- * @throws SQLException if an error occurs initializing the datasource
- *
- * @since 2.8.0
- */
- default void start() throws SQLException {
- // do nothing
- }
-
- /**
- * See {@link BasicDataSource#restart()}
- *
- * @throws SQLException if an error occurs initializing the datasource
- *
- * @since 2.8.0
- */
- default void restart() throws SQLException {
- // do nothing by default?
- }
}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/ConnectionFactoryFactory.java b/java/org/apache/tomcat/dbcp/dbcp2/ConnectionFactoryFactory.java
index ad1e870..bd5c244 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/ConnectionFactoryFactory.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/ConnectionFactoryFactory.java
@@ -44,7 +44,7 @@ class ConnectionFactoryFactory {
// Set up the driver connection factory we will use
final String user = basicDataSource.getUsername();
if (user != null) {
- connectionProperties.put("user", user);
+ connectionProperties.put(Constants.KEY_USER, user);
} else {
basicDataSource.log("DBCP DataSource configured without a 'username'");
}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/Constants.java b/java/org/apache/tomcat/dbcp/dbcp2/Constants.java
index d9278cf..da83187 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/Constants.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/Constants.java
@@ -17,7 +17,7 @@
package org.apache.tomcat.dbcp.dbcp2;
/**
- * Constants for use with JMX.
+ * Constants.
*
* @since 2.0
*/
@@ -31,4 +31,18 @@ public class Constants {
public static final String JMX_STATEMENT_POOL_BASE_EXT = JMX_CONNECTION_BASE_EXT;
public static final String JMX_STATEMENT_POOL_PREFIX = ",statementpool=statements";
+
+ /**
+ * JDBC properties and URL key for passwords.
+ *
+ * @since 2.9.0
+ */
+ public static final String KEY_PASSWORD = "password";
+
+ /**
+ * JDBC properties and URL key for users.
+ *
+ * @since 2.9.0
+ */
+ public static final String KEY_USER = "user";
}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/DataSourceConnectionFactory.java b/java/org/apache/tomcat/dbcp/dbcp2/DataSourceConnectionFactory.java
index 5fdceab..3ab0a7a 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/DataSourceConnectionFactory.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/DataSourceConnectionFactory.java
@@ -106,6 +106,6 @@ public class DataSourceConnectionFactory implements ConnectionFactory {
* @since 2.6.0
*/
public char[] getUserPassword() {
- return userPassword;
+ return userPassword == null ? null : userPassword.clone();
}
}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceMXBean.java b/java/org/apache/tomcat/dbcp/dbcp2/DataSourceMXBean.java
similarity index 62%
copy from java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceMXBean.java
copy to java/org/apache/tomcat/dbcp/dbcp2/DataSourceMXBean.java
index 5a637da..7315c58 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceMXBean.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/DataSourceMXBean.java
@@ -19,334 +19,328 @@ package org.apache.tomcat.dbcp.dbcp2;
import java.sql.SQLException;
/**
- * Defines the methods that will be made available via JMX.
+ * Defines the methods that will be made available via
+ * <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/management/agent.html">JMX</a>.
*
- * @since 2.0
+ * @since 2.9.0
*/
-public interface BasicDataSourceMXBean {
+public interface DataSourceMXBean {
/**
- * See {@link BasicDataSource#getAbandonedUsageTracking()}
+ * See {@link BasicDataSource#getAbandonedUsageTracking()}.
*
* @return {@link BasicDataSource#getAbandonedUsageTracking()}
*/
boolean getAbandonedUsageTracking();
/**
- * See {@link BasicDataSource#getDefaultAutoCommit()}
+ * See {@link BasicDataSource#getCacheState()}.
*
- * @return {@link BasicDataSource#getDefaultAutoCommit()}
+ * @return {@link BasicDataSource#getCacheState()}.
*/
- Boolean getDefaultAutoCommit();
+ boolean getCacheState();
/**
- * See {@link BasicDataSource#getDefaultReadOnly()}
+ * See {@link BasicDataSource#getConnectionInitSqlsAsArray()}.
*
- * @return {@link BasicDataSource#getDefaultReadOnly()}
+ * @return {@link BasicDataSource#getConnectionInitSqlsAsArray()}.
*/
- Boolean getDefaultReadOnly();
+ String[] getConnectionInitSqlsAsArray();
/**
- * See {@link BasicDataSource#getDefaultTransactionIsolation()}
+ * See {@link BasicDataSource#getDefaultAutoCommit()}.
*
- * @return {@link BasicDataSource#getDefaultTransactionIsolation()}
+ * @return {@link BasicDataSource#getDefaultAutoCommit()}.
*/
- int getDefaultTransactionIsolation();
+ Boolean getDefaultAutoCommit();
/**
- * See {@link BasicDataSource#getDefaultCatalog()}
+ * See {@link BasicDataSource#getDefaultCatalog()}.
*
- * @return {@link BasicDataSource#getDefaultCatalog()}
+ * @return {@link BasicDataSource#getDefaultCatalog()}.
*/
String getDefaultCatalog();
/**
- * See {@link BasicDataSource#getDefaultSchema()}
- *
- * @return {@link BasicDataSource#getDefaultSchema()}
- * @since 2.5.0
- */
- default String getDefaultSchema() {
- return null;
- }
-
- /**
- * See {@link BasicDataSource#getCacheState()}
+ * See {@link BasicDataSource#getDefaultReadOnly()}.
*
- * @return {@link BasicDataSource#getCacheState()}
+ * @return {@link BasicDataSource#getDefaultReadOnly()}.
*/
- boolean getCacheState();
+ Boolean getDefaultReadOnly();
/**
- * See {@link BasicDataSource#getDriverClassName()}
+ * See {@link BasicDataSource#getDefaultSchema()}.
*
- * @return {@link BasicDataSource#getDriverClassName()}
+ * @return {@link BasicDataSource#getDefaultSchema()}.
+ * @since 2.5.0
*/
- String getDriverClassName();
+ default String getDefaultSchema() {
+ return null;
+ }
/**
- * See {@link BasicDataSource#getLifo()}
+ * See {@link BasicDataSource#getDefaultTransactionIsolation()}.
*
- * @return {@link BasicDataSource#getLifo()}
+ * @return {@link BasicDataSource#getDefaultTransactionIsolation()}.
*/
- boolean getLifo();
+ int getDefaultTransactionIsolation();
/**
- * See {@link BasicDataSource#getMaxTotal()}
+ * See {@link BasicDataSource#getDisconnectionSqlCodesAsArray()}.
*
- * @return {@link BasicDataSource#getMaxTotal()}
+ * @return {@link BasicDataSource#getDisconnectionSqlCodesAsArray()}.
+ * @since 2.1
*/
- int getMaxTotal();
+ String[] getDisconnectionSqlCodesAsArray();
/**
- * See {@link BasicDataSource#getMaxIdle()}
+ * See {@link BasicDataSource#getDriverClassName()}.
*
- * @return {@link BasicDataSource#getMaxIdle()}
+ * @return {@link BasicDataSource#getDriverClassName()}.
*/
- int getMaxIdle();
+ String getDriverClassName();
/**
- * See {@link BasicDataSource#getMinIdle()}
+ * See {@link BasicDataSource#getFastFailValidation()}.
*
- * @return {@link BasicDataSource#getMinIdle()}
+ * @return {@link BasicDataSource#getFastFailValidation()}.
+ * @since 2.1
*/
- int getMinIdle();
+ boolean getFastFailValidation();
/**
- * See {@link BasicDataSource#getInitialSize()}
+ * See {@link BasicDataSource#getInitialSize()}.
*
- * @return {@link BasicDataSource#getInitialSize()}
+ * @return {@link BasicDataSource#getInitialSize()}.
*/
int getInitialSize();
/**
- * See {@link BasicDataSource#getMaxWaitMillis()}
+ * See {@link BasicDataSource#getLifo()}.
*
- * @return {@link BasicDataSource#getMaxWaitMillis()}
+ * @return {@link BasicDataSource#getLifo()}.
*/
- long getMaxWaitMillis();
+ boolean getLifo();
/**
- * See {@link BasicDataSource#isPoolPreparedStatements()}
+ * See {@link BasicDataSource#getLogAbandoned()}.
*
- * @return {@link BasicDataSource#isPoolPreparedStatements()}
+ * @return {@link BasicDataSource#getLogAbandoned()}.
*/
- boolean isPoolPreparedStatements();
+ boolean getLogAbandoned();
/**
- * See {@link BasicDataSource#isClearStatementPoolOnReturn()}
+ * See {@link BasicDataSource#getLogExpiredConnections()}.
*
- * @return {@link BasicDataSource#isClearStatementPoolOnReturn()}
- * @since 2.8.0
+ * @return {@link BasicDataSource#getLogExpiredConnections()}.
+ * @since 2.1
*/
- default boolean isClearStatementPoolOnReturn() {
- return false;
- }
+ boolean getLogExpiredConnections();
/**
- * See {@link BasicDataSource#getMaxOpenPreparedStatements()}
+ * See {@link BasicDataSource#getMaxConnLifetimeMillis()}.
*
- * @return {@link BasicDataSource#getMaxOpenPreparedStatements()}
+ * @return {@link BasicDataSource#getMaxConnLifetimeMillis()}.
*/
- int getMaxOpenPreparedStatements();
+ long getMaxConnLifetimeMillis();
/**
- * See {@link BasicDataSource#getTestOnCreate()}
+ * See {@link BasicDataSource#getMaxIdle()}.
*
- * @return {@link BasicDataSource#getTestOnCreate()}
+ * @return {@link BasicDataSource#getMaxIdle()}.
*/
- boolean getTestOnCreate();
+ int getMaxIdle();
/**
- * See {@link BasicDataSource#getTestOnBorrow()}
+ * See {@link BasicDataSource#getMaxOpenPreparedStatements()}.
*
- * @return {@link BasicDataSource#getTestOnBorrow()}
+ * @return {@link BasicDataSource#getMaxOpenPreparedStatements()}.
*/
- boolean getTestOnBorrow();
+ int getMaxOpenPreparedStatements();
/**
- * See {@link BasicDataSource#getTimeBetweenEvictionRunsMillis()}
+ * See {@link BasicDataSource#getMaxTotal()}.
*
- * @return {@link BasicDataSource#getTimeBetweenEvictionRunsMillis()}
+ * @return {@link BasicDataSource#getMaxTotal()}.
*/
- long getTimeBetweenEvictionRunsMillis();
+ int getMaxTotal();
/**
- * See {@link BasicDataSource#getNumTestsPerEvictionRun()}
+ * See {@link BasicDataSource#getMaxWaitMillis()}.
*
- * @return {@link BasicDataSource#getNumTestsPerEvictionRun()}
+ * @return {@link BasicDataSource#getMaxWaitMillis()}.
*/
- int getNumTestsPerEvictionRun();
+ long getMaxWaitMillis();
/**
- * See {@link BasicDataSource#getMinEvictableIdleTimeMillis()}
+ * See {@link BasicDataSource#getMinEvictableIdleTimeMillis()}.
*
- * @return {@link BasicDataSource#getMinEvictableIdleTimeMillis()}
+ * @return {@link BasicDataSource#getMinEvictableIdleTimeMillis()}.
*/
long getMinEvictableIdleTimeMillis();
/**
- * See {@link BasicDataSource#getSoftMinEvictableIdleTimeMillis()}
+ * See {@link BasicDataSource#getMinIdle()}.
*
- * @return {@link BasicDataSource#getSoftMinEvictableIdleTimeMillis()}
+ * @return {@link BasicDataSource#getMinIdle()}.
*/
- long getSoftMinEvictableIdleTimeMillis();
+ int getMinIdle();
/**
- * See {@link BasicDataSource#getTestWhileIdle()}
+ * See {@link BasicDataSource#getNumActive()}.
*
- * @return {@link BasicDataSource#getTestWhileIdle()}
+ * @return {@link BasicDataSource#getNumActive()}.
*/
- boolean getTestWhileIdle();
+ int getNumActive();
/**
- * See {@link BasicDataSource#getNumActive()}
+ * See {@link BasicDataSource#getNumIdle()}.
*
- * @return {@link BasicDataSource#getNumActive()}
+ * @return {@link BasicDataSource#getNumIdle()}.
*/
- int getNumActive();
+ int getNumIdle();
/**
- * See {@link BasicDataSource#getNumIdle()}
+ * See {@link BasicDataSource#getNumTestsPerEvictionRun()}.
*
- * @return {@link BasicDataSource#getNumIdle()}
+ * @return {@link BasicDataSource#getNumTestsPerEvictionRun()}.
*/
- int getNumIdle();
+ int getNumTestsPerEvictionRun();
/**
- * See {@link BasicDataSource#getPassword()}
+ * See {@link BasicDataSource#getRemoveAbandonedOnBorrow()}.
*
- * @return {@link BasicDataSource#getPassword()}
+ * @return {@link BasicDataSource#getRemoveAbandonedOnBorrow()}.
*/
- String getPassword();
+ boolean getRemoveAbandonedOnBorrow();
/**
- * See {@link BasicDataSource#getUrl()}
+ * See {@link BasicDataSource#getRemoveAbandonedOnMaintenance()}.
*
- * @return {@link BasicDataSource#getUrl()}
+ * @return {@link BasicDataSource#getRemoveAbandonedOnMaintenance()}.
*/
- String getUrl();
+ boolean getRemoveAbandonedOnMaintenance();
/**
- * See {@link BasicDataSource#getUsername()}
+ * See {@link BasicDataSource#getRemoveAbandonedTimeout()}.
*
- * @return {@link BasicDataSource#getUsername()}
+ * @return {@link BasicDataSource#getRemoveAbandonedTimeout()}.
*/
- String getUsername();
+ int getRemoveAbandonedTimeout();
/**
- * See {@link BasicDataSource#getValidationQuery()}
+ * See {@link BasicDataSource#getSoftMinEvictableIdleTimeMillis()}.
*
- * @return {@link BasicDataSource#getValidationQuery()}
+ * @return {@link BasicDataSource#getSoftMinEvictableIdleTimeMillis()}.
*/
- String getValidationQuery();
+ long getSoftMinEvictableIdleTimeMillis();
/**
- * See {@link BasicDataSource#getValidationQueryTimeout()}
+ * See {@link BasicDataSource#getTestOnBorrow()}.
*
- * @return {@link BasicDataSource#getValidationQueryTimeout()}
+ * @return {@link BasicDataSource#getTestOnBorrow()}.
*/
- int getValidationQueryTimeout();
+ boolean getTestOnBorrow();
/**
- * See {@link BasicDataSource#getConnectionInitSqlsAsArray()}
+ * See {@link BasicDataSource#getTestOnCreate()}.
*
- * @return {@link BasicDataSource#getConnectionInitSqlsAsArray()}
+ * @return {@link BasicDataSource#getTestOnCreate()}.
*/
- String[] getConnectionInitSqlsAsArray();
+ boolean getTestOnCreate();
/**
- * See {@link BasicDataSource#isAccessToUnderlyingConnectionAllowed()}
+ * See {@link BasicDataSource#getTestWhileIdle()}.
*
- * @return {@link BasicDataSource#isAccessToUnderlyingConnectionAllowed()}
+ * @return {@link BasicDataSource#getTestWhileIdle()}.
*/
- boolean isAccessToUnderlyingConnectionAllowed();
+ boolean getTestWhileIdle();
/**
- * See {@link BasicDataSource#getMaxConnLifetimeMillis()}
+ * See {@link BasicDataSource#getTimeBetweenEvictionRunsMillis()}.
*
- * @return {@link BasicDataSource#getMaxConnLifetimeMillis()}
+ * @return {@link BasicDataSource#getTimeBetweenEvictionRunsMillis()}.
*/
- long getMaxConnLifetimeMillis();
+ long getTimeBetweenEvictionRunsMillis();
/**
- * See {@link BasicDataSource#getLogExpiredConnections()}
+ * See {@link BasicDataSource#getUrl()}.
*
- * @return {@link BasicDataSource#getLogExpiredConnections()}
- * @since 2.1
+ * @return {@link BasicDataSource#getUrl()}.
*/
- boolean getLogExpiredConnections();
+ String getUrl();
/**
- * See {@link BasicDataSource#getRemoveAbandonedOnBorrow()}
+ * See {@link BasicDataSource#getUsername()}.
*
- * @return {@link BasicDataSource#getRemoveAbandonedOnBorrow()}
+ * @return {@link BasicDataSource#getUsername()}.
*/
- boolean getRemoveAbandonedOnBorrow();
+ String getUsername();
/**
- * See {@link BasicDataSource#getRemoveAbandonedOnMaintenance()}
+ * See {@link BasicDataSource#getValidationQuery()}.
*
- * @return {@link BasicDataSource#getRemoveAbandonedOnMaintenance()}
+ * @return {@link BasicDataSource#getValidationQuery()}.
*/
- boolean getRemoveAbandonedOnMaintenance();
+ String getValidationQuery();
/**
- * See {@link BasicDataSource#getRemoveAbandonedTimeout()}
+ * See {@link BasicDataSource#getValidationQueryTimeout()}.
*
- * @return {@link BasicDataSource#getRemoveAbandonedTimeout()}
+ * @return {@link BasicDataSource#getValidationQueryTimeout()}.
*/
- int getRemoveAbandonedTimeout();
+ int getValidationQueryTimeout();
/**
- * See {@link BasicDataSource#getLogAbandoned()}
+ * See {@link BasicDataSource#isAccessToUnderlyingConnectionAllowed()}.
*
- * @return {@link BasicDataSource#getLogAbandoned()}
+ * @return {@link BasicDataSource#isAccessToUnderlyingConnectionAllowed()}.
*/
- boolean getLogAbandoned();
+ boolean isAccessToUnderlyingConnectionAllowed();
/**
- * See {@link BasicDataSource#isClosed()}
+ * See {@link BasicDataSource#isClearStatementPoolOnReturn()}.
*
- * @return {@link BasicDataSource#isClosed()}
+ * @return {@link BasicDataSource#isClearStatementPoolOnReturn()}.
+ * @since 2.8.0
*/
- boolean isClosed();
+ default boolean isClearStatementPoolOnReturn() {
+ return false;
+ }
/**
- * See {@link BasicDataSource#getFastFailValidation()}
+ * See {@link BasicDataSource#isClosed()}.
*
- * @return {@link BasicDataSource#getFastFailValidation()}
- * @since 2.1
+ * @return {@link BasicDataSource#isClosed()}.
*/
- boolean getFastFailValidation();
+ boolean isClosed();
/**
- * See {@link BasicDataSource#getDisconnectionSqlCodesAsArray()}
+ * See {@link BasicDataSource#isPoolPreparedStatements()}.
*
- * @return {@link BasicDataSource#getDisconnectionSqlCodesAsArray()}
- * @since 2.1
+ * @return {@link BasicDataSource#isPoolPreparedStatements()}.
*/
- String[] getDisconnectionSqlCodesAsArray();
+ boolean isPoolPreparedStatements();
/**
- * See {@link BasicDataSource#start()}
+ * See {@link BasicDataSource#restart()}
*
- * @throws SQLException if an error occurs initializing the datasource
+ * @throws SQLException if an error occurs initializing the data source.
*
* @since 2.8.0
*/
- default void start() throws SQLException {
- // do nothing
+ default void restart() throws SQLException {
+ // do nothing by default?
}
/**
- * See {@link BasicDataSource#restart()}
+ * See {@link BasicDataSource#start()}
*
- * @throws SQLException if an error occurs initializing the datasource
+ * @throws SQLException if an error occurs initializing the data source.
*
* @since 2.8.0
*/
- default void restart() throws SQLException {
- // do nothing by default?
+ default void start() throws SQLException {
+ // do nothing
}
}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingConnection.java b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingConnection.java
index c036329..887fb66 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingConnection.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingConnection.java
@@ -33,6 +33,8 @@ import java.sql.SQLXML;
import java.sql.Savepoint;
import java.sql.Statement;
import java.sql.Struct;
+import java.time.Duration;
+import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -68,122 +70,75 @@ public class DelegatingConnection<C extends Connection> extends AbandonedTrace i
private volatile boolean closed;
private boolean cacheState = true;
- private Boolean autoCommitCached;
- private Boolean readOnlyCached;
- private Integer defaultQueryTimeoutSeconds;
+ private Boolean cachedAutoCommit;
+ private Boolean cachedReadOnly;
+ private String cachedCatalog;
+ private String cachedSchema;
+ private Duration defaultQueryTimeoutDuration;
/**
* Creates a wrapper for the Connection which traces this Connection in the AbandonedObjectPool.
*
- * @param c
- * the {@link Connection} to delegate all calls to.
+ * @param connection the {@link Connection} to delegate all calls to.
*/
- public DelegatingConnection(final C c) {
- connection = c;
+ public DelegatingConnection(final C connection) {
+ this.connection = connection;
}
- /**
- * Returns a string representation of the metadata associated with the innermost delegate connection.
- */
@Override
- public synchronized String toString() {
- String str = null;
-
- final Connection conn = this.getInnermostDelegateInternal();
- if (conn != null) {
- try {
- if (conn.isClosed()) {
- str = "connection is closed";
- } else {
- final StringBuilder sb = new StringBuilder();
- sb.append(hashCode());
- final DatabaseMetaData meta = conn.getMetaData();
- if (meta != null) {
- sb.append(", URL=");
- sb.append(meta.getURL());
- sb.append(", ");
- sb.append(meta.getDriverName());
- str = sb.toString();
- }
- }
- } catch (final SQLException ex) {
- // Ignore
- }
+ public void abort(final Executor executor) throws SQLException {
+ try {
+ Jdbc41Bridge.abort(connection, executor);
+ } catch (final SQLException e) {
+ handleException(e);
}
- return str != null ? str : super.toString();
- }
-
- /**
- * Returns my underlying {@link Connection}.
- *
- * @return my underlying {@link Connection}.
- */
- public C getDelegate() {
- return getDelegateInternal();
- }
-
- protected final C getDelegateInternal() {
- return connection;
}
- /**
- * Compares innermost delegate to the given connection.
- *
- * @param c
- * connection to compare innermost delegate with
- * @return true if innermost delegate equals <code>c</code>
- */
- public boolean innermostDelegateEquals(final Connection c) {
- final Connection innerCon = getInnermostDelegateInternal();
- if (innerCon == null) {
- return c == null;
+ protected void activate() {
+ closed = false;
+ setLastUsed();
+ if (connection instanceof DelegatingConnection) {
+ ((DelegatingConnection<?>) connection).activate();
}
- return innerCon.equals(c);
}
- /**
- * If my underlying {@link Connection} is not a {@code DelegatingConnection}, returns it, otherwise recursively
- * invokes this method on my delegate.
- * <p>
- * Hence this method will return the first delegate that is not a {@code DelegatingConnection}, or {@code null} when
- * no non-{@code DelegatingConnection} delegate can be found by traversing this chain.
- * </p>
- * <p>
- * This method is useful when you may have nested {@code DelegatingConnection}s, and you want to make sure to obtain
- * a "genuine" {@link Connection}.
- * </p>
- *
- * @return innermost delegate.
- */
- public Connection getInnermostDelegate() {
- return getInnermostDelegateInternal();
+ protected void checkOpen() throws SQLException {
+ if (closed) {
+ if (null != connection) {
+ String label = "";
+ try {
+ label = connection.toString();
+ } catch (final Exception ex) {
+ // ignore, leave label empty
+ }
+ throw new SQLException("Connection " + label + " is closed.");
+ }
+ throw new SQLException("Connection is null.");
+ }
}
/**
- * Although this method is public, it is part of the internal API and should not be used by clients. The signature
- * of this method may change at any time including in ways that break backwards compatibility.
- *
- * @return innermost delegate.
+ * Can be used to clear cached state when it is known that the underlying connection may have been accessed
+ * directly.
*/
- public final Connection getInnermostDelegateInternal() {
- Connection conn = connection;
- while (conn instanceof DelegatingConnection) {
- conn = ((DelegatingConnection<?>) conn).getDelegateInternal();
- if (this == conn) {
- return null;
- }
+ public void clearCachedState() {
+ cachedAutoCommit = null;
+ cachedReadOnly = null;
+ cachedSchema = null;
+ cachedCatalog = null;
+ if (connection instanceof DelegatingConnection) {
+ ((DelegatingConnection<?>) connection).clearCachedState();
}
- return conn;
}
- /**
- * Sets my delegate.
- *
- * @param connection
- * my delegate.
- */
- public void setDelegate(final C connection) {
- this.connection = connection;
+ @Override
+ public void clearWarnings() throws SQLException {
+ checkOpen();
+ try {
+ connection.clearWarnings();
+ } catch (final SQLException e) {
+ handleException(e);
+ }
}
/**
@@ -202,14 +157,6 @@ public class DelegatingConnection<C extends Connection> extends AbandonedTrace i
}
}
- protected boolean isClosedInternal() {
- return closed;
- }
-
- protected void setClosedInternal(final boolean closed) {
- this.closed = closed;
- }
-
protected final void closeInternal() throws SQLException {
try {
passivate();
@@ -238,35 +185,43 @@ public class DelegatingConnection<C extends Connection> extends AbandonedTrace i
}
}
- protected void handleException(final SQLException e) throws SQLException {
- throw e;
+ @Override
+ public void commit() throws SQLException {
+ checkOpen();
+ try {
+ connection.commit();
+ } catch (final SQLException e) {
+ handleException(e);
+ }
}
- /**
- * Handles the given {@code SQLException}.
- *
- * @param <T> The throwable type.
- * @param e The SQLException
- * @return the given {@code SQLException}
- * @since 2.7.0
- */
- protected <T extends Throwable> T handleExceptionNoThrow(final T e) {
- return e;
+ @Override
+ public Array createArrayOf(final String typeName, final Object[] elements) throws SQLException {
+ checkOpen();
+ try {
+ return connection.createArrayOf(typeName, elements);
+ } catch (final SQLException e) {
+ handleException(e);
+ return null;
+ }
}
- private void initializeStatement(final DelegatingStatement ds) throws SQLException {
- if (defaultQueryTimeoutSeconds != null && defaultQueryTimeoutSeconds.intValue() != ds.getQueryTimeout()) {
- ds.setQueryTimeout(defaultQueryTimeoutSeconds.intValue());
+ @Override
+ public Blob createBlob() throws SQLException {
+ checkOpen();
+ try {
+ return connection.createBlob();
+ } catch (final SQLException e) {
+ handleException(e);
+ return null;
}
}
@Override
- public Statement createStatement() throws SQLException {
+ public Clob createClob() throws SQLException {
checkOpen();
try {
- final DelegatingStatement ds = new DelegatingStatement(this, connection.createStatement());
- initializeStatement(ds);
- return ds;
+ return connection.createClob();
} catch (final SQLException e) {
handleException(e);
return null;
@@ -274,13 +229,10 @@ public class DelegatingConnection<C extends Connection> extends AbandonedTrace i
}
@Override
- public Statement createStatement(final int resultSetType, final int resultSetConcurrency) throws SQLException {
+ public NClob createNClob() throws SQLException {
checkOpen();
try {
- final DelegatingStatement ds = new DelegatingStatement(this,
- connection.createStatement(resultSetType, resultSetConcurrency));
- initializeStatement(ds);
- return ds;
+ return connection.createNClob();
} catch (final SQLException e) {
handleException(e);
return null;
@@ -288,13 +240,10 @@ public class DelegatingConnection<C extends Connection> extends AbandonedTrace i
}
@Override
- public PreparedStatement prepareStatement(final String sql) throws SQLException {
+ public SQLXML createSQLXML() throws SQLException {
checkOpen();
try {
- final DelegatingPreparedStatement dps = new DelegatingPreparedStatement(this,
- connection.prepareStatement(sql));
- initializeStatement(dps);
- return dps;
+ return connection.createSQLXML();
} catch (final SQLException e) {
handleException(e);
return null;
@@ -302,14 +251,10 @@ public class DelegatingConnection<C extends Connection> extends AbandonedTrace i
}
@Override
- public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency)
- throws SQLException {
+ public Statement createStatement() throws SQLException {
checkOpen();
try {
- final DelegatingPreparedStatement dps = new DelegatingPreparedStatement(this,
- connection.prepareStatement(sql, resultSetType, resultSetConcurrency));
- initializeStatement(dps);
- return dps;
+ return init(new DelegatingStatement(this, connection.createStatement()));
} catch (final SQLException e) {
handleException(e);
return null;
@@ -317,12 +262,10 @@ public class DelegatingConnection<C extends Connection> extends AbandonedTrace i
}
@Override
- public CallableStatement prepareCall(final String sql) throws SQLException {
+ public Statement createStatement(final int resultSetType, final int resultSetConcurrency) throws SQLException {
checkOpen();
try {
- final DelegatingCallableStatement dcs = new DelegatingCallableStatement(this, connection.prepareCall(sql));
- initializeStatement(dcs);
- return dcs;
+ return init(new DelegatingStatement(this, connection.createStatement(resultSetType, resultSetConcurrency)));
} catch (final SQLException e) {
handleException(e);
return null;
@@ -330,14 +273,12 @@ public class DelegatingConnection<C extends Connection> extends AbandonedTrace i
}
@Override
- public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency)
- throws SQLException {
+ public Statement createStatement(final int resultSetType, final int resultSetConcurrency,
+ final int resultSetHoldability) throws SQLException {
checkOpen();
try {
- final DelegatingCallableStatement dcs = new DelegatingCallableStatement(this,
- connection.prepareCall(sql, resultSetType, resultSetConcurrency));
- initializeStatement(dcs);
- return dcs;
+ return init(new DelegatingStatement(this,
+ connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability)));
} catch (final SQLException e) {
handleException(e);
return null;
@@ -345,22 +286,28 @@ public class DelegatingConnection<C extends Connection> extends AbandonedTrace i
}
@Override
- public void clearWarnings() throws SQLException {
+ public Struct createStruct(final String typeName, final Object[] attributes) throws SQLException {
checkOpen();
try {
- connection.clearWarnings();
+ return connection.createStruct(typeName, attributes);
} catch (final SQLException e) {
handleException(e);
+ return null;
}
}
@Override
- public void commit() throws SQLException {
+ public boolean getAutoCommit() throws SQLException {
checkOpen();
+ if (cacheState && cachedAutoCommit != null) {
+ return cachedAutoCommit.booleanValue();
+ }
try {
- connection.commit();
+ cachedAutoCommit = Boolean.valueOf(connection.getAutoCommit());
+ return cachedAutoCommit.booleanValue();
} catch (final SQLException e) {
handleException(e);
+ return false;
}
}
@@ -374,25 +321,25 @@ public class DelegatingConnection<C extends Connection> extends AbandonedTrace i
}
@Override
- public boolean getAutoCommit() throws SQLException {
+ public String getCatalog() throws SQLException {
checkOpen();
- if (cacheState && autoCommitCached != null) {
- return autoCommitCached.booleanValue();
+ if (cacheState && cachedCatalog != null) {
+ return cachedCatalog;
}
try {
- autoCommitCached = Boolean.valueOf(connection.getAutoCommit());
- return autoCommitCached.booleanValue();
+ cachedCatalog = connection.getCatalog();
+ return cachedCatalog;
} catch (final SQLException e) {
handleException(e);
- return false;
+ return null;
}
}
@Override
- public String getCatalog() throws SQLException {
+ public Properties getClientInfo() throws SQLException {
checkOpen();
try {
- return connection.getCatalog();
+ return connection.getClientInfo();
} catch (final SQLException e) {
handleException(e);
return null;
@@ -400,32 +347,108 @@ public class DelegatingConnection<C extends Connection> extends AbandonedTrace i
}
@Override
- public DatabaseMetaData getMetaData() throws SQLException {
+ public String getClientInfo(final String name) throws SQLException {
checkOpen();
try {
- return new DelegatingDatabaseMetaData(this, connection.getMetaData());
+ return connection.getClientInfo(name);
} catch (final SQLException e) {
handleException(e);
return null;
}
}
+ /**
+ * Gets the default query timeout that will be used for {@link Statement}s created from this connection.
+ * <code>null</code> means that the driver default will be used.
+ *
+ * @return query timeout limit in seconds; zero means there is no limit.
+ * @deprecated Use {@link #getDefaultQueryTimeoutDuration()}.
+ */
+ @Deprecated
+ public Integer getDefaultQueryTimeout() {
+ return defaultQueryTimeoutDuration == null ? null : Integer.valueOf((int) defaultQueryTimeoutDuration.getSeconds());
+ }
+
+ /**
+ * Gets the default query timeout that will be used for {@link Statement}s created from this connection.
+ * <code>null</code> means that the driver default will be used.
+ *
+ * @return query timeout limit; zero means there is no limit.
+ * @since 2.10.0
+ */
+ public Duration getDefaultQueryTimeoutDuration() {
+ return defaultQueryTimeoutDuration;
+ }
+
+ /**
+ * Returns my underlying {@link Connection}.
+ *
+ * @return my underlying {@link Connection}.
+ */
+ public C getDelegate() {
+ return getDelegateInternal();
+ }
+
+ /**
+ * Gets the delegate connection.
+ *
+ * @return the delegate connection.
+ */
+ protected final C getDelegateInternal() {
+ return connection;
+ }
+
@Override
- public int getTransactionIsolation() throws SQLException {
+ public int getHoldability() throws SQLException {
checkOpen();
try {
- return connection.getTransactionIsolation();
+ return connection.getHoldability();
} catch (final SQLException e) {
handleException(e);
- return -1;
+ return 0;
}
}
+ /**
+ * If my underlying {@link Connection} is not a {@code DelegatingConnection}, returns it, otherwise recursively
+ * invokes this method on my delegate.
+ * <p>
+ * Hence this method will return the first delegate that is not a {@code DelegatingConnection}, or {@code null} when
+ * no non-{@code DelegatingConnection} delegate can be found by traversing this chain.
+ * </p>
+ * <p>
+ * This method is useful when you may have nested {@code DelegatingConnection}s, and you want to make sure to obtain
+ * a "genuine" {@link Connection}.
+ * </p>
+ *
+ * @return innermost delegate.
+ */
+ public Connection getInnermostDelegate() {
+ return getInnermostDelegateInternal();
+ }
+
+ /**
+ * Although this method is public, it is part of the internal API and should not be used by clients. The signature
+ * of this method may change at any time including in ways that break backwards compatibility.
+ *
+ * @return innermost delegate.
+ */
+ public final Connection getInnermostDelegateInternal() {
+ Connection conn = connection;
+ while (conn instanceof DelegatingConnection) {
+ conn = ((DelegatingConnection<?>) conn).getDelegateInternal();
+ if (this == conn) {
+ return null;
+ }
+ }
+ return conn;
+ }
+
@Override
- public Map<String, Class<?>> getTypeMap() throws SQLException {
+ public DatabaseMetaData getMetaData() throws SQLException {
checkOpen();
try {
- return connection.getTypeMap();
+ return new DelegatingDatabaseMetaData(this, connection.getMetaData());
} catch (final SQLException e) {
handleException(e);
return null;
@@ -433,36 +456,47 @@ public class DelegatingConnection<C extends Connection> extends AbandonedTrace i
}
@Override
- public SQLWarning getWarnings() throws SQLException {
+ public int getNetworkTimeout() throws SQLException {
checkOpen();
try {
- return connection.getWarnings();
+ return Jdbc41Bridge.getNetworkTimeout(connection);
} catch (final SQLException e) {
handleException(e);
- return null;
+ return 0;
}
}
@Override
- public boolean isReadOnly() throws SQLException {
+ public String getSchema() throws SQLException {
checkOpen();
- if (cacheState && readOnlyCached != null) {
- return readOnlyCached.booleanValue();
+ if (cacheState && cachedSchema != null) {
+ return cachedSchema;
}
try {
- readOnlyCached = Boolean.valueOf(connection.isReadOnly());
- return readOnlyCached.booleanValue();
+ cachedSchema = Jdbc41Bridge.getSchema(connection);
+ return cachedSchema;
} catch (final SQLException e) {
handleException(e);
- return false;
+ return null;
}
}
@Override
- public String nativeSQL(final String sql) throws SQLException {
+ public int getTransactionIsolation() throws SQLException {
checkOpen();
try {
- return connection.nativeSQL(sql);
+ return connection.getTransactionIsolation();
+ } catch (final SQLException e) {
+ handleException(e);
+ return -1;
+ }
+ }
+
+ @Override
+ public Map<String, Class<?>> getTypeMap() throws SQLException {
+ checkOpen();
+ try {
+ return connection.getTypeMap();
} catch (final SQLException e) {
handleException(e);
return null;
@@ -470,141 +504,141 @@ public class DelegatingConnection<C extends Connection> extends AbandonedTrace i
}
@Override
- public void rollback() throws SQLException {
+ public SQLWarning getWarnings() throws SQLException {
checkOpen();
try {
- connection.rollback();
+ return connection.getWarnings();
} catch (final SQLException e) {
handleException(e);
+ return null;
}
}
/**
- * Gets the default query timeout that will be used for {@link Statement}s created from this connection.
- * <code>null</code> means that the driver default will be used.
+ * Handles the given exception by throwing it.
*
- * @return query timeout limit in seconds; zero means there is no limit.
+ * @param e the exception to throw.
+ * @throws SQLException the exception to throw.
*/
- public Integer getDefaultQueryTimeout() {
- return defaultQueryTimeoutSeconds;
+ protected void handleException(final SQLException e) throws SQLException {
+ throw e;
}
/**
- * Sets the default query timeout that will be used for {@link Statement}s created from this connection.
- * <code>null</code> means that the driver default will be used.
+ * Handles the given {@code SQLException}.
*
- * @param defaultQueryTimeoutSeconds
- * the new query timeout limit in seconds; zero means there is no limit
+ * @param <T> The throwable type.
+ * @param e The SQLException
+ * @return the given {@code SQLException}
+ * @since 2.7.0
*/
- public void setDefaultQueryTimeout(final Integer defaultQueryTimeoutSeconds) {
- this.defaultQueryTimeoutSeconds = defaultQueryTimeoutSeconds;
+ protected <T extends Throwable> T handleExceptionNoThrow(final T e) {
+ return e;
}
/**
- * Sets the state caching flag.
+ * Initializes the given statement with this connection's settings.
*
- * @param cacheState
- * The new value for the state caching flag
+ * @param <T> The DelegatingStatement type.
+ * @param delegatingStatement The DelegatingStatement to initialize.
+ * @return The given DelegatingStatement.
+ * @throws SQLException if a database access error occurs, this method is called on a closed Statement.
*/
- public void setCacheState(final boolean cacheState) {
- this.cacheState = cacheState;
+ private <T extends DelegatingStatement> T init(final T delegatingStatement) throws SQLException {
+ if (defaultQueryTimeoutDuration != null && defaultQueryTimeoutDuration.getSeconds() != delegatingStatement.getQueryTimeout()) {
+ delegatingStatement.setQueryTimeout((int) defaultQueryTimeoutDuration.getSeconds());
+ }
+ return delegatingStatement;
}
/**
- * Can be used to clear cached state when it is known that the underlying connection may have been accessed
- * directly.
+ * Compares innermost delegate to the given connection.
+ *
+ * @param c
+ * connection to compare innermost delegate with
+ * @return true if innermost delegate equals <code>c</code>
*/
- public void clearCachedState() {
- autoCommitCached = null;
- readOnlyCached = null;
- if (connection instanceof DelegatingConnection) {
- ((DelegatingConnection<?>) connection).clearCachedState();
+ public boolean innermostDelegateEquals(final Connection c) {
+ final Connection innerCon = getInnermostDelegateInternal();
+ if (innerCon == null) {
+ return c == null;
}
+ return innerCon.equals(c);
}
@Override
- public void setAutoCommit(final boolean autoCommit) throws SQLException {
- checkOpen();
- try {
- connection.setAutoCommit(autoCommit);
- if (cacheState) {
- autoCommitCached = Boolean.valueOf(connection.getAutoCommit());
- }
- } catch (final SQLException e) {
- autoCommitCached = null;
- handleException(e);
- }
+ public boolean isClosed() throws SQLException {
+ return closed || connection == null || connection.isClosed();
}
- @Override
- public void setCatalog(final String catalog) throws SQLException {
- checkOpen();
- try {
- connection.setCatalog(catalog);
- } catch (final SQLException e) {
- handleException(e);
- }
+ protected boolean isClosedInternal() {
+ return closed;
}
@Override
- public void setReadOnly(final boolean readOnly) throws SQLException {
+ public boolean isReadOnly() throws SQLException {
checkOpen();
- try {
- connection.setReadOnly(readOnly);
- if (cacheState) {
- readOnlyCached = Boolean.valueOf(connection.isReadOnly());
- }
- } catch (final SQLException e) {
- readOnlyCached = null;
- handleException(e);
+ if (cacheState && cachedReadOnly != null) {
+ return cachedReadOnly.booleanValue();
}
- }
-
- @Override
- public void setTransactionIsolation(final int level) throws SQLException {
- checkOpen();
try {
- connection.setTransactionIsolation(level);
+ cachedReadOnly = Boolean.valueOf(connection.isReadOnly());
+ return cachedReadOnly.booleanValue();
} catch (final SQLException e) {
handleException(e);
+ return false;
}
}
- @Override
- public void setTypeMap(final Map<String, Class<?>> map) throws SQLException {
- checkOpen();
+ /**
+ * Tests if the connection has not been closed and is still valid.
+ *
+ * @param timeout The duration to wait for the database operation used to validate the connection to complete.
+ * @return See {@link Connection#isValid(int)}.
+ * @throws SQLException See {@link Connection#isValid(int)}.
+ * @see Connection#isValid(int)
+ * @since 2.10.0
+ */
+ public boolean isValid(final Duration timeout) throws SQLException {
+ if (isClosed()) {
+ return false;
+ }
try {
- connection.setTypeMap(map);
+ return connection.isValid((int) timeout.getSeconds());
} catch (final SQLException e) {
handleException(e);
+ return false;
}
}
+ /**
+ * @deprecated Use {@link #isValid(Duration)}.
+ */
@Override
- public boolean isClosed() throws SQLException {
- return closed || connection == null || connection.isClosed();
+ @Deprecated
+ public boolean isValid(final int timeoutSeconds) throws SQLException {
+ return isValid(Duration.ofSeconds(timeoutSeconds));
}
- protected void checkOpen() throws SQLException {
- if (closed) {
- if (null != connection) {
- String label = "";
- try {
- label = connection.toString();
- } catch (final Exception ex) {
- // ignore, leave label empty
- }
- throw new SQLException("Connection " + label + " is closed.");
- }
- throw new SQLException("Connection is null.");
+ @Override
+ public boolean isWrapperFor(final Class<?> iface) throws SQLException {
+ if (iface.isAssignableFrom(getClass())) {
+ return true;
+ }
+ if (iface.isAssignableFrom(connection.getClass())) {
+ return true;
}
+ return connection.isWrapperFor(iface);
}
- protected void activate() {
- closed = false;
- setLastUsed();
- if (connection instanceof DelegatingConnection) {
- ((DelegatingConnection<?>) connection).activate();
+ @Override
+ public String nativeSQL(final String sql) throws SQLException {
+ checkOpen();
+ try {
+ return connection.nativeSQL(sql);
+ } catch (final SQLException e) {
+ handleException(e);
+ return null;
}
}
@@ -637,35 +671,14 @@ public class DelegatingConnection<C extends Connection> extends AbandonedTrace i
throw new SQLExceptionList(thrownList);
}
}
- setLastUsed(0);
- }
-
- @Override
- public int getHoldability() throws SQLException {
- checkOpen();
- try {
- return connection.getHoldability();
- } catch (final SQLException e) {
- handleException(e);
- return 0;
- }
- }
-
- @Override
- public void setHoldability(final int holdability) throws SQLException {
- checkOpen();
- try {
- connection.setHoldability(holdability);
- } catch (final SQLException e) {
- handleException(e);
- }
+ setLastUsed(Instant.EPOCH);
}
@Override
- public Savepoint setSavepoint() throws SQLException {
+ public CallableStatement prepareCall(final String sql) throws SQLException {
checkOpen();
try {
- return connection.setSavepoint();
+ return init(new DelegatingCallableStatement(this, connection.prepareCall(sql)));
} catch (final SQLException e) {
handleException(e);
return null;
@@ -673,10 +686,12 @@ public class DelegatingConnection<C extends Connection> extends AbandonedTrace i
}
@Override
- public Savepoint setSavepoint(final String name) throws SQLException {
+ public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency)
+ throws SQLException {
checkOpen();
try {
- return connection.setSavepoint(name);
+ return init(new DelegatingCallableStatement(this,
+ connection.prepareCall(sql, resultSetType, resultSetConcurrency)));
} catch (final SQLException e) {
handleException(e);
return null;
@@ -684,34 +699,23 @@ public class DelegatingConnection<C extends Connection> extends AbandonedTrace i
}
@Override
- public void rollback(final Savepoint savepoint) throws SQLException {
- checkOpen();
- try {
- connection.rollback(savepoint);
- } catch (final SQLException e) {
- handleException(e);
- }
- }
-
- @Override
- public void releaseSavepoint(final Savepoint savepoint) throws SQLException {
+ public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency,
+ final int resultSetHoldability) throws SQLException {
checkOpen();
try {
- connection.releaseSavepoint(savepoint);
+ return init(new DelegatingCallableStatement(this,
+ connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability)));
} catch (final SQLException e) {
handleException(e);
+ return null;
}
}
@Override
- public Statement createStatement(final int resultSetType, final int resultSetConcurrency,
- final int resultSetHoldability) throws SQLException {
+ public PreparedStatement prepareStatement(final String sql) throws SQLException {
checkOpen();
try {
- final DelegatingStatement ds = new DelegatingStatement(this,
- connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability));
- initializeStatement(ds);
- return ds;
+ return init(new DelegatingPreparedStatement(this, connection.prepareStatement(sql)));
} catch (final SQLException e) {
handleException(e);
return null;
@@ -719,14 +723,10 @@ public class DelegatingConnection<C extends Connection> extends AbandonedTrace i
}
@Override
- public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency,
- final int resultSetHoldability) throws SQLException {
+ public PreparedStatement prepareStatement(final String sql, final int autoGeneratedKeys) throws SQLException {
checkOpen();
try {
- final DelegatingPreparedStatement dps = new DelegatingPreparedStatement(this,
- connection.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability));
- initializeStatement(dps);
- return dps;
+ return init(new DelegatingPreparedStatement(this, connection.prepareStatement(sql, autoGeneratedKeys)));
} catch (final SQLException e) {
handleException(e);
return null;
@@ -734,14 +734,12 @@ public class DelegatingConnection<C extends Connection> extends AbandonedTrace i
}
@Override
- public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency,
- final int resultSetHoldability) throws SQLException {
+ public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency)
+ throws SQLException {
checkOpen();
try {
- final DelegatingCallableStatement dcs = new DelegatingCallableStatement(this,
- connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability));
- initializeStatement(dcs);
- return dcs;
+ return init(new DelegatingPreparedStatement(this,
+ connection.prepareStatement(sql, resultSetType, resultSetConcurrency)));
} catch (final SQLException e) {
handleException(e);
return null;
@@ -749,13 +747,12 @@ public class DelegatingConnection<C extends Connection> extends AbandonedTrace i
}
@Override
- public PreparedStatement prepareStatement(final String sql, final int autoGeneratedKeys) throws SQLException {
+ public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency,
+ final int resultSetHoldability) throws SQLException {
checkOpen();
try {
- final DelegatingPreparedStatement dps = new DelegatingPreparedStatement(this,
- connection.prepareStatement(sql, autoGeneratedKeys));
- initializeStatement(dps);
- return dps;
+ return init(new DelegatingPreparedStatement(this,
+ connection.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability)));
} catch (final SQLException e) {
handleException(e);
return null;
@@ -766,10 +763,7 @@ public class DelegatingConnection<C extends Connection> extends AbandonedTrace i
public PreparedStatement prepareStatement(final String sql, final int[] columnIndexes) throws SQLException {
checkOpen();
try {
- final DelegatingPreparedStatement dps = new DelegatingPreparedStatement(this,
- connection.prepareStatement(sql, columnIndexes));
- initializeStatement(dps);
- return dps;
+ return init(new DelegatingPreparedStatement(this, connection.prepareStatement(sql, columnIndexes)));
} catch (final SQLException e) {
handleException(e);
return null;
@@ -780,10 +774,7 @@ public class DelegatingConnection<C extends Connection> extends AbandonedTrace i
public PreparedStatement prepareStatement(final String sql, final String[] columnNames) throws SQLException {
checkOpen();
try {
- final DelegatingPreparedStatement dps = new DelegatingPreparedStatement(this,
- connection.prepareStatement(sql, columnNames));
- initializeStatement(dps);
- return dps;
+ return init(new DelegatingPreparedStatement(this, connection.prepareStatement(sql, columnNames)));
} catch (final SQLException e) {
handleException(e);
return null;
@@ -791,103 +782,82 @@ public class DelegatingConnection<C extends Connection> extends AbandonedTrace i
}
@Override
- public boolean isWrapperFor(final Class<?> iface) throws SQLException {
- if (iface.isAssignableFrom(getClass())) {
- return true;
- } else if (iface.isAssignableFrom(connection.getClass())) {
- return true;
- } else {
- return connection.isWrapperFor(iface);
- }
- }
-
- @Override
- public <T> T unwrap(final Class<T> iface) throws SQLException {
- if (iface.isAssignableFrom(getClass())) {
- return iface.cast(this);
- } else if (iface.isAssignableFrom(connection.getClass())) {
- return iface.cast(connection);
- } else {
- return connection.unwrap(iface);
- }
- }
-
- @Override
- public Array createArrayOf(final String typeName, final Object[] elements) throws SQLException {
+ public void releaseSavepoint(final Savepoint savepoint) throws SQLException {
checkOpen();
try {
- return connection.createArrayOf(typeName, elements);
+ connection.releaseSavepoint(savepoint);
} catch (final SQLException e) {
handleException(e);
- return null;
}
}
@Override
- public Blob createBlob() throws SQLException {
+ public void rollback() throws SQLException {
checkOpen();
try {
- return connection.createBlob();
+ connection.rollback();
} catch (final SQLException e) {
handleException(e);
- return null;
}
}
@Override
- public Clob createClob() throws SQLException {
+ public void rollback(final Savepoint savepoint) throws SQLException {
checkOpen();
try {
- return connection.createClob();
+ connection.rollback(savepoint);
} catch (final SQLException e) {
handleException(e);
- return null;
}
}
@Override
- public NClob createNClob() throws SQLException {
+ public void setAutoCommit(final boolean autoCommit) throws SQLException {
checkOpen();
try {
- return connection.createNClob();
+ connection.setAutoCommit(autoCommit);
+ if (cacheState) {
+ cachedAutoCommit = Boolean.valueOf(connection.getAutoCommit());
+ }
} catch (final SQLException e) {
+ cachedAutoCommit = null;
handleException(e);
- return null;
}
}
- @Override
- public SQLXML createSQLXML() throws SQLException {
- checkOpen();
- try {
- return connection.createSQLXML();
- } catch (final SQLException e) {
- handleException(e);
- return null;
- }
+ /**
+ * Sets the state caching flag.
+ *
+ * @param cacheState
+ * The new value for the state caching flag
+ */
+ public void setCacheState(final boolean cacheState) {
+ this.cacheState = cacheState;
}
@Override
- public Struct createStruct(final String typeName, final Object[] attributes) throws SQLException {
+ public void setCatalog(final String catalog) throws SQLException {
checkOpen();
try {
- return connection.createStruct(typeName, attributes);
+ connection.setCatalog(catalog);
+ if (cacheState) {
+ cachedCatalog = connection.getCatalog();
+ }
} catch (final SQLException e) {
+ cachedCatalog = null;
handleException(e);
- return null;
}
}
@Override
- public boolean isValid(final int timeoutSeconds) throws SQLException {
- if (isClosed()) {
- return false;
- }
+ public void setClientInfo(final Properties properties) throws SQLClientInfoException {
try {
- return connection.isValid(timeoutSeconds);
+ checkOpen();
+ connection.setClientInfo(properties);
+ } catch (final SQLClientInfoException e) {
+ throw e;
} catch (final SQLException e) {
- handleException(e);
- return false;
+ throw new SQLClientInfoException("Connection is closed.", EMPTY_FAILED_PROPERTIES, e);
}
}
@@ -903,55 +873,95 @@ public class DelegatingConnection<C extends Connection> extends AbandonedTrace i
}
}
+ protected void setClosedInternal(final boolean closed) {
+ this.closed = closed;
+ }
+
+ /**
+ * Sets the default query timeout that will be used for {@link Statement}s created from this connection.
+ * <code>null</code> means that the driver default will be used.
+ *
+ * @param defaultQueryTimeoutDuration
+ * the new query timeout limit Duration; zero means there is no limit.
+ * @since 2.10.0
+ */
+ public void setDefaultQueryTimeout(final Duration defaultQueryTimeoutDuration) {
+ this.defaultQueryTimeoutDuration = defaultQueryTimeoutDuration;
+ }
+
+ /**
+ * Sets the default query timeout that will be used for {@link Statement}s created from this connection.
+ * <code>null</code> means that the driver default will be used.
+ *
+ * @param defaultQueryTimeoutSeconds
+ * the new query timeout limit in seconds; zero means there is no limit.
+ * @deprecated Use {@link #setDefaultQueryTimeout(Duration)}.
+ */
+ @Deprecated
+ public void setDefaultQueryTimeout(final Integer defaultQueryTimeoutSeconds) {
+ this.defaultQueryTimeoutDuration = defaultQueryTimeoutSeconds == null ? null : Duration.ofSeconds(defaultQueryTimeoutSeconds.intValue());
+ }
+
+ /**
+ * Sets my delegate.
+ *
+ * @param connection
+ * my delegate.
+ */
+ public void setDelegate(final C connection) {
+ this.connection = connection;
+ }
+
@Override
- public void setClientInfo(final Properties properties) throws SQLClientInfoException {
+ public void setHoldability(final int holdability) throws SQLException {
+ checkOpen();
try {
- checkOpen();
- connection.setClientInfo(properties);
- } catch (final SQLClientInfoException e) {
- throw e;
+ connection.setHoldability(holdability);
} catch (final SQLException e) {
- throw new SQLClientInfoException("Connection is closed.", EMPTY_FAILED_PROPERTIES, e);
+ handleException(e);
}
}
@Override
- public Properties getClientInfo() throws SQLException {
+ public void setNetworkTimeout(final Executor executor, final int milliseconds) throws SQLException {
checkOpen();
try {
- return connection.getClientInfo();
+ Jdbc41Bridge.setNetworkTimeout(connection, executor, milliseconds);
} catch (final SQLException e) {
handleException(e);
- return null;
}
}
@Override
- public String getClientInfo(final String name) throws SQLException {
+ public void setReadOnly(final boolean readOnly) throws SQLException {
checkOpen();
try {
- return connection.getClientInfo(name);
+ connection.setReadOnly(readOnly);
+ if (cacheState) {
+ cachedReadOnly = Boolean.valueOf(connection.isReadOnly());
+ }
} catch (final SQLException e) {
+ cachedReadOnly = null;
handleException(e);
- return null;
}
}
@Override
- public void setSchema(final String schema) throws SQLException {
+ public Savepoint setSavepoint() throws SQLException {
checkOpen();
try {
- Jdbc41Bridge.setSchema(connection, schema);
+ return connection.setSavepoint();
} catch (final SQLException e) {
handleException(e);
+ return null;
}
}
@Override
- public String getSchema() throws SQLException {
+ public Savepoint setSavepoint(final String name) throws SQLException {
checkOpen();
try {
- return Jdbc41Bridge.getSchema(connection);
+ return connection.setSavepoint(name);
} catch (final SQLException e) {
handleException(e);
return null;
@@ -959,32 +969,78 @@ public class DelegatingConnection<C extends Connection> extends AbandonedTrace i
}
@Override
- public void abort(final Executor executor) throws SQLException {
+ public void setSchema(final String schema) throws SQLException {
+ checkOpen();
try {
- Jdbc41Bridge.abort(connection, executor);
+ Jdbc41Bridge.setSchema(connection, schema);
+ if (cacheState) {
+ cachedSchema = connection.getSchema();
+ }
} catch (final SQLException e) {
+ cachedSchema = null;
handleException(e);
}
}
@Override
- public void setNetworkTimeout(final Executor executor, final int milliseconds) throws SQLException {
+ public void setTransactionIsolation(final int level) throws SQLException {
checkOpen();
try {
- Jdbc41Bridge.setNetworkTimeout(connection, executor, milliseconds);
+ connection.setTransactionIsolation(level);
} catch (final SQLException e) {
handleException(e);
}
}
@Override
- public int getNetworkTimeout() throws SQLException {
+ public void setTypeMap(final Map<String, Class<?>> map) throws SQLException {
checkOpen();
try {
- return Jdbc41Bridge.getNetworkTimeout(connection);
+ connection.setTypeMap(map);
} catch (final SQLException e) {
handleException(e);
- return 0;
}
}
+
+ /**
+ * Returns a string representation of the metadata associated with the innermost delegate connection.
+ */
+ @Override
+ public synchronized String toString() {
+ String str = null;
+
+ final Connection conn = this.getInnermostDelegateInternal();
+ if (conn != null) {
+ try {
+ if (conn.isClosed()) {
+ str = "connection is closed";
+ } else {
+ final StringBuilder sb = new StringBuilder();
+ sb.append(hashCode());
+ final DatabaseMetaData meta = conn.getMetaData();
+ if (meta != null) {
+ sb.append(", URL=");
+ sb.append(meta.getURL());
+ sb.append(", ");
+ sb.append(meta.getDriverName());
+ str = sb.toString();
+ }
+ }
+ } catch (final SQLException ex) {
+ // Ignore
+ }
+ }
+ return str != null ? str : super.toString();
+ }
+
+ @Override
+ public <T> T unwrap(final Class<T> iface) throws SQLException {
+ if (iface.isAssignableFrom(getClass())) {
+ return iface.cast(this);
+ }
+ if (iface.isAssignableFrom(connection.getClass())) {
+ return iface.cast(connection);
+ }
+ return connection.unwrap(iface);
+ }
}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingDatabaseMetaData.java b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingDatabaseMetaData.java
index 7b45869..00f816c 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingDatabaseMetaData.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingDatabaseMetaData.java
@@ -984,11 +984,10 @@ public class DelegatingDatabaseMetaData implements DatabaseMetaData {
}
protected void handleException(final SQLException e) throws SQLException {
- if (connection != null) {
- connection.handleException(e);
- } else {
+ if (connection == null) {
throw e;
}
+ connection.handleException(e);
}
@Override
@@ -1025,11 +1024,11 @@ public class DelegatingDatabaseMetaData implements DatabaseMetaData {
public boolean isWrapperFor(final Class<?> iface) throws SQLException {
if (iface.isAssignableFrom(getClass())) {
return true;
- } else if (iface.isAssignableFrom(databaseMetaData.getClass())) {
+ }
+ if (iface.isAssignableFrom(databaseMetaData.getClass())) {
return true;
- } else {
- return databaseMetaData.isWrapperFor(iface);
}
+ return databaseMetaData.isWrapperFor(iface);
}
@Override
@@ -1805,8 +1804,6 @@ public class DelegatingDatabaseMetaData implements DatabaseMetaData {
}
}
- /* JDBC_4_ANT_KEY_BEGIN */
-
@Override
public boolean supportsSubqueriesInComparisons() throws SQLException {
try {
@@ -1903,11 +1900,11 @@ public class DelegatingDatabaseMetaData implements DatabaseMetaData {
public <T> T unwrap(final Class<T> iface) throws SQLException {
if (iface.isAssignableFrom(getClass())) {
return iface.cast(this);
- } else if (iface.isAssignableFrom(databaseMetaData.getClass())) {
+ }
+ if (iface.isAssignableFrom(databaseMetaData.getClass())) {
return iface.cast(databaseMetaData);
- } else {
- return databaseMetaData.unwrap(iface);
}
+ return databaseMetaData.unwrap(iface);
}
@Override
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingResultSet.java b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingResultSet.java
index 56a01fd..62b1a3b 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingResultSet.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingResultSet.java
@@ -102,15 +102,15 @@ public final class DelegatingResultSet extends AbandonedTrace implements ResultS
* Private to ensure all construction is {@link #wrapResultSet(Connection, ResultSet)}
* </p>
*
- * @param conn
+ * @param connection
* Connection which created this ResultSet
- * @param res
+ * @param resultSet
* ResultSet to wrap
*/
- private DelegatingResultSet(final Connection conn, final ResultSet res) {
- super((AbandonedTrace) conn);
- this.connection = conn;
- this.resultSet = res;
+ private DelegatingResultSet(final Connection connection, final ResultSet resultSet) {
+ super((AbandonedTrace) connection);
+ this.connection = connection;
+ this.resultSet = resultSet;
}
/**
@@ -1117,11 +1117,11 @@ public final class DelegatingResultSet extends AbandonedTrace implements ResultS
public boolean isWrapperFor(final Class<?> iface) throws SQLException {
if (iface.isAssignableFrom(getClass())) {
return true;
- } else if (iface.isAssignableFrom(resultSet.getClass())) {
+ }
+ if (iface.isAssignableFrom(resultSet.getClass())) {
return true;
- } else {
- return resultSet.isWrapperFor(iface);
}
+ return resultSet.isWrapperFor(iface);
}
@Override
@@ -1248,11 +1248,11 @@ public final class DelegatingResultSet extends AbandonedTrace implements ResultS
public <T> T unwrap(final Class<T> iface) throws SQLException {
if (iface.isAssignableFrom(getClass())) {
return iface.cast(this);
- } else if (iface.isAssignableFrom(resultSet.getClass())) {
+ }
+ if (iface.isAssignableFrom(resultSet.getClass())) {
return iface.cast(resultSet);
- } else {
- return resultSet.unwrap(iface);
}
+ return resultSet.unwrap(iface);
}
@Override
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingStatement.java b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingStatement.java
index c3c4a08..3f3481b 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingStatement.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingStatement.java
@@ -43,7 +43,7 @@ public class DelegatingStatement extends AbandonedTrace implements Statement {
/** The connection that created me. **/
private DelegatingConnection<?> connection;
- private boolean closed = false;
+ private boolean closed;
/**
* Create a wrapper for the Statement which traces this Statement to the Connection which created it and the code
@@ -625,11 +625,10 @@ public class DelegatingStatement extends AbandonedTrace implements Statement {
}
protected void handleException(final SQLException e) throws SQLException {
- if (connection != null) {
- connection.handleException(e);
- } else {
+ if (connection == null) {
throw e;
}
+ connection.handleException(e);
}
/*
@@ -670,11 +669,11 @@ public class DelegatingStatement extends AbandonedTrace implements Statement {
public boolean isWrapperFor(final Class<?> iface) throws SQLException {
if (iface.isAssignableFrom(getClass())) {
return true;
- } else if (iface.isAssignableFrom(statement.getClass())) {
+ }
+ if (iface.isAssignableFrom(statement.getClass())) {
return true;
- } else {
- return statement.isWrapperFor(iface);
}
+ return statement.isWrapperFor(iface);
}
/**
@@ -816,10 +815,10 @@ public class DelegatingStatement extends AbandonedTrace implements Statement {
public <T> T unwrap(final Class<T> iface) throws SQLException {
if (iface.isAssignableFrom(getClass())) {
return iface.cast(this);
- } else if (iface.isAssignableFrom(statement.getClass())) {
+ }
+ if (iface.isAssignableFrom(statement.getClass())) {
return iface.cast(statement);
- } else {
- return statement.unwrap(iface);
}
+ return statement.unwrap(iface);
}
}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/Jdbc41Bridge.java b/java/org/apache/tomcat/dbcp/dbcp2/Jdbc41Bridge.java
index 15b943d..42f29c4 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/Jdbc41Bridge.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/Jdbc41Bridge.java
@@ -77,6 +77,29 @@ public class Jdbc41Bridge {
}
/**
+ * Delegates to {@link Statement#closeOnCompletion()} without throwing an {@link AbstractMethodError}.
+ * <p>
+ * If the JDBC driver does not implement {@link Statement#closeOnCompletion()}, then just check that the connection
+ * is closed to then throw an SQLException.
+ * </p>
+ *
+ * @param statement
+ * See {@link Statement#closeOnCompletion()}
+ * @throws SQLException
+ * See {@link Statement#closeOnCompletion()}
+ * @see Statement#closeOnCompletion()
+ */
+ public static void closeOnCompletion(final Statement statement) throws SQLException {
+ try {
+ statement.closeOnCompletion();
+ } catch (final AbstractMethodError e) {
+ if (statement.isClosed()) {
+ throw new SQLException("Statement closed");
+ }
+ }
+ }
+
+ /**
* Delegates to {@link DatabaseMetaData#generatedKeyAlwaysReturned()} without throwing a
* {@link AbstractMethodError}.
* <p>
@@ -315,6 +338,26 @@ public class Jdbc41Bridge {
}
/**
+ * Delegates to {@link CommonDataSource#getParentLogger()} without throwing an {@link AbstractMethodError}.
+ * <p>
+ * If the JDBC driver does not implement {@link CommonDataSource#getParentLogger()}, then return null.
+ * </p>
+ *
+ * @param commonDataSource
+ * See {@link CommonDataSource#getParentLogger()}
+ * @return See {@link CommonDataSource#getParentLogger()}
+ * @throws SQLFeatureNotSupportedException
+ * See {@link CommonDataSource#getParentLogger()}
+ */
+ public static Logger getParentLogger(final CommonDataSource commonDataSource) throws SQLFeatureNotSupportedException {
+ try {
+ return commonDataSource.getParentLogger();
+ } catch (final AbstractMethodError e) {
+ throw new SQLFeatureNotSupportedException("javax.sql.CommonDataSource#getParentLogger()");
+ }
+ }
+
+ /**
* Delegates to {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)} without throwing a
* {@link AbstractMethodError}.
* <p>
@@ -371,6 +414,31 @@ public class Jdbc41Bridge {
}
/**
+ * Delegates to {@link Statement#isCloseOnCompletion()} without throwing an {@link AbstractMethodError}.
+ * <p>
+ * If the JDBC driver does not implement {@link Statement#isCloseOnCompletion()}, then just check that the
+ * connection is closed to then throw an SQLException.
+ * </p>
+ *
+ * @param statement
+ * See {@link Statement#isCloseOnCompletion()}
+ * @return See {@link Statement#isCloseOnCompletion()}
+ * @throws SQLException
+ * See {@link Statement#isCloseOnCompletion()}
+ * @see Statement#closeOnCompletion()
+ */
+ public static boolean isCloseOnCompletion(final Statement statement) throws SQLException {
+ try {
+ return statement.isCloseOnCompletion();
+ } catch (final AbstractMethodError e) {
+ if (statement.isClosed()) {
+ throw new SQLException("Statement closed");
+ }
+ return false;
+ }
+ }
+
+ /**
* Delegates to {@link Connection#setNetworkTimeout(Executor, int)} without throwing an {@link AbstractMethodError}.
* <p>
* If the JDBC driver does not implement {@link Connection#setNetworkTimeout(Executor, int)}, then do nothing.
@@ -417,72 +485,4 @@ public class Jdbc41Bridge {
}
}
- /**
- * Delegates to {@link Statement#closeOnCompletion()} without throwing an {@link AbstractMethodError}.
- * <p>
- * If the JDBC driver does not implement {@link Statement#closeOnCompletion()}, then just check that the connection
- * is closed to then throw an SQLException.
- * </p>
- *
- * @param statement
- * See {@link Statement#closeOnCompletion()}
- * @throws SQLException
- * See {@link Statement#closeOnCompletion()}
- * @see Statement#closeOnCompletion()
- */
- public static void closeOnCompletion(final Statement statement) throws SQLException {
- try {
- statement.closeOnCompletion();
- } catch (final AbstractMethodError e) {
- if (statement.isClosed()) {
- throw new SQLException("Statement closed");
- }
- }
- }
-
- /**
- * Delegates to {@link Statement#isCloseOnCompletion()} without throwing an {@link AbstractMethodError}.
- * <p>
- * If the JDBC driver does not implement {@link Statement#isCloseOnCompletion()}, then just check that the
- * connection is closed to then throw an SQLException.
- * </p>
- *
- * @param statement
- * See {@link Statement#isCloseOnCompletion()}
- * @return See {@link Statement#isCloseOnCompletion()}
- * @throws SQLException
- * See {@link Statement#isCloseOnCompletion()}
- * @see Statement#closeOnCompletion()
- */
- public static boolean isCloseOnCompletion(final Statement statement) throws SQLException {
- try {
- return statement.isCloseOnCompletion();
- } catch (final AbstractMethodError e) {
- if (statement.isClosed()) {
- throw new SQLException("Statement closed");
- }
- return false;
- }
- }
-
- /**
- * Delegates to {@link CommonDataSource#getParentLogger()} without throwing an {@link AbstractMethodError}.
- * <p>
- * If the JDBC driver does not implement {@link CommonDataSource#getParentLogger()}, then return null.
- * </p>
- *
- * @param commonDataSource
- * See {@link CommonDataSource#getParentLogger()}
- * @return See {@link CommonDataSource#getParentLogger()}
- * @throws SQLFeatureNotSupportedException
- * See {@link CommonDataSource#getParentLogger()}
- */
- public static Logger getParentLogger(final CommonDataSource commonDataSource) throws SQLFeatureNotSupportedException {
- try {
- return commonDataSource.getParentLogger();
- } catch (final AbstractMethodError e) {
- throw new SQLFeatureNotSupportedException("javax.sql.CommonDataSource#getParentLogger()");
- }
- }
-
}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/PStmtKey.java b/java/org/apache/tomcat/dbcp/dbcp2/PStmtKey.java
index 3b5daf3..87991e7 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/PStmtKey.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/PStmtKey.java
@@ -852,7 +852,7 @@ public class PStmtKey {
* @return An array of column indexes.
*/
public int[] getColumnIndexes() {
- return columnIndexes;
+ return columnIndexes == null ? null : columnIndexes.clone();
}
/**
@@ -861,7 +861,7 @@ public class PStmtKey {
* @return An array of column names.
*/
public String[] getColumnNames() {
- return columnNames;
+ return columnNames == null ? null : columnNames.clone();
}
/**
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/PoolableCallableStatement.java b/java/org/apache/tomcat/dbcp/dbcp2/PoolableCallableStatement.java
index 683a24f..16e27a1 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/PoolableCallableStatement.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/PoolableCallableStatement.java
@@ -71,6 +71,21 @@ public class PoolableCallableStatement extends DelegatingCallableStatement {
}
/**
+ * Activates after retrieval from the pool. Adds a trace for this CallableStatement to the Connection that created
+ * it.
+ *
+ * @since 2.4.0 made public, was protected in 2.3.0.
+ */
+ @Override
+ public void activate() throws SQLException {
+ setClosedInternal(false);
+ if (getConnectionInternal() != null) {
+ getConnectionInternal().addTrace(this);
+ }
+ super.activate();
+ }
+
+ /**
* Returns the CallableStatement to the pool. If {{@link #isClosed()}, this is a No-op.
*/
@Override
@@ -88,21 +103,6 @@ public class PoolableCallableStatement extends DelegatingCallableStatement {
}
/**
- * Activates after retrieval from the pool. Adds a trace for this CallableStatement to the Connection that created
- * it.
- *
- * @since 2.4.0 made public, was protected in 2.3.0.
- */
- @Override
- public void activate() throws SQLException {
- setClosedInternal(false);
- if (getConnectionInternal() != null) {
- getConnectionInternal().addTrace(this);
- }
- super.activate();
- }
-
- /**
* Passivates to prepare for return to the pool. Removes the trace associated with this CallableStatement from the
* Connection that created it. Also closes any associated ResultSets.
*
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnection.java b/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnection.java
index 6b052ce..52243c5 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnection.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnection.java
@@ -21,6 +21,7 @@ import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
+import java.time.Duration;
import java.util.Collection;
import java.util.concurrent.Executor;
@@ -64,7 +65,7 @@ public class PoolableConnection extends DelegatingConnection<Connection> impleme
* Indicate that unrecoverable SQLException was thrown when using this connection. Such a connection should be
* considered broken and not pass validation in the future.
*/
- private boolean fatalSqlExceptionThrown = false;
+ private boolean fatalSqlExceptionThrown;
/**
* SQL_STATE codes considered to signal fatal conditions. Overrides the defaults in
@@ -81,6 +82,20 @@ public class PoolableConnection extends DelegatingConnection<Connection> impleme
* my underlying connection
* @param pool
* the pool to which I should return when closed
+ * @param jmxName
+ * JMX name
+ */
+ public PoolableConnection(final Connection conn, final ObjectPool<PoolableConnection> pool,
+ final ObjectName jmxName) {
+ this(conn, pool, jmxName, null, true);
+ }
+
+ /**
+ *
+ * @param conn
+ * my underlying connection
+ * @param pool
+ * the pool to which I should return when closed
* @param jmxObjectName
* JMX name
* @param disconnectSqlCodes
@@ -108,50 +123,16 @@ public class PoolableConnection extends DelegatingConnection<Connection> impleme
}
/**
+ * Abort my underlying {@link Connection}.
*
- * @param conn
- * my underlying connection
- * @param pool
- * the pool to which I should return when closed
- * @param jmxName
- * JMX name
- */
- public PoolableConnection(final Connection conn, final ObjectPool<PoolableConnection> pool,
- final ObjectName jmxName) {
- this(conn, pool, jmxName, null, true);
- }
-
- @Override
- protected void passivate() throws SQLException {
- super.passivate();
- setClosedInternal(true);
- if (getDelegateInternal() instanceof PoolingConnection) {
- ((PoolingConnection) getDelegateInternal()).connectionReturnedToPool();
- }
- }
-
- /**
- * {@inheritDoc}
- * <p>
- * This method should not be used by a client to determine whether or not a connection should be return to the
- * connection pool (by calling {@link #close()}). Clients should always attempt to return a connection to the pool
- * once it is no longer required.
+ * @since 2.9.0
*/
@Override
- public boolean isClosed() throws SQLException {
- if (isClosedInternal()) {
- return true;
- }
-
- if (getDelegateInternal().isClosed()) {
- // Something has gone wrong. The underlying connection has been
- // closed without the connection being returned to the pool. Return
- // it now.
- close();
- return true;
+ public void abort(final Executor executor) throws SQLException {
+ if (jmxObjectName != null) {
+ jmxObjectName.unregisterMBean();
}
-
- return false;
+ super.abort(executor);
}
/**
@@ -215,44 +196,132 @@ public class PoolableConnection extends DelegatingConnection<Connection> impleme
}
/**
- * Actually close my underlying {@link Connection}.
+ * @return The disconnection SQL codes.
+ * @since 2.6.0
+ */
+ public Collection<String> getDisconnectionSqlCodes() {
+ return disconnectionSqlCodes;
+ }
+
+ /**
+ * Expose the {@link #toString()} method via a bean getter so it can be read as a property via JMX.
*/
@Override
- public void reallyClose() throws SQLException {
- if (jmxObjectName != null) {
- jmxObjectName.unregisterMBean();
+ public String getToString() {
+ return toString();
+ }
+
+ @Override
+ protected void handleException(final SQLException e) throws SQLException {
+ fatalSqlExceptionThrown |= isFatalException(e);
+ super.handleException(e);
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * This method should not be used by a client to determine whether or not a connection should be return to the
+ * connection pool (by calling {@link #close()}). Clients should always attempt to return a connection to the pool
+ * once it is no longer required.
+ */
+ @Override
+ public boolean isClosed() throws SQLException {
+ if (isClosedInternal()) {
+ return true;
}
- if (validationPreparedStatement != null) {
- try {
- validationPreparedStatement.close();
- } catch (final SQLException sqle) {
- // Ignore
- }
+ if (getDelegateInternal().isClosed()) {
+ // Something has gone wrong. The underlying connection has been
+ // closed without the connection being returned to the pool. Return
+ // it now.
+ close();
+ return true;
}
- super.closeInternal();
+ return false;
}
/**
- * Abort my underlying {@link Connection}.
+ * Checks the SQLState of the input exception.
+ * <p>
+ * If {@link #disconnectionSqlCodes} has been set, sql states are compared to those in the configured list of fatal
+ * exception codes. If this property is not set, codes are compared against the default codes in
+ * {@link Utils#DISCONNECTION_SQL_CODES} and in this case anything starting with #{link
+ * Utils.DISCONNECTION_SQL_CODE_PREFIX} is considered a disconnection.
+ * </p>
*
- * @since 2.9.0
+ * @param e SQLException to be examined
+ * @return true if the exception signals a disconnection
+ */
+ boolean isDisconnectionSqlException(final SQLException e) {
+ boolean fatalException = false;
+ final String sqlState = e.getSQLState();
+ if (sqlState != null) {
+ fatalException = disconnectionSqlCodes == null
+ ? sqlState.startsWith(Utils.DISCONNECTION_SQL_CODE_PREFIX) || Utils.DISCONNECTION_SQL_CODES.contains(sqlState)
+ : disconnectionSqlCodes.contains(sqlState);
+ }
+ return fatalException;
+ }
+
+ /**
+ * Checks the SQLState of the input exception and any nested SQLExceptions it wraps.
+ * <p>
+ * If {@link #disconnectionSqlCodes} has been set, sql states are compared to those in the
+ * configured list of fatal exception codes. If this property is not set, codes are compared against the default
+ * codes in {@link Utils#DISCONNECTION_SQL_CODES} and in this case anything starting with #{link
+ * Utils.DISCONNECTION_SQL_CODE_PREFIX} is considered a disconnection.
+ * </p>
+ *
+ * @param e
+ * SQLException to be examined
+ * @return true if the exception signals a disconnection
+ */
+ boolean isFatalException(final SQLException e) {
+ boolean fatalException = isDisconnectionSqlException(e);
+ if (!fatalException) {
+ SQLException parentException = e;
+ SQLException nextException = e.getNextException();
+ while (nextException != null && nextException != parentException && !fatalException) {
+ fatalException = isDisconnectionSqlException(nextException);
+ parentException = nextException;
+ nextException = parentException.getNextException();
+ }
+ }
+ return fatalException;
+ }
+
+ /**
+ * @return Whether to fail-fast.
+ * @since 2.6.0
*/
+ public boolean isFastFailValidation() {
+ return fastFailValidation;
+ }
+
@Override
- public void abort(Executor executor) throws SQLException {
- if (jmxObjectName != null) {
- jmxObjectName.unregisterMBean();
+ protected void passivate() throws SQLException {
+ super.passivate();
+ setClosedInternal(true);
+ if (getDelegateInternal() instanceof PoolingConnection) {
+ ((PoolingConnection) getDelegateInternal()).connectionReturnedToPool();
}
- super.abort(executor);
}
/**
- * Expose the {@link #toString()} method via a bean getter so it can be read as a property via JMX.
+ * Actually close my underlying {@link Connection}.
*/
@Override
- public String getToString() {
- return toString();
+ public void reallyClose() throws SQLException {
+ if (jmxObjectName != null) {
+ jmxObjectName.unregisterMBean();
+ }
+
+ if (validationPreparedStatement != null) {
+ Utils.closeQuietly((AutoCloseable) validationPreparedStatement);
+ }
+
+ super.closeInternal();
}
/**
@@ -272,17 +341,42 @@ public class PoolableConnection extends DelegatingConnection<Connection> impleme
* The validation timeout in seconds.
* @throws SQLException
* Thrown when validation fails or an SQLException occurs during validation
+ * @deprecated Use {@link #validate(String, Duration)}.
*/
- public void validate(final String sql, int timeoutSeconds) throws SQLException {
+ @Deprecated
+ public void validate(final String sql, final int timeoutSeconds) throws SQLException {
+ validate(sql, Duration.ofSeconds(timeoutSeconds));
+ }
+
+ /**
+ * 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 timeoutDuration
+ * The validation timeout in seconds.
+ * @throws SQLException
+ * Thrown when validation fails or an SQLException occurs during validation
+ * @since 2.10.0
+ */
+ public void validate(final String sql, Duration timeoutDuration) throws SQLException {
if (fastFailValidation && fatalSqlExceptionThrown) {
throw new SQLException(Utils.getMessage("poolableConnection.validate.fastFail"));
}
- if (sql == null || sql.length() == 0) {
- if (timeoutSeconds < 0) {
- timeoutSeconds = 0;
+ if (sql == null || sql.isEmpty()) {
+ if (timeoutDuration.isNegative()) {
+ timeoutDuration = Duration.ZERO;
}
- if (!isValid(timeoutSeconds)) {
+ if (!isValid(timeoutDuration)) {
throw new SQLException("isValid() returned false");
}
return;
@@ -295,8 +389,8 @@ public class PoolableConnection extends DelegatingConnection<Connection> impleme
validationPreparedStatement = getInnermostDelegateInternal().prepareStatement(sql);
}
- if (timeoutSeconds > 0) {
- validationPreparedStatement.setQueryTimeout(timeoutSeconds);
+ if (timeoutDuration.compareTo(Duration.ZERO) > 0) {
+ validationPreparedStatement.setQueryTimeout((int) timeoutDuration.getSeconds());
}
try (ResultSet rs = validationPreparedStatement.executeQuery()) {
@@ -307,57 +401,4 @@ public class PoolableConnection extends DelegatingConnection<Connection> impleme
throw sqle;
}
}
-
- /**
- * Checks the SQLState of the input exception and any nested SQLExceptions it wraps.
- * <p>
- * If {@link #disconnectionSqlCodes} has been set, sql states are compared to those in the
- * configured list of fatal exception codes. If this property is not set, codes are compared against the default
- * codes in {@link Utils#DISCONNECTION_SQL_CODES} and in this case anything starting with #{link
- * Utils.DISCONNECTION_SQL_CODE_PREFIX} is considered a disconnection.
- * </p>
- *
- * @param e
- * SQLException to be examined
- * @return true if the exception signals a disconnection
- */
- private boolean isDisconnectionSqlException(final SQLException e) {
- boolean fatalException = false;
- final String sqlState = e.getSQLState();
- if (sqlState != null) {
- fatalException = disconnectionSqlCodes == null
- ? sqlState.startsWith(Utils.DISCONNECTION_SQL_CODE_PREFIX)
- || Utils.DISCONNECTION_SQL_CODES.contains(sqlState)
- : disconnectionSqlCodes.contains(sqlState);
- if (!fatalException) {
- final SQLException nextException = e.getNextException();
- if (nextException != null && nextException != e) {
- fatalException = isDisconnectionSqlException(e.getNextException());
- }
- }
- }
- return fatalException;
- }
-
- @Override
- protected void handleException(final SQLException e) throws SQLException {
- fatalSqlExceptionThrown |= isDisconnectionSqlException(e);
- super.handleException(e);
- }
-
- /**
- * @return The disconnection SQL codes.
- * @since 2.6.0
- */
- public Collection<String> getDisconnectionSqlCodes() {
- return disconnectionSqlCodes;
- }
-
- /**
- * @return Whether to fail-fast.
- * @since 2.6.0
- */
- public boolean isFastFailValidation() {
- return fastFailValidation;
- }
}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnectionFactory.java b/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnectionFactory.java
index 84f92f4..f95c262 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnectionFactory.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnectionFactory.java
@@ -19,6 +19,8 @@ package org.apache.tomcat.dbcp.dbcp2;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
+import java.time.Duration;
+import java.time.Instant;
import java.util.Collection;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicLong;
@@ -56,7 +58,7 @@ public class PoolableConnectionFactory implements PooledObjectFactory<PoolableCo
private volatile String validationQuery;
- private volatile int validationQueryTimeoutSeconds = -1;
+ private volatile Duration validationQueryTimeoutDuration = Duration.ofSeconds(-1);
private Collection<String> connectionInitSqls;
@@ -88,11 +90,11 @@ public class PoolableConnectionFactory implements PooledObjectFactory<PoolableCo
private int maxOpenPreparedStatements = GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL_PER_KEY;
- private long maxConnLifetimeMillis = -1;
+ private Duration maxConnDuration = Duration.ofMillis(-1);
- private final AtomicLong connectionIndex = new AtomicLong(0);
+ private final AtomicLong connectionIndex = new AtomicLong();
- private Integer defaultQueryTimeoutSeconds;
+ private Duration defaultQueryTimeoutDuration;
/**
* Creates a new {@code PoolableConnectionFactory}.
@@ -112,26 +114,26 @@ public class PoolableConnectionFactory implements PooledObjectFactory<PoolableCo
validateLifetime(p);
- final PoolableConnection conn = p.getObject();
- conn.activate();
+ final PoolableConnection pConnection = p.getObject();
+ pConnection.activate();
- if (defaultAutoCommit != null && conn.getAutoCommit() != defaultAutoCommit.booleanValue()) {
- conn.setAutoCommit(defaultAutoCommit.booleanValue());
+ if (defaultAutoCommit != null && pConnection.getAutoCommit() != defaultAutoCommit.booleanValue()) {
+ pConnection.setAutoCommit(defaultAutoCommit.booleanValue());
}
if (defaultTransactionIsolation != UNKNOWN_TRANSACTION_ISOLATION
- && conn.getTransactionIsolation() != defaultTransactionIsolation) {
- conn.setTransactionIsolation(defaultTransactionIsolation);
+ && pConnection.getTransactionIsolation() != defaultTransactionIsolation) {
+ pConnection.setTransactionIsolation(defaultTransactionIsolation);
}
- if (defaultReadOnly != null && conn.isReadOnly() != defaultReadOnly.booleanValue()) {
- conn.setReadOnly(defaultReadOnly.booleanValue());
+ if (defaultReadOnly != null && pConnection.isReadOnly() != defaultReadOnly.booleanValue()) {
+ pConnection.setReadOnly(defaultReadOnly.booleanValue());
}
- if (defaultCatalog != null && !defaultCatalog.equals(conn.getCatalog())) {
- conn.setCatalog(defaultCatalog);
+ if (defaultCatalog != null && !defaultCatalog.equals(pConnection.getCatalog())) {
+ pConnection.setCatalog(defaultCatalog);
}
- if (defaultSchema != null && !defaultSchema.equals(Jdbc41Bridge.getSchema(conn))) {
- Jdbc41Bridge.setSchema(conn, defaultSchema);
+ if (defaultSchema != null && !defaultSchema.equals(Jdbc41Bridge.getSchema(pConnection))) {
+ Jdbc41Bridge.setSchema(pConnection, defaultSchema);
}
- conn.setDefaultQueryTimeout(defaultQueryTimeoutSeconds);
+ pConnection.setDefaultQueryTimeout(defaultQueryTimeoutDuration);
}
@Override
@@ -144,7 +146,7 @@ public class PoolableConnectionFactory implements PooledObjectFactory<PoolableCo
*/
@Override
public void destroyObject(final PooledObject<PoolableConnection> p, final DestroyMode mode) throws Exception {
- if (mode != null && mode.equals(DestroyMode.ABANDONED)) {
+ if (mode == DestroyMode.ABANDONED) {
p.getObject().getInnermostDelegate().abort(Runnable::run);
} else {
p.getObject().reallyClose();
@@ -152,6 +154,8 @@ public class PoolableConnectionFactory implements PooledObjectFactory<PoolableCo
}
/**
+ * Gets the cache state.
+ *
* @return The cache state.
* @since Made public in 2.6.0.
*/
@@ -160,6 +164,8 @@ public class PoolableConnectionFactory implements PooledObjectFactory<PoolableCo
}
/**
+ * Gets the connection factory.
+ *
* @return The connection factory.
* @since Made public in 2.6.0.
*/
@@ -213,17 +219,31 @@ public class PoolableConnectionFactory implements PooledObjectFactory<PoolableCo
/**
* @return Default query timeout in seconds.
+ * @deprecated Use {@link #getDefaultQueryTimeoutDuration()}.
*/
+ @Deprecated
public Integer getDefaultQueryTimeout() {
- return defaultQueryTimeoutSeconds;
+ return getDefaultQueryTimeoutSeconds();
+ }
+
+ /**
+ * Gets the default query timeout Duration.
+ *
+ * @return Default query timeout Duration.
+ * @since 2.10.0
+ */
+ public Duration getDefaultQueryTimeoutDuration() {
+ return defaultQueryTimeoutDuration;
}
/**
* @return Default query timeout in seconds.
* @since 2.6.0
+ * @deprecated Use {@link #getDefaultQueryTimeoutDuration()}.
*/
+ @Deprecated
public Integer getDefaultQueryTimeoutSeconds() {
- return defaultQueryTimeoutSeconds;
+ return defaultQueryTimeoutDuration == null ? null : Integer.valueOf((int) defaultQueryTimeoutDuration.getSeconds());
}
/**
@@ -271,11 +291,23 @@ public class PoolableConnectionFactory implements PooledObjectFactory<PoolableCo
}
/**
+ * Gets the Maximum connection duration.
+ *
+ * @return Maximum connection duration.
+ * @since 2.10.0
+ */
+ public Duration getMaxConnDuration() {
+ return maxConnDuration;
+ }
+
+ /**
+ * Gets the Maximum connection lifetime in milliseconds.
+ *
* @return Maximum connection lifetime in milliseconds.
* @since 2.6.0
*/
public long getMaxConnLifetimeMillis() {
- return maxConnLifetimeMillis;
+ return maxConnDuration.toMillis();
}
protected int getMaxOpenPreparedStatements() {
@@ -305,11 +337,25 @@ public class PoolableConnectionFactory implements PooledObjectFactory<PoolableCo
}
/**
+ * Gets the query timeout in seconds.
+ *
+ * @return Validation query timeout in seconds.
+ * @since 2.10.0
+ */
+ public Duration getValidationQueryTimeoutDuration() {
+ return validationQueryTimeoutDuration;
+ }
+
+ /**
+ * Gets the query timeout in seconds.
+ *
* @return Validation query timeout in seconds.
* @since 2.6.0
+ * @deprecated Use {@link #getValidationQueryTimeoutDuration()}.
*/
+ @Deprecated
public int getValidationQueryTimeoutSeconds() {
- return validationQueryTimeoutSeconds;
+ return (int) validationQueryTimeoutDuration.getSeconds();
}
protected void initializeConnection(final Connection conn) throws SQLException {
@@ -374,11 +420,7 @@ public class PoolableConnectionFactory implements PooledObjectFactory<PoolableCo
initializeConnection(conn);
} catch (final SQLException sqle) {
// Make sure the connection is closed
- try {
- conn.close();
- } catch (final SQLException ignore) {
- // ignore
- }
+ Utils.closeQuietly((AutoCloseable) conn);
// Rethrow original exception so it is visible to caller
throw sqle;
}
@@ -390,7 +432,7 @@ public class PoolableConnectionFactory implements PooledObjectFactory<PoolableCo
final GenericKeyedObjectPoolConfig<DelegatingPreparedStatement> config = new GenericKeyedObjectPoolConfig<>();
config.setMaxTotalPerKey(-1);
config.setBlockWhenExhausted(false);
- config.setMaxWaitMillis(0);
+ config.setMaxWait(Duration.ZERO);
config.setMaxIdlePerKey(1);
config.setMaxTotal(maxOpenPreparedStatements);
if (dataSourceJmxObjectName != null) {
@@ -505,8 +547,25 @@ public class PoolableConnectionFactory implements PooledObjectFactory<PoolableCo
this.defaultCatalog = defaultCatalog;
}
+ /**
+ * Sets the query timeout Duration.
+ *
+ * @param defaultQueryTimeoutDuration the query timeout Duration.
+ * @since 2.10.0
+ */
+ public void setDefaultQueryTimeout(final Duration defaultQueryTimeoutDuration) {
+ this.defaultQueryTimeoutDuration = defaultQueryTimeoutDuration;
+ }
+
+ /**
+ * Sets the query timeout in seconds.
+ *
+ * @param defaultQueryTimeoutSeconds the query timeout in seconds.
+ * @deprecated Use {@link #setDefaultQueryTimeout(Duration)}.
+ */
+ @Deprecated
public void setDefaultQueryTimeout(final Integer defaultQueryTimeoutSeconds) {
- this.defaultQueryTimeoutSeconds = defaultQueryTimeoutSeconds;
+ this.defaultQueryTimeoutDuration = defaultQueryTimeoutSeconds == null ? null : Duration.ofSeconds(defaultQueryTimeoutSeconds.longValue());
}
/**
@@ -573,11 +632,25 @@ public class PoolableConnectionFactory implements PooledObjectFactory<PoolableCo
* Sets the maximum lifetime in milliseconds of a connection after which the connection will always fail activation,
* passivation and validation. A value of zero or less indicates an infinite lifetime. The default value is -1.
*
+ * @param maxConnDuration
+ * The maximum lifetime in milliseconds.
+ * @since 2.10.0
+ */
+ public void setMaxConn(final Duration maxConnDuration) {
+ this.maxConnDuration = maxConnDuration;
+ }
+
+ /**
+ * Sets the maximum lifetime in milliseconds of a connection after which the connection will always fail activation,
+ * passivation and validation. A value of zero or less indicates an infinite lifetime. The default value is -1.
+ *
* @param maxConnLifetimeMillis
* The maximum lifetime in milliseconds.
+ * @deprecated Use {@link #setMaxConn(Duration)}.
*/
+ @Deprecated
public void setMaxConnLifetimeMillis(final long maxConnLifetimeMillis) {
- this.maxConnLifetimeMillis = maxConnLifetimeMillis;
+ this.maxConnDuration = Duration.ofMillis(maxConnLifetimeMillis);
}
/**
@@ -610,11 +683,7 @@ public class PoolableConnectionFactory implements PooledObjectFactory<PoolableCo
*/
public synchronized void setPool(final ObjectPool<PoolableConnection> pool) {
if (null != this.pool && pool != this.pool) {
- try {
- this.pool.close();
- } catch (final Exception e) {
- // ignored !?!
- }
+ Utils.closeQuietly(this.pool);
}
this.pool = pool;
}
@@ -639,29 +708,47 @@ public class PoolableConnectionFactory implements PooledObjectFactory<PoolableCo
}
/**
+ * Sets the validation query timeout, the amount of time, that connection validation will wait for a response from the
+ * database when executing a validation query. Use a value less than or equal to 0 for no timeout.
+ *
+ * @param validationQueryTimeoutDuration new validation query timeout duration.
+ * @since 2.10.0
+ */
+ public void setValidationQueryTimeout(final Duration validationQueryTimeoutDuration) {
+ this.validationQueryTimeoutDuration = validationQueryTimeoutDuration;
+ }
+
+ /**
* Sets the validation query timeout, the amount of time, in seconds, that connection validation will wait for a
* response from the database when executing a validation query. Use a value less than or equal to 0 for no timeout.
*
* @param validationQueryTimeoutSeconds
* new validation query timeout value in seconds
+ * @deprecated {@link #setValidationQueryTimeout(Duration)}.
*/
+ @Deprecated
public void setValidationQueryTimeout(final int validationQueryTimeoutSeconds) {
- this.validationQueryTimeoutSeconds = validationQueryTimeoutSeconds;
+ this.validationQueryTimeoutDuration = Duration.ofSeconds(validationQueryTimeoutSeconds);
}
+ /**
+ * Validates the given connection if it is open.
+ *
+ * @param conn the connection to validate.
+ * @throws SQLException if the connection is closed or validate fails.
+ */
public void validateConnection(final PoolableConnection conn) throws SQLException {
if (conn.isClosed()) {
throw new SQLException("validateConnection: connection closed");
}
- conn.validate(validationQuery, validationQueryTimeoutSeconds);
+ conn.validate(validationQuery, validationQueryTimeoutDuration);
}
private void validateLifetime(final PooledObject<PoolableConnection> p) throws Exception {
- if (maxConnLifetimeMillis > 0) {
- final long lifetime = System.currentTimeMillis() - p.getCreateTime();
- if (lifetime > maxConnLifetimeMillis) {
- throw new LifetimeExceededException(Utils.getMessage("connectionFactory.lifetimeExceeded",
- Long.valueOf(lifetime), Long.valueOf(maxConnLifetimeMillis)));
+ if (maxConnDuration.compareTo(Duration.ZERO) > 0) {
+ final Duration lifetimeDuration = Duration.between(p.getCreateInstant(), Instant.now());
+ if (lifetimeDuration.compareTo(maxConnDuration) > 0) {
+ throw new LifetimeExceededException(Utils.getMessage("connectionFactory.lifetimeExceeded", lifetimeDuration, maxConnDuration));
}
}
}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnectionMXBean.java b/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnectionMXBean.java
index eaa9fdd..75db37d 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnectionMXBean.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnectionMXBean.java
@@ -24,47 +24,47 @@ import java.sql.SQLException;
* @since 2.0
*/
public interface PoolableConnectionMXBean {
- // Read-only properties
- boolean isClosed() throws SQLException;
+ // Methods
+ void clearCachedState();
- // SQLWarning getWarnings() throws SQLException;
- String getToString();
+ void clearWarnings() throws SQLException;
+
+ void close() throws SQLException;
// Read-write properties
boolean getAutoCommit() throws SQLException;
- void setAutoCommit(boolean autoCommit) throws SQLException;
-
boolean getCacheState();
- void setCacheState(boolean cacheState);
-
String getCatalog() throws SQLException;
- void setCatalog(String catalog) throws SQLException;
-
int getHoldability() throws SQLException;
- void setHoldability(int holdability) throws SQLException;
+ String getSchema() throws SQLException;
- boolean isReadOnly() throws SQLException;
+ // SQLWarning getWarnings() throws SQLException;
+ String getToString();
- void setReadOnly(boolean readOnly) throws SQLException;
+ int getTransactionIsolation() throws SQLException;
- String getSchema() throws SQLException;
+ // Read-only properties
+ boolean isClosed() throws SQLException;
- void setSchema(String schema) throws SQLException;
+ boolean isReadOnly() throws SQLException;
- int getTransactionIsolation() throws SQLException;
+ void reallyClose() throws SQLException;
- void setTransactionIsolation(int level) throws SQLException;
+ void setAutoCommit(boolean autoCommit) throws SQLException;
- // Methods
- void clearCachedState();
+ void setCacheState(boolean cacheState);
- void clearWarnings() throws SQLException;
+ void setCatalog(String catalog) throws SQLException;
- void close() throws SQLException;
+ void setHoldability(int holdability) throws SQLException;
- void reallyClose() throws SQLException;
+ void setReadOnly(boolean readOnly) throws SQLException;
+
+ void setSchema(String schema) throws SQLException;
+
+ void setTransactionIsolation(int level) throws SQLException;
}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/PoolablePreparedStatement.java b/java/org/apache/tomcat/dbcp/dbcp2/PoolablePreparedStatement.java
index 32b63aa..4cedf14 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/PoolablePreparedStatement.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/PoolablePreparedStatement.java
@@ -49,7 +49,7 @@ public class PoolablePreparedStatement<K> extends DelegatingPreparedStatement {
*/
private final K key;
- private volatile boolean batchAdded = false;
+ private volatile boolean batchAdded;
/**
* Constructor.
@@ -74,6 +74,15 @@ public class PoolablePreparedStatement<K> extends DelegatingPreparedStatement {
removeThisTrace(getConnectionInternal());
}
+ @Override
+ public void activate() throws SQLException {
+ setClosedInternal(false);
+ if (getConnectionInternal() != null) {
+ getConnectionInternal().addTrace(this);
+ }
+ super.activate();
+ }
+
/**
* Add batch.
*/
@@ -110,15 +119,6 @@ public class PoolablePreparedStatement<K> extends DelegatingPreparedStatement {
}
@Override
- public void activate() throws SQLException {
- setClosedInternal(false);
- if (getConnectionInternal() != null) {
- getConnectionInternal().addTrace(this);
- }
- super.activate();
- }
-
- @Override
public void passivate() throws SQLException {
// DBCP-372. clearBatch with throw an exception if called when the
// connection is marked as closed.
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/PoolingConnection.java b/java/org/apache/tomcat/dbcp/dbcp2/PoolingConnection.java
index 4f98039..6586a49 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/PoolingConnection.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/PoolingConnection.java
@@ -64,7 +64,7 @@ public class PoolingConnection extends DelegatingConnection<Connection>
/** Pool of {@link PreparedStatement}s. and {@link CallableStatement}s */
private KeyedObjectPool<PStmtKey, DelegatingPreparedStatement> pstmtPool;
- private boolean clearStatementPoolOnReturn = false;
+ private boolean clearStatementPoolOnReturn;
/**
* Constructor.
@@ -151,21 +151,6 @@ public class PoolingConnection extends DelegatingConnection<Connection>
*
* @param sql
* the SQL string used to define the statement
- * @param columnIndexes
- * An array of column indexes indicating the columns that should be returned from the inserted row or
- * rows.
- *
- * @return the PStmtKey created for the given arguments.
- */
- protected PStmtKey createKey(final String sql, final int[] columnIndexes) {
- return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull(), columnIndexes);
- }
-
- /**
- * Creates a PStmtKey for the given arguments.
- *
- * @param sql
- * the SQL string used to define the statement
* @param autoGeneratedKeys
* A flag indicating whether auto-generated keys should be returned; one of
* <code>Statement.RETURN_GENERATED_KEYS</code> or <code>Statement.NO_GENERATED_KEYS</code>.
@@ -258,6 +243,21 @@ public class PoolingConnection extends DelegatingConnection<Connection>
*
* @param sql
* the SQL string used to define the statement
+ * @param columnIndexes
+ * An array of column indexes indicating the columns that should be returned from the inserted row or
+ * rows.
+ *
+ * @return the PStmtKey created for the given arguments.
+ */
+ protected PStmtKey createKey(final String sql, final int[] columnIndexes) {
+ return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull(), columnIndexes);
+ }
+
+ /**
+ * Creates a PStmtKey for the given arguments.
+ *
+ * @param sql
+ * the SQL string used to define the statement
* @param statementType
* statement type
*
@@ -507,24 +507,6 @@ public class PoolingConnection extends DelegatingConnection<Connection>
*
* @param sql
* the SQL string used to define the PreparedStatement
- * @param columnIndexes
- * An array of column indexes indicating the columns that should be returned from the inserted row or
- * rows.
- * @return a {@link PoolablePreparedStatement}
- * @throws SQLException
- * Wraps an underlying exception.
- *
- */
- @Override
- public PreparedStatement prepareStatement(final String sql, final int[] columnIndexes) throws SQLException {
- return prepareStatement(createKey(sql, columnIndexes));
- }
-
- /**
- * Creates or obtains a {@link PreparedStatement} from the pool.
- *
- * @param sql
- * the SQL string used to define the PreparedStatement
* @param resultSetType
* result set type
* @param resultSetConcurrency
@@ -565,6 +547,24 @@ public class PoolingConnection extends DelegatingConnection<Connection>
*
* @param sql
* the SQL string used to define the PreparedStatement
+ * @param columnIndexes
+ * An array of column indexes indicating the columns that should be returned from the inserted row or
+ * rows.
+ * @return a {@link PoolablePreparedStatement}
+ * @throws SQLException
+ * Wraps an underlying exception.
+ *
+ */
+ @Override
+ public PreparedStatement prepareStatement(final String sql, final int[] columnIndexes) throws SQLException {
+ return prepareStatement(createKey(sql, columnIndexes));
+ }
+
+ /**
+ * Creates or obtains a {@link PreparedStatement} from the pool.
+ *
+ * @param sql
+ * the SQL string used to define the PreparedStatement
* @param columnNames
* column names
* @return a {@link PoolablePreparedStatement}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/PoolingDataSource.java b/java/org/apache/tomcat/dbcp/dbcp2/PoolingDataSource.java
index 5f0ca20..f11e1df 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/PoolingDataSource.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/PoolingDataSource.java
@@ -41,11 +41,57 @@ import org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool;
*/
public class PoolingDataSource<C extends Connection> implements DataSource, AutoCloseable {
+ /**
+ * PoolGuardConnectionWrapper is a Connection wrapper that makes sure a closed connection cannot be used anymore.
+ *
+ * @since 2.0
+ */
+ private class PoolGuardConnectionWrapper<D extends Connection> extends DelegatingConnection<D> {
+
+ PoolGuardConnectionWrapper(final D delegate) {
+ super(delegate);
+ }
+
+ @Override
+ public void close() throws SQLException {
+ if (getDelegateInternal() != null) {
+ super.close();
+ super.setDelegate(null);
+ }
+ }
+
+ /**
+ * @see org.apache.tomcat.dbcp.dbcp2.DelegatingConnection#getDelegate()
+ */
+ @Override
+ public D getDelegate() {
+ return isAccessToUnderlyingConnectionAllowed() ? super.getDelegate() : null;
+ }
+
+ /**
+ * @see org.apache.tomcat.dbcp.dbcp2.DelegatingConnection#getInnermostDelegate()
+ */
+ @Override
+ public Connection getInnermostDelegate() {
+ return isAccessToUnderlyingConnectionAllowed() ? super.getInnermostDelegate() : null;
+ }
+
+ @Override
+ public boolean isClosed() throws SQLException {
+ return getDelegateInternal() == null || super.isClosed();
+ }
+ }
+
private static final Log log = LogFactory.getLog(PoolingDataSource.class);
/** Controls access to the underlying connection */
private boolean accessToUnderlyingConnectionAllowed;
+ /** My log writer. */
+ private PrintWriter logWriter;
+
+ private final ObjectPool<C> pool;
+
/**
* Constructs a new instance backed by the given connection pool.
*
@@ -86,45 +132,6 @@ public class PoolingDataSource<C extends Connection> implements DataSource, Auto
}
/**
- * Returns the value of the accessToUnderlyingConnectionAllowed property.
- *
- * @return true if access to the underlying {@link Connection} is allowed, false otherwise.
- */
- public boolean isAccessToUnderlyingConnectionAllowed() {
- return this.accessToUnderlyingConnectionAllowed;
- }
-
- /**
- * Sets the value of the accessToUnderlyingConnectionAllowed property. It controls if the PoolGuard allows access to
- * the underlying connection. (Default: false)
- *
- * @param allow
- * Access to the underlying connection is granted when true.
- */
- public void setAccessToUnderlyingConnectionAllowed(final boolean allow) {
- this.accessToUnderlyingConnectionAllowed = allow;
- }
-
- /* JDBC_4_ANT_KEY_BEGIN */
- @Override
- public boolean isWrapperFor(final Class<?> iface) throws SQLException {
- return false;
- }
-
- @Override
- public <T> T unwrap(final Class<T> iface) throws SQLException {
- throw new SQLException("PoolingDataSource is not a wrapper.");
- }
- /* JDBC_4_ANT_KEY_END */
-
- @Override
- public Logger getParentLogger() throws SQLFeatureNotSupportedException {
- throw new SQLFeatureNotSupportedException();
- }
-
- // --- DataSource methods -----------------------------------------
-
- /**
* Returns a {@link java.sql.Connection} from my pool, according to the contract specified by
* {@link ObjectPool#borrowObject}.
*/
@@ -160,6 +167,19 @@ public class PoolingDataSource<C extends Connection> implements DataSource, Auto
throw new UnsupportedOperationException();
}
+ // --- DataSource methods -----------------------------------------
+
+ /**
+ * Throws {@link UnsupportedOperationException}.
+ *
+ * @throws UnsupportedOperationException
+ * As this implementation does not support this feature.
+ */
+ @Override
+ public int getLoginTimeout() {
+ throw new UnsupportedOperationException("Login timeout is not supported.");
+ }
+
/**
* Returns my log writer.
*
@@ -171,15 +191,38 @@ public class PoolingDataSource<C extends Connection> implements DataSource, Auto
return logWriter;
}
+ @Override
+ public Logger getParentLogger() throws SQLFeatureNotSupportedException {
+ throw new SQLFeatureNotSupportedException();
+ }
+
+ protected ObjectPool<C> getPool() {
+ return pool;
+ }
+
/**
- * Throws {@link UnsupportedOperationException}.
+ * Returns the value of the accessToUnderlyingConnectionAllowed property.
*
- * @throws UnsupportedOperationException
- * As this implementation does not support this feature.
+ * @return true if access to the underlying {@link Connection} is allowed, false otherwise.
*/
+ public boolean isAccessToUnderlyingConnectionAllowed() {
+ return this.accessToUnderlyingConnectionAllowed;
+ }
+
@Override
- public int getLoginTimeout() {
- throw new UnsupportedOperationException("Login timeout is not supported.");
+ public boolean isWrapperFor(final Class<?> iface) throws SQLException {
+ return iface != null && iface.isInstance(this);
+ }
+
+ /**
+ * Sets the value of the accessToUnderlyingConnectionAllowed property. It controls if the PoolGuard allows access to
+ * the underlying connection. (Default: false)
+ *
+ * @param allow
+ * Access to the underlying connection is granted when true.
+ */
+ public void setAccessToUnderlyingConnectionAllowed(final boolean allow) {
+ this.accessToUnderlyingConnectionAllowed = allow;
}
/**
@@ -203,53 +246,11 @@ public class PoolingDataSource<C extends Connection> implements DataSource, Auto
logWriter = out;
}
- /** My log writer. */
- private PrintWriter logWriter = null;
-
- private final ObjectPool<C> pool;
-
- protected ObjectPool<C> getPool() {
- return pool;
- }
-
- /**
- * PoolGuardConnectionWrapper is a Connection wrapper that makes sure a closed connection cannot be used anymore.
- *
- * @since 2.0
- */
- private class PoolGuardConnectionWrapper<D extends Connection> extends DelegatingConnection<D> {
-
- PoolGuardConnectionWrapper(final D delegate) {
- super(delegate);
- }
-
- /**
- * @see org.apache.tomcat.dbcp.dbcp2.DelegatingConnection#getDelegate()
- */
- @Override
- public D getDelegate() {
- return isAccessToUnderlyingConnectionAllowed() ? super.getDelegate() : null;
- }
-
- /**
- * @see org.apache.tomcat.dbcp.dbcp2.DelegatingConnection#getInnermostDelegate()
- */
- @Override
- public Connection getInnermostDelegate() {
- return isAccessToUnderlyingConnectionAllowed() ? super.getInnermostDelegate() : null;
- }
-
- @Override
- public void close() throws SQLException {
- if (getDelegateInternal() != null) {
- super.close();
- super.setDelegate(null);
- }
- }
-
- @Override
- public boolean isClosed() throws SQLException {
- return getDelegateInternal() == null ? true : super.isClosed();
+ @Override
+ public <T> T unwrap(final Class<T> iface) throws SQLException {
+ if (isWrapperFor(iface)) {
+ return iface.cast(this);
}
+ throw new SQLException(this + " is not a wrapper for " + iface);
}
}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/PoolingDriver.java b/java/org/apache/tomcat/dbcp/dbcp2/PoolingDriver.java
index 67b4c4d..5f793f8 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/PoolingDriver.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/PoolingDriver.java
@@ -36,7 +36,44 @@ import org.apache.tomcat.dbcp.pool2.ObjectPool;
*/
public class PoolingDriver implements Driver {
- private static final DriverPropertyInfo[] EMPTY_DRIVER_PROPERTY_INFO_ARRAY = new DriverPropertyInfo[0];
+ /**
+ * PoolGuardConnectionWrapper is a Connection wrapper that makes sure a closed connection cannot be used anymore.
+ *
+ * @since 2.0
+ */
+ private class PoolGuardConnectionWrapper extends DelegatingConnection<Connection> {
+
+ private final ObjectPool<? extends Connection> pool;
+
+ PoolGuardConnectionWrapper(final ObjectPool<? extends Connection> pool, final Connection delegate) {
+ super(delegate);
+ this.pool = pool;
+ }
+
+ /**
+ * @see org.apache.tomcat.dbcp.dbcp2.DelegatingConnection#getDelegate()
+ */
+ @Override
+ public Connection getDelegate() {
+ if (isAccessToUnderlyingConnectionAllowed()) {
+ return super.getDelegate();
+ }
+ return null;
+ }
+
+ /**
+ * @see org.apache.tomcat.dbcp.dbcp2.DelegatingConnection#getInnermostDelegate()
+ */
+ @Override
+ public Connection getInnermostDelegate() {
+ if (isAccessToUnderlyingConnectionAllowed()) {
+ return super.getInnermostDelegate();
+ }
+ return null;
+ }
+ }
+
+ private static final DriverPropertyInfo[] EMPTY_DRIVER_PROPERTY_INFO_ARRAY = {};
/* Register myself with the {@link DriverManager}. */
static {
@@ -50,6 +87,16 @@ public class PoolingDriver implements Driver {
/** The map of registered pools. */
protected static final HashMap<String, ObjectPool<? extends Connection>> pools = new HashMap<>();
+ /** My URL prefix */
+ public static final String URL_PREFIX = "jdbc:apache:commons:dbcp:";
+
+ protected static final int URL_PREFIX_LEN = URL_PREFIX.length();
+
+ // version numbers
+ protected static final int MAJOR_VERSION = 1;
+
+ protected static final int MINOR_VERSION = 0;
+
/** Controls access to the underlying connection */
private final boolean accessToUnderlyingConnectionAllowed;
@@ -70,42 +117,9 @@ public class PoolingDriver implements Driver {
this.accessToUnderlyingConnectionAllowed = accessToUnderlyingConnectionAllowed;
}
- /**
- * Returns the value of the accessToUnderlyingConnectionAllowed property.
- *
- * @return true if access to the underlying is allowed, false otherwise.
- */
- protected boolean isAccessToUnderlyingConnectionAllowed() {
- return accessToUnderlyingConnectionAllowed;
- }
-
- /**
- * Gets the connection pool for the given name.
- *
- * @param name
- * The pool name
- * @return The pool
- * @throws SQLException
- * Thrown when the named pool is not registered.
- */
- public synchronized ObjectPool<? extends Connection> getConnectionPool(final String name) throws SQLException {
- final ObjectPool<? extends Connection> pool = pools.get(name);
- if (null == pool) {
- throw new SQLException("Pool not registered: " + name);
- }
- return pool;
- }
-
- /**
- * Registers a named pool.
- *
- * @param name
- * The pool name.
- * @param pool
- * The pool.
- */
- public synchronized void registerPool(final String name, final ObjectPool<? extends Connection> pool) {
- pools.put(name, pool);
+ @Override
+ public boolean acceptsURL(final String url) throws SQLException {
+ return url != null && url.startsWith(URL_PREFIX);
}
/**
@@ -128,20 +142,6 @@ public class PoolingDriver implements Driver {
}
}
- /**
- * Gets the pool names.
- *
- * @return the pool names.
- */
- public synchronized String[] getPoolNames() {
- return pools.keySet().toArray(Utils.EMPTY_STRING_ARRAY);
- }
-
- @Override
- public boolean acceptsURL(final String url) throws SQLException {
- return url != null && url.startsWith(URL_PREFIX);
- }
-
@Override
public Connection connect(final String url, final Properties info) throws SQLException {
if (acceptsURL(url)) {
@@ -164,33 +164,21 @@ public class PoolingDriver implements Driver {
return null;
}
- @Override
- public Logger getParentLogger() throws SQLFeatureNotSupportedException {
- throw new SQLFeatureNotSupportedException();
- }
-
/**
- * Invalidates the given connection.
+ * Gets the connection pool for the given name.
*
- * @param conn
- * connection to invalidate
+ * @param name
+ * The pool name
+ * @return The pool
* @throws SQLException
- * if the connection is not a <code>PoolGuardConnectionWrapper</code> or an error occurs invalidating
- * the connection
+ * Thrown when the named pool is not registered.
*/
- public void invalidateConnection(final Connection conn) throws SQLException {
- if (conn instanceof PoolGuardConnectionWrapper) { // normal case
- final PoolGuardConnectionWrapper pgconn = (PoolGuardConnectionWrapper) conn;
- @SuppressWarnings("unchecked")
- final ObjectPool<Connection> pool = (ObjectPool<Connection>) pgconn.pool;
- try {
- pool.invalidateObject(pgconn.getDelegateInternal());
- } catch (final Exception e) {
- // Ignore.
- }
- } else {
- throw new SQLException("Invalid connection class");
+ public synchronized ObjectPool<? extends Connection> getConnectionPool(final String name) throws SQLException {
+ final ObjectPool<? extends Connection> pool = pools.get(name);
+ if (null == pool) {
+ throw new SQLException("Pool not registered: " + name);
}
+ return pool;
}
@Override
@@ -204,57 +192,68 @@ public class PoolingDriver implements Driver {
}
@Override
- public boolean jdbcCompliant() {
- return true;
+ public Logger getParentLogger() throws SQLFeatureNotSupportedException {
+ throw new SQLFeatureNotSupportedException();
+ }
+
+ /**
+ * Gets the pool names.
+ *
+ * @return the pool names.
+ */
+ public synchronized String[] getPoolNames() {
+ return pools.keySet().toArray(Utils.EMPTY_STRING_ARRAY);
}
@Override
public DriverPropertyInfo[] getPropertyInfo(final String url, final Properties info) {
return EMPTY_DRIVER_PROPERTY_INFO_ARRAY;
}
-
- /** My URL prefix */
- public static final String URL_PREFIX = "jdbc:apache:commons:dbcp:";
- protected static final int URL_PREFIX_LEN = URL_PREFIX.length();
-
- // version numbers
- protected static final int MAJOR_VERSION = 1;
- protected static final int MINOR_VERSION = 0;
-
/**
- * PoolGuardConnectionWrapper is a Connection wrapper that makes sure a closed connection cannot be used anymore.
+ * Invalidates the given connection.
*
- * @since 2.0
+ * @param conn
+ * connection to invalidate
+ * @throws SQLException
+ * if the connection is not a <code>PoolGuardConnectionWrapper</code> or an error occurs invalidating
+ * the connection
*/
- private class PoolGuardConnectionWrapper extends DelegatingConnection<Connection> {
-
- private final ObjectPool<? extends Connection> pool;
-
- PoolGuardConnectionWrapper(final ObjectPool<? extends Connection> pool, final Connection delegate) {
- super(delegate);
- this.pool = pool;
+ public void invalidateConnection(final Connection conn) throws SQLException {
+ if (!(conn instanceof PoolGuardConnectionWrapper)) {
+ throw new SQLException("Invalid connection class");
}
-
- /**
- * @see org.apache.tomcat.dbcp.dbcp2.DelegatingConnection#getDelegate()
- */
- @Override
- public Connection getDelegate() {
- if (isAccessToUnderlyingConnectionAllowed()) {
- return super.getDelegate();
- }
- return null;
+ final PoolGuardConnectionWrapper pgconn = (PoolGuardConnectionWrapper) conn;
+ @SuppressWarnings("unchecked")
+ final ObjectPool<Connection> pool = (ObjectPool<Connection>) pgconn.pool;
+ try {
+ pool.invalidateObject(pgconn.getDelegateInternal());
+ } catch (final Exception e) {
+ // Ignore.
}
+ }
- /**
- * @see org.apache.tomcat.dbcp.dbcp2.DelegatingConnection#getInnermostDelegate()
- */
- @Override
- public Connection getInnermostDelegate() {
- if (isAccessToUnderlyingConnectionAllowed()) {
- return super.getInnermostDelegate();
- }
- return null;
- }
+ /**
+ * Returns the value of the accessToUnderlyingConnectionAllowed property.
+ *
+ * @return true if access to the underlying is allowed, false otherwise.
+ */
+ protected boolean isAccessToUnderlyingConnectionAllowed() {
+ return accessToUnderlyingConnectionAllowed;
+ }
+ @Override
+ public boolean jdbcCompliant() {
+ return true;
+ }
+
+ /**
+ * Registers a named pool.
+ *
+ * @param name
+ * The pool name.
+ * @param pool
+ * The pool.
+ */
+ public synchronized void registerPool(final String name, final ObjectPool<? extends Connection> pool) {
+ pools.put(name, pool);
}
}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/Utils.java b/java/org/apache/tomcat/dbcp/dbcp2/Utils.java
index c0ebadb..d4c4aa7 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/Utils.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/Utils.java
@@ -17,7 +17,9 @@
*/
package org.apache.tomcat.dbcp.dbcp2;
+import java.sql.Connection;
import java.sql.ResultSet;
+import java.sql.Statement;
import java.text.MessageFormat;
import java.util.HashSet;
import java.util.Properties;
@@ -36,8 +38,11 @@ public final class Utils {
/**
* Whether the security manager is enabled.
+ *
+ * @deprecated No replacement.
*/
- public static final boolean IS_SECURITY_ENABLED = System.getSecurityManager() != null;
+ @Deprecated
+ public static final boolean IS_SECURITY_ENABLED = isSecurityEnabled();
/** Any SQL_STATE starting with this value is considered a fatal disconnect */
public static final String DISCONNECTION_SQL_CODE_PREFIX = "08";
@@ -55,9 +60,9 @@ public final class Utils {
*/
public static final Set<String> DISCONNECTION_SQL_CODES;
- static final ResultSet[] EMPTY_RESULT_SET_ARRAY = new ResultSet[0];
- static final String[] EMPTY_STRING_ARRAY = new String[0];
+ static final ResultSet[] EMPTY_RESULT_SET_ARRAY = {};
+ static final String[] EMPTY_STRING_ARRAY = {};
static {
DISCONNECTION_SQL_CODES = new HashSet<>();
DISCONNECTION_SQL_CODES.add("57P01"); // Admin shutdown
@@ -88,8 +93,8 @@ public final class Utils {
public static Properties cloneWithoutCredentials(final Properties properties) {
if (properties != null) {
final Properties temp = (Properties) properties.clone();
- temp.remove("user");
- temp.remove("password");
+ temp.remove(Constants.KEY_USER);
+ temp.remove(Constants.KEY_PASSWORD);
return temp;
}
return properties;
@@ -112,6 +117,39 @@ public final class Utils {
}
/**
+ * Closes the Connection (which may be null).
+ *
+ * @param connection a Connection, may be {@code null}
+ * @deprecated Use {@link #closeQuietly(AutoCloseable)}.
+ */
+ @Deprecated
+ public static void closeQuietly(final Connection connection) {
+ closeQuietly((AutoCloseable) connection);
+ }
+
+ /**
+ * Closes the ResultSet (which may be null).
+ *
+ * @param resultSet a ResultSet, may be {@code null}
+ * @deprecated Use {@link #closeQuietly(AutoCloseable)}.
+ */
+ @Deprecated
+ public static void closeQuietly(final ResultSet resultSet) {
+ closeQuietly((AutoCloseable) resultSet);
+ }
+
+ /**
+ * Closes the Statement (which may be null).
+ *
+ * @param statement a Statement, may be {@code null}.
+ * @deprecated Use {@link #closeQuietly(AutoCloseable)}.
+ */
+ @Deprecated
+ public static void closeQuietly(final Statement statement) {
+ closeQuietly((AutoCloseable) statement);
+ }
+
+ /**
* Gets the correct i18n message for the given key.
*
* @param key The key to look up an i18n message.
@@ -137,6 +175,10 @@ public final class Utils {
return mf.format(args, new StringBuffer(), null).toString();
}
+ static boolean isSecurityEnabled() {
+ return System.getSecurityManager() != null;
+ }
+
/**
* Converts the given String to a char[].
*
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/ConnectionImpl.java b/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/ConnectionImpl.java
index 7cde269..9c820a3 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/ConnectionImpl.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/ConnectionImpl.java
@@ -84,6 +84,44 @@ class ConnectionImpl extends DelegatingConnection<Connection> {
}
/**
+ * Get the delegated connection, if allowed.
+ *
+ * @return the internal connection, or null if access is not allowed.
+ * @see #isAccessToUnderlyingConnectionAllowed()
+ */
+ @Override
+ public Connection getDelegate() {
+ if (isAccessToUnderlyingConnectionAllowed()) {
+ return getDelegateInternal();
+ }
+ return null;
+ }
+
+ /**
+ * Get the innermost connection, if allowed.
+ *
+ * @return the innermost internal connection, or null if access is not allowed.
+ * @see #isAccessToUnderlyingConnectionAllowed()
+ */
+ @Override
+ public Connection getInnermostDelegate() {
+ if (isAccessToUnderlyingConnectionAllowed()) {
+ return super.getInnermostDelegateInternal();
+ }
+ return null;
+ }
+
+ /**
+ * If false, getDelegate() and getInnermostDelegate() will return null.
+ *
+ * @return true if access is allowed to the underlying connection
+ * @see ConnectionImpl
+ */
+ public boolean isAccessToUnderlyingConnectionAllowed() {
+ return accessToUnderlyingConnectionAllowed;
+ }
+
+ /**
* If pooling of <code>CallableStatement</code>s is turned on in the {@link DriverAdapterCPDS}, a pooled object may
* be returned, otherwise delegate to the wrapped JDBC 1.x {@link java.sql.Connection}.
*
@@ -196,6 +234,17 @@ class ConnectionImpl extends DelegatingConnection<Connection> {
}
}
+ @Override
+ public PreparedStatement prepareStatement(final String sql, final int autoGeneratedKeys) throws SQLException {
+ checkOpen();
+ try {
+ return new DelegatingPreparedStatement(this, pooledConnection.prepareStatement(sql, autoGeneratedKeys));
+ } catch (final SQLException e) {
+ handleException(e);
+ return null;
+ }
+ }
+
/**
* If pooling of <code>PreparedStatement</code>s is turned on in the {@link DriverAdapterCPDS}, a pooled object may
* be returned, otherwise delegate to the wrapped JDBC 1.x {@link java.sql.Connection}.
@@ -216,6 +265,10 @@ 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 {
@@ -230,17 +283,6 @@ class ConnectionImpl extends DelegatingConnection<Connection> {
}
@Override
- public PreparedStatement prepareStatement(final String sql, final int autoGeneratedKeys) throws SQLException {
- checkOpen();
- try {
- return new DelegatingPreparedStatement(this, pooledConnection.prepareStatement(sql, autoGeneratedKeys));
- } catch (final SQLException e) {
- handleException(e);
- return null;
- }
- }
-
- @Override
public PreparedStatement prepareStatement(final String sql, final int[] columnIndexes) throws SQLException {
checkOpen();
try {
@@ -262,46 +304,4 @@ class ConnectionImpl extends DelegatingConnection<Connection> {
}
}
- //
- // Methods for accessing the delegate connection
- //
-
- /**
- * If false, getDelegate() and getInnermostDelegate() will return null.
- *
- * @return true if access is allowed to the underlying connection
- * @see ConnectionImpl
- */
- public boolean isAccessToUnderlyingConnectionAllowed() {
- return accessToUnderlyingConnectionAllowed;
- }
-
- /**
- * Get the delegated connection, if allowed.
- *
- * @return the internal connection, or null if access is not allowed.
- * @see #isAccessToUnderlyingConnectionAllowed()
- */
- @Override
- public Connection getDelegate() {
- if (isAccessToUnderlyingConnectionAllowed()) {
- return getDelegateInternal();
- }
- return null;
- }
-
- /**
- * Get the innermost connection, if allowed.
- *
- * @return the innermost internal connection, or null if access is not allowed.
- * @see #isAccessToUnderlyingConnectionAllowed()
- */
- @Override
- public Connection getInnermostDelegate() {
- if (isAccessToUnderlyingConnectionAllowed()) {
- return super.getInnermostDelegateInternal();
- }
- return null;
- }
-
}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java b/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java
index 399114f..ff50366 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java
@@ -21,6 +21,7 @@ import java.io.Serializable;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
+import java.time.Duration;
import java.util.Hashtable;
import java.util.Properties;
import java.util.logging.Logger;
@@ -37,6 +38,7 @@ import javax.sql.ConnectionPoolDataSource;
import javax.sql.PooledConnection;
import org.apache.tomcat.dbcp.dbcp2.BasicDataSource;
+import org.apache.tomcat.dbcp.dbcp2.Constants;
import org.apache.tomcat.dbcp.dbcp2.DelegatingPreparedStatement;
import org.apache.tomcat.dbcp.dbcp2.PStmtKey;
import org.apache.tomcat.dbcp.dbcp2.Utils;
@@ -77,10 +79,6 @@ import org.apache.tomcat.dbcp.pool2.impl.GenericKeyedObjectPoolConfig;
*/
public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceable, Serializable, ObjectFactory {
- private static final String KEY_USER = "user";
-
- private static final String KEY_PASSWORD = "password";
-
private static final long serialVersionUID = -4820523787212147844L;
private static final String GET_CONNECTION_CALLED = "A PooledConnection was already requested from this source, "
@@ -111,12 +109,13 @@ public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceabl
/** Log stream. NOT USED */
private transient PrintWriter logWriter;
+
// PreparedStatement pool properties
private boolean poolPreparedStatements;
private int maxIdle = 10;
- private long timeBetweenEvictionRunsMillis = BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
+ private Duration durationBetweenEvictionRuns = BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS;
private int numTestsPerEvictionRun = -1;
- private int minEvictableIdleTimeMillis = -1;
+ private Duration minEvictableIdleDuration = BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_DURATION;
private int maxPreparedStatements = -1;
@@ -132,7 +131,7 @@ public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceabl
private boolean accessToUnderlyingConnectionAllowed;
/**
- * Default no-arg constructor for Serialization
+ * Default no-argument constructor for Serialization
*/
public DriverAdapterCPDS() {
}
@@ -160,8 +159,8 @@ public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceabl
}
/**
- * Gets the value of description. This property is here for use by the code which will deploy this datasource. It is
- * not used internally.
+ * Gets the value of description. This property is here for use by the code which will deploy this data source. It
+ * is not used internally.
*
* @return value of description, may be null.
* @see #setDescription(String)
@@ -179,6 +178,18 @@ public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceabl
return driver;
}
+ /**
+ * Gets the duration to sleep between runs of the idle object evictor thread. When non-positive, no
+ * idle object evictor thread will be run.
+ *
+ * @return the value of the evictor thread timer
+ * @see #setDurationBetweenEvictionRuns(Duration)
+ * @since 2.9.0
+ */
+ public Duration getDurationBetweenEvictionRuns() {
+ return durationBetweenEvictionRuns;
+ }
+
private int getIntegerStringContent(final RefAddr ra) {
return Integer.parseInt(getStringContent(ra));
}
@@ -207,7 +218,7 @@ public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceabl
* @return the value of maxIdle
*/
public int getMaxIdle() {
- return this.maxIdle;
+ return maxIdle;
}
/**
@@ -223,12 +234,27 @@ public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceabl
* Gets the minimum amount of time a statement may sit idle in the pool before it is eligible for eviction by the
* idle object evictor (if any).
*
+ * @see #setMinEvictableIdleDuration
+ * @see #setDurationBetweenEvictionRuns
+ * @return the minimum amount of time a statement may sit idle in the pool.
+ * @since 2.9.0
+ */
+ public Duration getMinEvictableIdleDuration() {
+ return minEvictableIdleDuration;
+ }
+
+ /**
+ * Gets the minimum amount of time a statement may sit idle in the pool before it is eligible for eviction by the
+ * idle object evictor (if any).
+ *
* @see #setMinEvictableIdleTimeMillis
* @see #setTimeBetweenEvictionRunsMillis
* @return the minimum amount of time a statement may sit idle in the pool.
+ * @deprecated USe {@link #getMinEvictableIdleDuration()}.
*/
+ @Deprecated
public int getMinEvictableIdleTimeMillis() {
- return minEvictableIdleTimeMillis;
+ return (int) minEvictableIdleDuration.toMillis();
}
/**
@@ -267,11 +293,11 @@ public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceabl
if (isNotEmpty(ra)) {
setUrl(getStringContent(ra));
}
- ra = ref.get(KEY_USER);
+ ra = ref.get(Constants.KEY_USER);
if (isNotEmpty(ra)) {
setUser(getStringContent(ra));
}
- ra = ref.get(KEY_PASSWORD);
+ ra = ref.get(Constants.KEY_PASSWORD);
if (isNotEmpty(ra)) {
setPassword(getStringContent(ra));
}
@@ -299,6 +325,7 @@ public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceabl
if (isNotEmpty(ra)) {
setMinEvictableIdleTimeMillis(getIntegerStringContent(ra));
}
+
ra = ref.get("maxPreparedStatements");
if (isNotEmpty(ra)) {
setMaxPreparedStatements(getIntegerStringContent(ra));
@@ -336,7 +363,7 @@ public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceabl
* @since 2.4.0
*/
public char[] getPasswordCharArray() {
- return userPassword;
+ return userPassword == null ? null : userPassword.clone();
}
/**
@@ -358,11 +385,11 @@ public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceabl
throws SQLException {
getConnectionCalled = true;
PooledConnectionImpl pooledConnection = null;
- // Workaround for buggy WebLogic 5.1 classloader - ignore the exception upon first invocation.
+ // Workaround for buggy WebLogic 5.1 class loader - ignore the exception upon first invocation.
try {
if (connectionProperties != null) {
- update(connectionProperties, KEY_USER, pooledUserName);
- update(connectionProperties, KEY_PASSWORD, pooledUserPassword);
+ update(connectionProperties, Constants.KEY_USER, pooledUserName);
+ update(connectionProperties, Constants.KEY_PASSWORD, pooledUserPassword);
pooledConnection = new PooledConnectionImpl(
DriverManager.getConnection(getUrl(), connectionProperties));
} else {
@@ -385,22 +412,22 @@ public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceabl
final GenericKeyedObjectPoolConfig<DelegatingPreparedStatement> config = new GenericKeyedObjectPoolConfig<>();
config.setMaxTotalPerKey(Integer.MAX_VALUE);
config.setBlockWhenExhausted(false);
- config.setMaxWaitMillis(0);
+ config.setMaxWait(Duration.ZERO);
config.setMaxIdlePerKey(getMaxIdle());
if (getMaxPreparedStatements() <= 0) {
- // since there is no limit, create a prepared statement pool with an eviction thread;
+ // Since there is no limit, create a prepared statement pool with an eviction thread;
// evictor settings are the same as the connection pool settings.
- config.setTimeBetweenEvictionRunsMillis(getTimeBetweenEvictionRunsMillis());
+ config.setTimeBetweenEvictionRuns(getDurationBetweenEvictionRuns());
config.setNumTestsPerEvictionRun(getNumTestsPerEvictionRun());
- config.setMinEvictableIdleTimeMillis(getMinEvictableIdleTimeMillis());
+ config.setMinEvictableIdleTime(getMinEvictableIdleDuration());
} else {
- // since there is a limit, create a prepared statement pool without an eviction thread;
+ // Since there is a limit, create a prepared statement pool without an eviction thread;
// pool has LRU functionality so when the limit is reached, 15% of the pool is cleared.
// see org.apache.commons.pool2.impl.GenericKeyedObjectPool.clearOldest method
config.setMaxTotal(getMaxPreparedStatements());
- config.setTimeBetweenEvictionRunsMillis(-1);
+ config.setTimeBetweenEvictionRuns(Duration.ofMillis(-1));
config.setNumTestsPerEvictionRun(0);
- config.setMinEvictableIdleTimeMillis(0);
+ config.setMinEvictableIdleTime(Duration.ZERO);
}
stmtPool = new GenericKeyedObjectPool<>(pooledConnection, config);
pooledConnection.setStatementPool(stmtPool);
@@ -421,16 +448,22 @@ public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceabl
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_PASSWORD, getPassword()));
- ref.add(new StringRefAddr(KEY_USER, getUser()));
+ 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("poolPreparedStatements", String.valueOf(isPoolPreparedStatements())));
ref.add(new StringRefAddr("maxIdle", String.valueOf(getMaxIdle())));
- ref.add(new StringRefAddr("timeBetweenEvictionRunsMillis", String.valueOf(getTimeBetweenEvictionRunsMillis())));
ref.add(new StringRefAddr("numTestsPerEvictionRun", String.valueOf(getNumTestsPerEvictionRun())));
- ref.add(new StringRefAddr("minEvictableIdleTimeMillis", String.valueOf(getMinEvictableIdleTimeMillis())));
ref.add(new StringRefAddr("maxPreparedStatements", String.valueOf(getMaxPreparedStatements())));
+ //
+ // Pair of current and deprecated.
+ ref.add(new StringRefAddr("durationBetweenEvictionRuns", String.valueOf(getDurationBetweenEvictionRuns())));
+ ref.add(new StringRefAddr("timeBetweenEvictionRunsMillis", String.valueOf(getTimeBetweenEvictionRunsMillis())));
+ //
+ // Pair of current and deprecated.
+ ref.add(new StringRefAddr("minEvictableIdleDuration", String.valueOf(getMinEvictableIdleDuration())));
+ ref.add(new StringRefAddr("minEvictableIdleTimeMillis", String.valueOf(getMinEvictableIdleTimeMillis())));
return ref;
}
@@ -444,10 +477,12 @@ public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceabl
* idle object evictor thread will be run.
*
* @return the value of the evictor thread timer
- * @see #setTimeBetweenEvictionRunsMillis(long)
+ * @see #setDurationBetweenEvictionRuns(Duration)
+ * @deprecated Use {@link #getDurationBetweenEvictionRuns()}.
*/
+ @Deprecated
public long getTimeBetweenEvictionRunsMillis() {
- return timeBetweenEvictionRunsMillis;
+ return durationBetweenEvictionRuns.toMillis();
}
/**
@@ -518,11 +553,11 @@ public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceabl
assertInitializationAllowed();
connectionProperties = props;
if (connectionProperties != null) {
- if (connectionProperties.containsKey(KEY_USER)) {
- setUser(connectionProperties.getProperty(KEY_USER));
+ if (connectionProperties.containsKey(Constants.KEY_USER)) {
+ setUser(connectionProperties.getProperty(Constants.KEY_USER));
}
- if (connectionProperties.containsKey(KEY_PASSWORD)) {
- setPassword(connectionProperties.getProperty(KEY_PASSWORD));
+ if (connectionProperties.containsKey(Constants.KEY_PASSWORD)) {
+ setPassword(connectionProperties.getProperty(Constants.KEY_PASSWORD));
}
}
}
@@ -531,25 +566,40 @@ public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceabl
* Sets the value of description. This property is here for use by the code which will deploy this datasource. It is
* not used internally.
*
- * @param v Value to assign to description.
+ * @param description Value to assign to description.
*/
- public void setDescription(final String v) {
- this.description = v;
+ public void setDescription(final String description) {
+ this.description = description;
}
/**
* Sets the driver class name. Setting the driver class name cause the driver to be registered with the
* DriverManager.
*
- * @param v Value to assign to driver.
+ * @param driver Value to assign to driver.
* @throws IllegalStateException if {@link #getPooledConnection()} has been called
* @throws ClassNotFoundException if the class cannot be located
*/
- public void setDriver(final String v) throws ClassNotFoundException {
+ public void setDriver(final String driver) throws ClassNotFoundException {
assertInitializationAllowed();
- this.driver = v;
+ this.driver = driver;
// make sure driver is registered
- Class.forName(v);
+ Class.forName(driver);
+ }
+
+ /**
+ * Sets the duration to sleep between runs of the idle object evictor thread. When non-positive, no
+ * idle object evictor thread will be run.
+ *
+ * @param durationBetweenEvictionRuns The duration to sleep between runs of the idle object evictor
+ * thread. When non-positive, no idle object evictor thread will be run.
+ * @see #getDurationBetweenEvictionRuns()
+ * @throws IllegalStateException if {@link #getPooledConnection()} has been called
+ * @since 2.9.0
+ */
+ public void setDurationBetweenEvictionRuns(final Duration durationBetweenEvictionRuns) {
+ assertInitializationAllowed();
+ this.durationBetweenEvictionRuns = durationBetweenEvictionRuns;
}
/**
@@ -558,15 +608,15 @@ public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceabl
*/
@Override
public void setLoginTimeout(final int seconds) {
- loginTimeout = seconds;
+ this.loginTimeout = seconds;
}
/**
* Sets the log writer for this data source. NOT USED.
*/
@Override
- public void setLogWriter(final PrintWriter out) {
- logWriter = out;
+ public void setLogWriter(final PrintWriter logWriter) {
+ this.logWriter = logWriter;
}
/**
@@ -594,14 +644,31 @@ public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceabl
* Sets the minimum amount of time a statement may sit idle in the pool before it is eligible for eviction by the
* idle object evictor (if any). When non-positive, no objects will be evicted from the pool due to idle time alone.
*
- * @param minEvictableIdleTimeMillis minimum time to set (in ms)
- * @see #getMinEvictableIdleTimeMillis()
- * @see #setTimeBetweenEvictionRunsMillis(long)
+ * @param minEvictableIdleDuration minimum time to set in milliseconds.
+ * @see #getMinEvictableIdleDuration()
+ * @see #setDurationBetweenEvictionRuns(Duration)
+ * @throws IllegalStateException if {@link #getPooledConnection()} has been called.
+ * @since 2.9.0
+ */
+ public void setMinEvictableIdleDuration(final Duration minEvictableIdleDuration) {
+ assertInitializationAllowed();
+ this.minEvictableIdleDuration = minEvictableIdleDuration;
+ }
+
+ /**
+ * Sets the minimum amount of time a statement may sit idle in the pool before it is eligible for eviction by the
+ * idle object evictor (if any). When non-positive, no objects will be evicted from the pool due to idle time alone.
+ *
+ * @param minEvictableIdleTimeMillis minimum time to set in milliseconds.
+ * @see #getMinEvictableIdleDuration()
+ * @see #setDurationBetweenEvictionRuns(Duration)
* @throws IllegalStateException if {@link #getPooledConnection()} has been called
+ * @deprecated Use {@link #setMinEvictableIdleDuration(Duration)}.
*/
+ @Deprecated
public void setMinEvictableIdleTimeMillis(final int minEvictableIdleTimeMillis) {
assertInitializationAllowed();
- this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
+ this.minEvictableIdleDuration = Duration.ofMillis(minEvictableIdleTimeMillis);
}
/**
@@ -614,7 +681,7 @@ public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceabl
*
* @param numTestsPerEvictionRun number of statements to examine per run
* @see #getNumTestsPerEvictionRun()
- * @see #setTimeBetweenEvictionRunsMillis(long)
+ * @see #setDurationBetweenEvictionRuns(Duration)
* @throws IllegalStateException if {@link #getPooledConnection()} has been called
*/
public void setNumTestsPerEvictionRun(final int numTestsPerEvictionRun) {
@@ -631,7 +698,7 @@ public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceabl
public void setPassword(final char[] userPassword) {
assertInitializationAllowed();
this.userPassword = Utils.clone(userPassword);
- update(connectionProperties, KEY_PASSWORD, Utils.toString(this.userPassword));
+ update(connectionProperties, Constants.KEY_PASSWORD, Utils.toString(this.userPassword));
}
/**
@@ -643,7 +710,7 @@ public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceabl
public void setPassword(final String userPassword) {
assertInitializationAllowed();
this.userPassword = Utils.toCharArray(userPassword);
- update(connectionProperties, KEY_PASSWORD, userPassword);
+ update(connectionProperties, Constants.KEY_PASSWORD, userPassword);
}
/**
@@ -663,35 +730,37 @@ public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceabl
*
* @param timeBetweenEvictionRunsMillis The number of milliseconds to sleep between runs of the idle object evictor
* thread. When non-positive, no idle object evictor thread will be run.
- * @see #getTimeBetweenEvictionRunsMillis()
+ * @see #getDurationBetweenEvictionRuns()
* @throws IllegalStateException if {@link #getPooledConnection()} has been called
+ * @deprecated Use {@link #setDurationBetweenEvictionRuns(Duration)}.
*/
+ @Deprecated
public void setTimeBetweenEvictionRunsMillis(final long timeBetweenEvictionRunsMillis) {
assertInitializationAllowed();
- this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
+ this.durationBetweenEvictionRuns = Duration.ofMillis(timeBetweenEvictionRunsMillis);
}
/**
* Sets the value of URL string used to locate the database for this datasource.
*
- * @param v Value to assign to url.
+ * @param url Value to assign to url.
* @throws IllegalStateException if {@link #getPooledConnection()} has been called
*/
- public void setUrl(final String v) {
+ public void setUrl(final String url) {
assertInitializationAllowed();
- this.url = v;
+ this.url = url;
}
/**
* Sets the value of default user (login or user name).
*
- * @param v Value to assign to user.
+ * @param userName Value to assign to user.
* @throws IllegalStateException if {@link #getPooledConnection()} has been called
*/
- public void setUser(final String v) {
+ public void setUser(final String userName) {
assertInitializationAllowed();
- this.userName = v;
- update(connectionProperties, KEY_USER, v);
+ this.userName = userName;
+ update(connectionProperties, Constants.KEY_USER, userName);
}
/**
@@ -717,11 +786,11 @@ public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceabl
builder.append(", maxIdle=");
builder.append(maxIdle);
builder.append(", timeBetweenEvictionRunsMillis=");
- builder.append(timeBetweenEvictionRunsMillis);
+ builder.append(durationBetweenEvictionRuns);
builder.append(", numTestsPerEvictionRun=");
builder.append(numTestsPerEvictionRun);
builder.append(", minEvictableIdleTimeMillis=");
- builder.append(minEvictableIdleTimeMillis);
+ builder.append(minEvictableIdleDuration);
builder.append(", maxPreparedStatements=");
builder.append(maxPreparedStatements);
builder.append(", getConnectionCalled=");
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PooledConnectionImpl.java b/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PooledConnectionImpl.java
index 7069bc8..60dcc75 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PooledConnectionImpl.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PooledConnectionImpl.java
@@ -20,7 +20,9 @@ import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
-import java.util.Vector;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
import javax.sql.ConnectionEvent;
import javax.sql.ConnectionEventListener;
@@ -67,12 +69,12 @@ class PooledConnectionImpl
/**
* ConnectionEventListeners.
*/
- private final Vector<ConnectionEventListener> eventListeners;
+ private final List<ConnectionEventListener> eventListeners;
/**
* StatementEventListeners.
*/
- private final Vector<StatementEventListener> statementEventListeners = new Vector<>();
+ private final List<StatementEventListener> statementEventListeners = Collections.synchronizedList(new ArrayList<>());
/**
* Flag set to true, once {@link #close()} is called.
@@ -100,7 +102,7 @@ class PooledConnectionImpl
} else {
this.delegatingConnection = new DelegatingConnection<>(connection);
}
- eventListeners = new Vector<>();
+ eventListeners = Collections.synchronizedList(new ArrayList<>());
closed = false;
}
@@ -125,7 +127,6 @@ class PooledConnectionImpl
}
}
- /* JDBC_4_ANT_KEY_BEGIN */
@Override
public void addStatementEventListener(final StatementEventListener listener) {
if (!statementEventListeners.contains(listener)) {
@@ -205,20 +206,6 @@ class PooledConnectionImpl
*
* @param sql
* The SQL statement.
- * @param columnIndexes
- * An array of column indexes indicating the columns that should be returned from the inserted row or
- * rows.
- * @return a key to uniquely identify a prepared statement.
- */
- protected PStmtKey createKey(final String sql, final int[] columnIndexes) {
- return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull(), columnIndexes);
- }
-
- /**
- * Creates a {@link PStmtKey} for the given arguments.
- *
- * @param sql
- * The SQL statement.
* @param resultSetType
* A result set type; one of <code>ResultSet.TYPE_FORWARD_ONLY</code>,
* <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>.
@@ -306,6 +293,20 @@ class PooledConnectionImpl
*
* @param sql
* The SQL statement.
+ * @param columnIndexes
+ * An array of column indexes indicating the columns that should be returned from the inserted row or
+ * rows.
+ * @return a key to uniquely identify a prepared statement.
+ */
+ protected PStmtKey createKey(final String sql, final int[] columnIndexes) {
+ return new PStmtKey(normalizeSQL(sql), getCatalogOrNull(), getSchemaOrNull(), columnIndexes);
+ }
+
+ /**
+ * Creates a {@link PStmtKey} for the given arguments.
+ *
+ * @param sql
+ * The SQL statement.
* @param statementType
* The SQL statement type, prepared or callable.
* @return a key to uniquely identify a prepared statement.
@@ -368,14 +369,6 @@ class PooledConnectionImpl
}
}
- private String getSchemaOrNull() {
- try {
- return connection == null ? null : Jdbc41Bridge.getSchema(connection);
- } catch (final SQLException e) {
- return null;
- }
- }
-
/**
* Returns a JDBC connection.
*
@@ -398,6 +391,14 @@ class PooledConnectionImpl
return logicalConnection;
}
+ private String getSchemaOrNull() {
+ try {
+ return connection == null ? null : Jdbc41Bridge.getSchema(connection);
+ } catch (final SQLException e) {
+ return null;
+ }
+ }
+
/**
* Returns the value of the accessToUnderlyingConnectionAllowed property.
*
@@ -612,19 +613,6 @@ class PooledConnectionImpl
}
}
- PreparedStatement prepareStatement(final String sql, final int[] columnIndexes) throws SQLException {
- if (pStmtPool == null) {
- return connection.prepareStatement(sql, columnIndexes);
- }
- try {
- return pStmtPool.borrowObject(createKey(sql, columnIndexes));
- } catch (final RuntimeException e) {
- throw e;
- } catch (final Exception e) {
- throw new SQLException("Borrow prepareStatement from pool failed", e);
- }
- }
-
/**
* Creates or obtains a {@link PreparedStatement} from my pool.
*
@@ -671,6 +659,19 @@ class PooledConnectionImpl
}
}
+ PreparedStatement prepareStatement(final String sql, final int[] columnIndexes) throws SQLException {
+ if (pStmtPool == null) {
+ return connection.prepareStatement(sql, columnIndexes);
+ }
+ try {
+ return pStmtPool.borrowObject(createKey(sql, columnIndexes));
+ } catch (final RuntimeException e) {
+ throw e;
+ } catch (final Exception e) {
+ throw new SQLException("Borrow prepareStatement from pool failed", e);
+ }
+ }
+
PreparedStatement prepareStatement(final String sql, final String[] columnNames) throws SQLException {
if (pStmtPool == null) {
return connection.prepareStatement(sql, columnNames);
@@ -692,7 +693,6 @@ class PooledConnectionImpl
eventListeners.remove(listener);
}
- /* JDBC_4_ANT_KEY_BEGIN */
@Override
public void removeStatementEventListener(final StatementEventListener listener) {
statementEventListeners.remove(listener);
@@ -715,20 +715,6 @@ class PooledConnectionImpl
}
/**
- * My {@link KeyedPooledObjectFactory} method for validating {@link PreparedStatement}s.
- *
- * @param key
- * Ignored.
- * @param pooledObject
- * Ignored.
- * @return {@code true}
- */
- @Override
- public boolean validateObject(final PStmtKey key, final PooledObject<DelegatingPreparedStatement> pooledObject) {
- return true;
- }
-
- /**
* @since 2.6.0
*/
@Override
@@ -753,4 +739,18 @@ class PooledConnectionImpl
builder.append("]");
return builder.toString();
}
+
+ /**
+ * My {@link KeyedPooledObjectFactory} method for validating {@link PreparedStatement}s.
+ *
+ * @param key
+ * Ignored.
+ * @param pooledObject
+ * Ignored.
+ * @return {@code true}
+ */
+ @Override
+ public boolean validateObject(final PStmtKey key, final PooledObject<DelegatingPreparedStatement> pooledObject) {
+ return true;
+ }
}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/datasources/CPDSConnectionFactory.java b/java/org/apache/tomcat/dbcp/dbcp2/datasources/CPDSConnectionFactory.java
index 311bad9..7ee9031 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/datasources/CPDSConnectionFactory.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/datasources/CPDSConnectionFactory.java
@@ -20,6 +20,8 @@ import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
+import java.time.Duration;
+import java.time.Instant;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
@@ -48,12 +50,11 @@ class CPDSConnectionFactory
private final ConnectionPoolDataSource cpds;
private final String validationQuery;
- private final int validationQueryTimeoutSeconds;
+ private final Duration validationQueryTimeoutDuration;
private final boolean rollbackAfterValidation;
private ObjectPool<PooledConnectionAndInfo> pool;
- private final String userName;
- private char[] userPassword;
- private long maxConnLifetimeMillis = -1;
+ private UserPassKey userPassKey;
+ private Duration maxConnDuration = Duration.ofMillis(-1);
/**
* Map of PooledConnections for which close events are ignored. Connections are muted when they are being validated.
@@ -74,24 +75,23 @@ class CPDSConnectionFactory
* a query to use to {@link #validateObject validate} {@link Connection}s. Should return at least one
* row. May be {@code null} in which case {@link Connection#isValid(int)} will be used to validate
* connections.
- * @param validationQueryTimeoutSeconds
- * Timeout in seconds before validation fails
+ * @param validationQueryTimeoutDuration
+ * Timeout Duration before validation fails
* @param rollbackAfterValidation
* whether a rollback should be issued after {@link #validateObject validating} {@link Connection}s.
* @param userName
* The user name to use to create connections
* @param userPassword
* The password to use to create connections
- * @since 2.4.0
+ * @since 2.10.0
*/
public CPDSConnectionFactory(final ConnectionPoolDataSource cpds, final String validationQuery,
- final int validationQueryTimeoutSeconds, final boolean rollbackAfterValidation, final String userName,
- final char[] userPassword) {
+ final Duration validationQueryTimeoutDuration, final boolean rollbackAfterValidation, final String userName,
+ final char[] userPassword) {
this.cpds = cpds;
this.validationQuery = validationQuery;
- this.validationQueryTimeoutSeconds = validationQueryTimeoutSeconds;
- this.userName = userName;
- this.userPassword = userPassword;
+ this.validationQueryTimeoutDuration = validationQueryTimeoutDuration;
+ this.userPassKey = new UserPassKey(userName, userPassword);
this.rollbackAfterValidation = rollbackAfterValidation;
}
@@ -104,7 +104,7 @@ class CPDSConnectionFactory
* a query to use to {@link #validateObject validate} {@link Connection}s. Should return at least one
* row. May be {@code null} in which case {@link Connection#isValid(int)} will be used to validate
* connections.
- * @param validationQueryTimeoutSeconds
+ * @param validationQueryTimeoutDuration
* Timeout in seconds before validation fails
* @param rollbackAfterValidation
* whether a rollback should be issued after {@link #validateObject validating} {@link Connection}s.
@@ -112,149 +112,92 @@ class CPDSConnectionFactory
* The user name to use to create connections
* @param userPassword
* The password to use to create connections
+ * @since 2.10.0
*/
- public CPDSConnectionFactory(final ConnectionPoolDataSource cpds, final String validationQuery,
- final int validationQueryTimeoutSeconds, final boolean rollbackAfterValidation, final String userName,
- final String userPassword) {
- this(cpds, validationQuery, validationQueryTimeoutSeconds, rollbackAfterValidation, userName,
- Utils.toCharArray(userPassword));
- }
-
- /**
- * (Testing API) Gets the value of password for the default user.
- *
- * @return value of password.
- */
- char[] getPasswordCharArray() {
- return userPassword;
+ public CPDSConnectionFactory(final ConnectionPoolDataSource cpds, final String validationQuery, final Duration validationQueryTimeoutDuration,
+ final boolean rollbackAfterValidation, final String userName, final String userPassword) {
+ this(cpds, validationQuery, validationQueryTimeoutDuration, rollbackAfterValidation, userName, Utils.toCharArray(userPassword));
}
/**
- * Returns the object pool used to pool connections created by this factory.
+ * Creates a new {@code PoolableConnectionFactory}.
*
- * @return ObjectPool managing pooled connections
+ * @param cpds
+ * the ConnectionPoolDataSource from which to obtain PooledConnection's
+ * @param validationQuery
+ * a query to use to {@link #validateObject validate} {@link Connection}s. Should return at least one
+ * row. May be {@code null} in which case {@link Connection#isValid(int)} will be used to validate
+ * connections.
+ * @param validationQueryTimeoutSeconds
+ * Timeout in seconds before validation fails
+ * @param rollbackAfterValidation
+ * whether a rollback should be issued after {@link #validateObject validating} {@link Connection}s.
+ * @param userName
+ * The user name to use to create connections
+ * @param userPassword
+ * The password to use to create connections
+ * @since 2.4.0
+ * @deprecated Use {@link #CPDSConnectionFactory(ConnectionPoolDataSource, String, Duration, boolean, String, char[])}.
*/
- public ObjectPool<PooledConnectionAndInfo> getPool() {
- return pool;
+ @Deprecated
+ public CPDSConnectionFactory(final ConnectionPoolDataSource cpds, final String validationQuery,
+ final int validationQueryTimeoutSeconds, final boolean rollbackAfterValidation, final String userName,
+ final char[] userPassword) {
+ this.cpds = cpds;
+ this.validationQuery = validationQuery;
+ this.validationQueryTimeoutDuration = Duration.ofSeconds(validationQueryTimeoutSeconds);
+ this.userPassKey = new UserPassKey(userName, userPassword);
+ this.rollbackAfterValidation = rollbackAfterValidation;
}
/**
+ * Creates a new {@code PoolableConnectionFactory}.
*
- * @param pool
- * the {@link ObjectPool} in which to pool those {@link Connection}s
+ * @param cpds
+ * the ConnectionPoolDataSource from which to obtain PooledConnection's
+ * @param validationQuery
+ * a query to use to {@link #validateObject validate} {@link Connection}s. Should return at least one
+ * row. May be {@code null} in which case {@link Connection#isValid(int)} will be used to validate
+ * connections.
+ * @param validationQueryTimeoutSeconds
+ * Timeout in seconds before validation fails
+ * @param rollbackAfterValidation
+ * whether a rollback should be issued after {@link #validateObject validating} {@link Connection}s.
+ * @param userName
+ * The user name to use to create connections
+ * @param userPassword
+ * The password to use to create connections
+ * @deprecated Use {@link #CPDSConnectionFactory(ConnectionPoolDataSource, String, Duration, boolean, String, String)}.
*/
- public void setPool(final ObjectPool<PooledConnectionAndInfo> pool) {
- this.pool = pool;
+ @Deprecated
+ public CPDSConnectionFactory(final ConnectionPoolDataSource cpds, final String validationQuery, final int validationQueryTimeoutSeconds,
+ final boolean rollbackAfterValidation, final String userName, final String userPassword) {
+ this(cpds, validationQuery, validationQueryTimeoutSeconds, rollbackAfterValidation, userName, Utils.toCharArray(userPassword));
}
@Override
- public synchronized PooledObject<PooledConnectionAndInfo> makeObject() {
- final PooledConnectionAndInfo pci;
- try {
- PooledConnection pc = null;
- if (userName == null) {
- pc = cpds.getPooledConnection();
- } else {
- pc = cpds.getPooledConnection(userName, Utils.toString(userPassword));
- }
-
- 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);
- pci = new PooledConnectionAndInfo(pc, userName, userPassword);
- pcMap.put(pc, pci);
- } catch (final SQLException e) {
- throw new RuntimeException(e.getMessage());
- }
- return new DefaultPooledObject<>(pci);
+ public void activateObject(final PooledObject<PooledConnectionAndInfo> p) throws Exception {
+ validateLifetime(p);
}
/**
- * Closes the PooledConnection and stops listening for events from it.
+ * Verifies that the user name matches the user whose connections are being managed by this factory and closes the
+ * pool if this is the case; otherwise does nothing.
*/
@Override
- public void destroyObject(final PooledObject<PooledConnectionAndInfo> p) throws Exception {
- doDestroyObject(p.getObject());
- }
-
- private void doDestroyObject(final PooledConnectionAndInfo pci) throws Exception {
- final PooledConnection pc = pci.getPooledConnection();
- pc.removeConnectionEventListener(this);
- pcMap.remove(pc);
- pc.close();
- }
-
- @Override
- public boolean validateObject(final PooledObject<PooledConnectionAndInfo> p) {
- try {
- validateLifetime(p);
- } catch (final Exception e) {
- return false;
- }
- boolean valid = false;
- final PooledConnection pconn = p.getObject().getPooledConnection();
- Connection conn = null;
- validatingSet.add(pconn);
- if (null == validationQuery) {
- int timeoutSeconds = validationQueryTimeoutSeconds;
- if (timeoutSeconds < 0) {
- timeoutSeconds = 0;
- }
- try {
- conn = pconn.getConnection();
- valid = conn.isValid(timeoutSeconds);
- } catch (final SQLException e) {
- valid = false;
- } finally {
- Utils.closeQuietly(conn);
- validatingSet.remove(pconn);
- }
- } else {
- Statement stmt = null;
- ResultSet rset = null;
- // logical Connection from the PooledConnection must be closed
- // before another one can be requested and closing it will
- // generate an event. Keep track so we know not to return
- // the PooledConnection
- validatingSet.add(pconn);
- try {
- conn = pconn.getConnection();
- stmt = conn.createStatement();
- rset = stmt.executeQuery(validationQuery);
- valid = rset.next();
- if (rollbackAfterValidation) {
- conn.rollback();
- }
- } catch (final Exception e) {
- valid = false;
- } finally {
- Utils.closeQuietly(rset);
- Utils.closeQuietly(stmt);
- Utils.closeQuietly(conn);
- validatingSet.remove(pconn);
+ public void closePool(final String userName) throws SQLException {
+ synchronized (this) {
+ if (userName == null || !userName.equals(this.userPassKey.getUserName())) {
+ return;
}
}
- return valid;
- }
-
- @Override
- public void passivateObject(final PooledObject<PooledConnectionAndInfo> p) throws Exception {
- validateLifetime(p);
- }
-
- @Override
- public void activateObject(final PooledObject<PooledConnectionAndInfo> p) throws Exception {
- validateLifetime(p);
+ try {
+ pool.close();
+ } catch (final Exception ex) {
+ throw new SQLException("Error closing connection pool", ex);
+ }
}
- // ***********************************************************************
- // java.sql.ConnectionEventListener implementation
- // ***********************************************************************
-
/**
* This will be called if the Connection returned by the getConnection method came from a PooledConnection, and the
* user calls the close() method of this connection object. What we need to do here is to release this
@@ -309,9 +252,38 @@ class CPDSConnectionFactory
}
}
- // ***********************************************************************
- // PooledConnectionManager implementation
- // ***********************************************************************
+ /**
+ * Closes the PooledConnection and stops listening for events from it.
+ */
+ @Override
+ public void destroyObject(final PooledObject<PooledConnectionAndInfo> p) throws Exception {
+ doDestroyObject(p.getObject());
+ }
+
+ private void doDestroyObject(final PooledConnectionAndInfo pci) throws Exception {
+ final PooledConnection pc = pci.getPooledConnection();
+ pc.removeConnectionEventListener(this);
+ pcMap.remove(pc);
+ pc.close();
+ }
+
+ /**
+ * (Testing API) Gets the value of password for the default user.
+ *
+ * @return value of password.
+ */
+ char[] getPasswordCharArray() {
+ return userPassKey.getPasswordCharArray();
+ }
+
+ /**
+ * Returns the object pool used to pool connections created by this factory.
+ *
+ * @return ObjectPool managing pooled connections
+ */
+ public ObjectPool<PooledConnectionAndInfo> getPool() {
+ return pool;
+ }
/**
* Invalidates the PooledConnection in the pool. The CPDSConnectionFactory closes the connection and pool counters
@@ -332,25 +304,65 @@ class CPDSConnectionFactory
}
}
+ // ***********************************************************************
+ // java.sql.ConnectionEventListener implementation
+ // ***********************************************************************
+
+ @Override
+ public synchronized PooledObject<PooledConnectionAndInfo> makeObject() {
+ final PooledConnectionAndInfo pci;
+ 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);
+ pci = new PooledConnectionAndInfo(pc, userPassKey);
+ pcMap.put(pc, pci);
+ } catch (final SQLException e) {
+ throw new RuntimeException(e.getMessage());
+ }
+ return new DefaultPooledObject<>(pci);
+ }
+
+ @Override
+ public void passivateObject(final PooledObject<PooledConnectionAndInfo> p) throws Exception {
+ validateLifetime(p);
+ }
+
/**
- * Sets the database password used when creating new connections.
+ * Sets the maximum Duration of a connection after which the connection will always fail activation,
+ * passivation and validation.
*
- * @param userPassword
- * new password
+ * @param maxConnDuration
+ * A value of zero or less indicates an infinite lifetime. The default value is -1 milliseconds.
+ * @since 2.10.0
*/
- public synchronized void setPassword(final char[] userPassword) {
- this.userPassword = Utils.clone(userPassword);
+ public void setMaxConn(final Duration maxConnDuration) {
+ this.maxConnDuration = maxConnDuration;
}
/**
- * Sets the database password used when creating new connections.
+ * Sets the maximum lifetime in milliseconds of a connection after which the connection will always fail activation,
+ * passivation and validation.
*
- * @param userPassword
- * new password
+ * @param maxConnDuration
+ * A value of zero or less indicates an infinite lifetime. The default value is -1 milliseconds.
+ * @since 2.9.0
+ * @deprecated Use {@link #setMaxConn(Duration)}.
*/
- @Override
- public synchronized void setPassword(final String userPassword) {
- this.userPassword = Utils.toCharArray(userPassword);
+ @Deprecated
+ public void setMaxConnLifetime(final Duration maxConnDuration) {
+ this.maxConnDuration = maxConnDuration;
}
/**
@@ -359,37 +371,41 @@ class CPDSConnectionFactory
*
* @param maxConnLifetimeMillis
* A value of zero or less indicates an infinite lifetime. The default value is -1.
+ * @deprecated Use {@link #setMaxConn(Duration)}.
*/
+ @Deprecated
public void setMaxConnLifetimeMillis(final long maxConnLifetimeMillis) {
- this.maxConnLifetimeMillis = maxConnLifetimeMillis;
+ setMaxConnLifetime(Duration.ofMillis(maxConnLifetimeMillis));
}
/**
- * Verifies that the user name matches the user whose connections are being managed by this factory and closes the
- * pool if this is the case; otherwise does nothing.
+ * Sets the database password used when creating new connections.
+ *
+ * @param userPassword
+ * new password
+ */
+ public synchronized void setPassword(final char[] userPassword) {
+ this.userPassKey = new UserPassKey(userPassKey.getUserName(), userPassword);
+ }
+
+ /**
+ * Sets the database password used when creating new connections.
+ *
+ * @param userPassword
+ * new password
*/
@Override
- public void closePool(final String userName) throws SQLException {
- synchronized (this) {
- if (userName == null || !userName.equals(this.userName)) {
- return;
- }
- }
- try {
- pool.close();
- } catch (final Exception ex) {
- throw new SQLException("Error closing connection pool", ex);
- }
+ public synchronized void setPassword(final String userPassword) {
+ this.userPassKey = new UserPassKey(userPassKey.getUserName(), userPassword);
}
- private void validateLifetime(final PooledObject<PooledConnectionAndInfo> p) throws Exception {
- if (maxConnLifetimeMillis > 0) {
- final long lifetime = System.currentTimeMillis() - p.getCreateTime();
- if (lifetime > maxConnLifetimeMillis) {
- throw new Exception(Utils.getMessage("connectionFactory.lifetimeExceeded", Long.valueOf(lifetime),
- Long.valueOf(maxConnLifetimeMillis)));
- }
- }
+ /**
+ *
+ * @param pool
+ * the {@link ObjectPool} in which to pool those {@link Connection}s
+ */
+ public void setPool(final ObjectPool<PooledConnectionAndInfo> pool) {
+ this.pool = pool;
}
/**
@@ -402,19 +418,81 @@ class CPDSConnectionFactory
builder.append(cpds);
builder.append(", validationQuery=");
builder.append(validationQuery);
- builder.append(", validationQueryTimeoutSeconds=");
- builder.append(validationQueryTimeoutSeconds);
+ builder.append(", validationQueryTimeoutDuration=");
+ builder.append(validationQueryTimeoutDuration);
builder.append(", rollbackAfterValidation=");
builder.append(rollbackAfterValidation);
builder.append(", pool=");
builder.append(pool);
- builder.append(", maxConnLifetimeMillis=");
- builder.append(maxConnLifetimeMillis);
+ builder.append(", maxConnDuration=");
+ builder.append(maxConnDuration);
builder.append(", validatingSet=");
builder.append(validatingSet);
builder.append(", pcMap=");
builder.append(pcMap);
- builder.append(']');
+ builder.append("]");
return builder.toString();
}
+
+ private void validateLifetime(final PooledObject<PooledConnectionAndInfo> pooledObject) throws Exception {
+ if (maxConnDuration.compareTo(Duration.ZERO) > 0) {
+ final Duration lifetimeDuration = Duration.between(pooledObject.getCreateInstant(), Instant.now());
+ if (lifetimeDuration.compareTo(maxConnDuration) > 0) {
+ throw new Exception(Utils.getMessage("connectionFactory.lifetimeExceeded", lifetimeDuration, maxConnDuration));
+ }
+ }
+ }
+
+ @Override
+ public boolean validateObject(final PooledObject<PooledConnectionAndInfo> p) {
+ try {
+ validateLifetime(p);
+ } catch (final Exception e) {
+ return false;
+ }
+ boolean valid = false;
+ final PooledConnection pconn = p.getObject().getPooledConnection();
+ Connection conn = null;
+ validatingSet.add(pconn);
+ if (null == validationQuery) {
+ Duration timeoutDuration = validationQueryTimeoutDuration;
+ if (timeoutDuration.isNegative()) {
+ timeoutDuration = Duration.ZERO;
+ }
+ try {
+ conn = pconn.getConnection();
+ valid = conn.isValid((int) timeoutDuration.getSeconds());
+ } catch (final SQLException e) {
+ valid = false;
+ } finally {
+ Utils.closeQuietly((AutoCloseable) conn);
+ validatingSet.remove(pconn);
+ }
+ } else {
+ Statement stmt = null;
+ ResultSet rset = null;
+ // logical Connection from the PooledConnection must be closed
+ // before another one can be requested and closing it will
+ // generate an event. Keep track so we know not to return
+ // the PooledConnection
+ validatingSet.add(pconn);
+ try {
+ conn = pconn.getConnection();
+ stmt = conn.createStatement();
+ rset = stmt.executeQuery(validationQuery);
+ valid = rset.next();
+ if (rollbackAfterValidation) {
+ conn.rollback();
+ }
+ } catch (final Exception e) {
+ valid = false;
+ } finally {
+ Utils.closeQuietly((AutoCloseable) rset);
+ Utils.closeQuietly((AutoCloseable) stmt);
+ Utils.closeQuietly((AutoCloseable) conn);
+ validatingSet.remove(pconn);
+ }
+ }
+ return valid;
+ }
}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/datasources/CharArray.java b/java/org/apache/tomcat/dbcp/dbcp2/datasources/CharArray.java
new file mode 100644
index 0000000..58b4d9a
--- /dev/null
+++ b/java/org/apache/tomcat/dbcp/dbcp2/datasources/CharArray.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.tomcat.dbcp.dbcp2.datasources;
+
+import java.util.Arrays;
+
+import org.apache.tomcat.dbcp.dbcp2.Utils;
+
+/**
+ * A {@code char} array wrapper that does not reveal its contents inadvertently through toString(). In contrast to, for
+ * example, AtomicReference which toString()'s its contents.
+ *
+ * May contain null.
+ *
+ * @since 2.9.0
+ */
+final class CharArray {
+
+ static final CharArray NULL = new CharArray((char[]) null);
+
+ private final char[] chars;
+
+ CharArray(final char[] chars) {
+ this.chars = Utils.clone(chars);
+ }
+
+ CharArray(final String string) {
+ this.chars = Utils.toCharArray(string);
+ }
+
+ /**
+ * Converts the value of char array as a String.
+ *
+ * @return value as a string, may be null.
+ */
+ String asString() {
+ return Utils.toString(chars);
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof CharArray)) {
+ return false;
+ }
+ final CharArray other = (CharArray) obj;
+ return Arrays.equals(chars, other.chars);
+ }
+
+ /**
+ * Gets the value of char array.
+ *
+ * @return value, may be null.
+ */
+ char[] get() {
+ return chars == null ? null : chars.clone();
+ }
+
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(chars);
+ }
+
+ /**
+ * Calls {@code super.toString()} and does not reveal its contents inadvertently.
+ */
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSource.java b/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSource.java
index 7f99a9b..43cd8ba 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSource.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSource.java
@@ -23,6 +23,7 @@ import java.nio.charset.StandardCharsets;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
+import java.time.Duration;
import java.util.Properties;
import java.util.logging.Logger;
@@ -35,6 +36,7 @@ import javax.sql.PooledConnection;
import org.apache.tomcat.dbcp.pool2.impl.BaseObjectPoolConfig;
import org.apache.tomcat.dbcp.pool2.impl.GenericKeyedObjectPoolConfig;
+import org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool;
/**
* <p>
@@ -99,8 +101,8 @@ public abstract class InstanceKeyDataSource implements DataSource, Referenceable
/** Environment that may be used to set up a JNDI initial context. */
private Properties jndiEnvironment;
- /** Login TimeOut in seconds */
- private int loginTimeout;
+ /** Login Timeout */
+ private Duration loginTimeoutDuration = Duration.ZERO;
/** Log stream */
private PrintWriter logWriter;
@@ -114,22 +116,22 @@ public abstract class InstanceKeyDataSource implements DataSource, Referenceable
private boolean defaultLifo = BaseObjectPoolConfig.DEFAULT_LIFO;
private int defaultMaxIdle = GenericKeyedObjectPoolConfig.DEFAULT_MAX_IDLE_PER_KEY;
private int defaultMaxTotal = GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL;
- private long defaultMaxWaitMillis = BaseObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS;
- private long defaultMinEvictableIdleTimeMillis = BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
+ private Duration defaultMaxWaitDuration = BaseObjectPoolConfig.DEFAULT_MAX_WAIT;
+ private Duration defaultMinEvictableIdleDuration = BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_DURATION;
private int defaultMinIdle = GenericKeyedObjectPoolConfig.DEFAULT_MIN_IDLE_PER_KEY;
private int defaultNumTestsPerEvictionRun = BaseObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
- private long defaultSoftMinEvictableIdleTimeMillis = BaseObjectPoolConfig.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
+ private Duration defaultSoftMinEvictableIdleDuration = BaseObjectPoolConfig.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_DURATION;
private boolean defaultTestOnCreate = BaseObjectPoolConfig.DEFAULT_TEST_ON_CREATE;
private boolean defaultTestOnBorrow = BaseObjectPoolConfig.DEFAULT_TEST_ON_BORROW;
private boolean defaultTestOnReturn = BaseObjectPoolConfig.DEFAULT_TEST_ON_RETURN;
private boolean defaultTestWhileIdle = BaseObjectPoolConfig.DEFAULT_TEST_WHILE_IDLE;
- private long defaultTimeBetweenEvictionRunsMillis = BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
+ private Duration defaultDurationBetweenEvictionRuns = BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS;
// Connection factory properties
private String validationQuery;
- private int validationQueryTimeoutSeconds = -1;
+ private Duration validationQueryTimeoutDuration = Duration.ofSeconds(-1);
private boolean rollbackAfterValidation;
- private long maxConnLifetimeMillis = -1;
+ private Duration maxConnDuration = Duration.ofMillis(-1);
// Connection properties
private Boolean defaultAutoCommit;
@@ -137,7 +139,7 @@ public abstract class InstanceKeyDataSource implements DataSource, Referenceable
private Boolean defaultReadOnly;
/**
- * Default no-arg constructor for Serialization
+ * Default no-arg constructor for Serialization.
*/
public InstanceKeyDataSource() {
}
@@ -159,27 +161,138 @@ public abstract class InstanceKeyDataSource implements DataSource, Referenceable
@Override
public abstract void close() throws Exception;
- protected abstract PooledConnectionManager getConnectionManager(UserPassKey upkey);
+ private void closeDueToException(final PooledConnectionAndInfo info) {
+ if (info != null) {
+ try {
+ info.getPooledConnection().getConnection().close();
+ } catch (final Exception e) {
+ // do not throw this exception because we are in the middle
+ // of handling another exception. But record it because
+ // it potentially leaks connections from the pool.
+ getLogWriter().println("[ERROR] Could not return connection to pool during exception handling. " + e.getMessage());
+ }
+ }
+ }
- /* JDBC_4_ANT_KEY_BEGIN */
+ /**
+ * Attempts to establish a database connection.
+ */
@Override
- public boolean isWrapperFor(final Class<?> iface) throws SQLException {
- return false;
+ public Connection getConnection() throws SQLException {
+ return getConnection(null, null);
}
+ /**
+ * Attempts to retrieve a database connection using {@link #getPooledConnectionAndInfo(String, String)} with the
+ * provided user name and password. The password on the {@code PooledConnectionAndInfo} instance returned by
+ * <code>getPooledConnectionAndInfo</code> is compared to the <code>password</code> parameter. If the comparison
+ * fails, a database connection using the supplied user name and password is attempted. If the connection attempt
+ * fails, an SQLException is thrown, indicating that the given password did not match the password used to create
+ * the pooled connection. If the connection attempt succeeds, this means that the database password has been
+ * changed. In this case, the <code>PooledConnectionAndInfo</code> instance retrieved with the old password is
+ * destroyed and the <code>getPooledConnectionAndInfo</code> is repeatedly invoked until a
+ * <code>PooledConnectionAndInfo</code> instance with the new password is returned.
+ */
@Override
- public <T> T unwrap(final Class<T> iface) throws SQLException {
- throw new SQLException("InstanceKeyDataSource is not a wrapper.");
+ public Connection getConnection(final String userName, final String userPassword) throws SQLException {
+ if (instanceKey == null) {
+ throw new SQLException("Must set the ConnectionPoolDataSource "
+ + "through setDataSourceName or setConnectionPoolDataSource" + " before calling getConnection.");
+ }
+ getConnectionCalled = true;
+ PooledConnectionAndInfo info = null;
+ try {
+ info = getPooledConnectionAndInfo(userName, userPassword);
+ } catch (final RuntimeException | SQLException e) {
+ closeDueToException(info);
+ throw e;
+ } catch (final Exception e) {
+ closeDueToException(info);
+ throw new SQLException("Cannot borrow connection from pool", e);
+ }
+
+ // Password on PooledConnectionAndInfo does not match
+ if (!(null == userPassword ? null == info.getPassword() : userPassword.equals(info.getPassword()))) {
+ try { // See if password has changed by attempting connection
+ testCPDS(userName, userPassword);
+ } catch (final SQLException ex) {
+ // Password has not changed, so refuse client, but return connection to the pool
+ closeDueToException(info);
+ throw new SQLException(
+ "Given password did not match password used" + " to create the PooledConnection.", ex);
+ } catch (final javax.naming.NamingException ne) {
+ throw new SQLException("NamingException encountered connecting to database", ne);
+ }
+ /*
+ * Password must have changed -> destroy connection and keep retrying until we get a new, good one,
+ * destroying any idle connections with the old password as we pull them from the pool.
+ */
+ final UserPassKey upkey = info.getUserPassKey();
+ final PooledConnectionManager manager = getConnectionManager(upkey);
+ // Destroy and remove from pool
+ manager.invalidate(info.getPooledConnection());
+ // Reset the password on the factory if using CPDSConnectionFactory
+ manager.setPassword(upkey.getPassword());
+ info = null;
+ for (int i = 0; i < 10; i++) { // Bound the number of retries - only needed if bad instances return
+ try {
+ info = getPooledConnectionAndInfo(userName, userPassword);
+ } catch (final RuntimeException | SQLException e) {
+ closeDueToException(info);
+ throw e;
+ } catch (final Exception e) {
+ closeDueToException(info);
+ throw new SQLException("Cannot borrow connection from pool", e);
+ }
+ if (info != null && userPassword != null && userPassword.equals(info.getPassword())) {
+ break;
+ }
+ if (info != null) {
+ manager.invalidate(info.getPooledConnection());
+ }
+ info = null;
+ }
+ if (info == null) {
+ throw new SQLException("Cannot borrow connection from pool - password change failure.");
+ }
+ }
+
+ final Connection connection = info.getPooledConnection().getConnection();
+ try {
+ setupDefaults(connection, userName);
+ connection.clearWarnings();
+ return connection;
+ } catch (final SQLException ex) {
+ try {
+ connection.close();
+ } catch (final Exception exc) {
+ getLogWriter().println("ignoring exception during close: " + exc);
+ }
+ throw ex;
+ }
}
- /* JDBC_4_ANT_KEY_END */
- @Override
- public Logger getParentLogger() throws SQLFeatureNotSupportedException {
- throw new SQLFeatureNotSupportedException();
+ protected abstract PooledConnectionManager getConnectionManager(UserPassKey upkey);
+
+ /**
+ * Gets the value of connectionPoolDataSource. This method will return null, if the backing data source is being
+ * accessed via JNDI.
+ *
+ * @return value of connectionPoolDataSource.
+ */
+ public ConnectionPoolDataSource getConnectionPoolDataSource() {
+ return dataSource;
}
- // -------------------------------------------------------------------
- // Properties
+ /**
+ * Gets the name of the ConnectionPoolDataSource which backs this pool. This name is used to look up the data source
+ * from a JNDI service provider.
+ *
+ * @return value of dataSourceName.
+ */
+ public String getDataSourceName() {
+ return dataSourceName;
+ }
/**
* Gets the default value for {@link GenericKeyedObjectPoolConfig#getBlockWhenExhausted()} for each per user pool.
@@ -192,15 +305,13 @@ public abstract class InstanceKeyDataSource implements DataSource, Referenceable
}
/**
- * Sets the default value for {@link GenericKeyedObjectPoolConfig#getBlockWhenExhausted()} for each per user pool.
+ * Gets the default value for {@link GenericObjectPool#getDurationBetweenEvictionRuns()} for each per user pool.
*
- * @param blockWhenExhausted
- * The default value for {@link GenericKeyedObjectPoolConfig#getBlockWhenExhausted()} for each per user
- * pool.
+ * @return The default value for {@link GenericObjectPool#getDurationBetweenEvictionRuns()} for each per user pool.
+ * @since 2.10.0
*/
- public void setDefaultBlockWhenExhausted(final boolean blockWhenExhausted) {
- assertInitializationAllowed();
- this.defaultBlockWhenExhausted = blockWhenExhausted;
+ public Duration getDefaultDurationBetweenEvictionRuns() {
+ return this.defaultDurationBetweenEvictionRuns;
}
/**
@@ -215,19 +326,6 @@ public abstract class InstanceKeyDataSource implements DataSource, Referenceable
}
/**
- * Sets the default value for {@link GenericKeyedObjectPoolConfig#getEvictionPolicyClassName()} for each per user
- * pool.
- *
- * @param evictionPolicyClassName
- * The default value for {@link GenericKeyedObjectPoolConfig#getEvictionPolicyClassName()} for each per
- * user pool.
- */
- public void setDefaultEvictionPolicyClassName(final String evictionPolicyClassName) {
- assertInitializationAllowed();
- this.defaultEvictionPolicyClassName = evictionPolicyClassName;
- }
-
- /**
* Gets the default value for {@link GenericKeyedObjectPoolConfig#getLifo()} for each per user pool.
*
* @return The default value for {@link GenericKeyedObjectPoolConfig#getLifo()} for each per user pool.
@@ -237,17 +335,6 @@ public abstract class InstanceKeyDataSource implements DataSource, Referenceable
}
/**
- * Sets the default value for {@link GenericKeyedObjectPoolConfig#getLifo()} for each per user pool.
- *
- * @param lifo
- * The default value for {@link GenericKeyedObjectPoolConfig#getLifo()} for each per user pool.
- */
- public void setDefaultLifo(final boolean lifo) {
- assertInitializationAllowed();
- this.defaultLifo = lifo;
- }
-
- /**
* Gets the default value for {@link GenericKeyedObjectPoolConfig#getMaxIdlePerKey()} for each per user pool.
*
* @return The default value for {@link GenericKeyedObjectPoolConfig#getMaxIdlePerKey()} for each per user pool.
@@ -257,17 +344,6 @@ public abstract class InstanceKeyDataSource implements DataSource, Referenceable
}
/**
- * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMaxIdlePerKey()} for each per user pool.
- *
- * @param maxIdle
- * The default value for {@link GenericKeyedObjectPoolConfig#getMaxIdlePerKey()} for each per user pool.
- */
- public void setDefaultMaxIdle(final int maxIdle) {
- assertInitializationAllowed();
- this.defaultMaxIdle = maxIdle;
- }
-
- /**
* Gets the default value for {@link GenericKeyedObjectPoolConfig#getMaxTotalPerKey()} for each per user pool.
*
* @return The default value for {@link GenericKeyedObjectPoolConfig#getMaxTotalPerKey()} for each per user pool.
@@ -277,58 +353,49 @@ public abstract class InstanceKeyDataSource implements DataSource, Referenceable
}
/**
- * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMaxTotalPerKey()} for each per user pool.
+ * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitDuration()} for each per user pool.
*
- * @param maxTotal
- * The default value for {@link GenericKeyedObjectPoolConfig#getMaxTotalPerKey()} for each per user pool.
+ * @return The default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitDuration()} for each per user pool.
+ * @since 2.9.0
*/
- public void setDefaultMaxTotal(final int maxTotal) {
- assertInitializationAllowed();
- this.defaultMaxTotal = maxTotal;
+ public Duration getDefaultMaxWait() {
+ return this.defaultMaxWaitDuration;
}
/**
- * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitMillis()} for each per user pool.
+ * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitDuration()} for each per user pool.
*
- * @return The default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitMillis()} for each per user pool.
+ * @return The default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitDuration()} for each per user pool.
+ * @deprecated Use {@link #getDefaultMaxWait()}.
*/
+ @Deprecated
public long getDefaultMaxWaitMillis() {
- return this.defaultMaxWaitMillis;
- }
-
- /**
- * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitMillis()} for each per user pool.
- *
- * @param maxWaitMillis
- * The default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitMillis()} for each per user pool.
- */
- public void setDefaultMaxWaitMillis(final long maxWaitMillis) {
- assertInitializationAllowed();
- this.defaultMaxWaitMillis = maxWaitMillis;
+ return getDefaultMaxWait().toMillis();
}
/**
- * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleTimeMillis()} for each per user
+ * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleDuration()} for each per user
* pool.
*
- * @return The default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleTimeMillis()} for each per
+ * @return The default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleDuration()} for each per
* user pool.
+ * @since 2.10.0
*/
- public long getDefaultMinEvictableIdleTimeMillis() {
- return this.defaultMinEvictableIdleTimeMillis;
+ public Duration getDefaultMinEvictableIdleDuration() {
+ return this.defaultMinEvictableIdleDuration;
}
/**
- * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleTimeMillis()} for each per user
+ * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleDuration()} for each per user
* pool.
*
- * @param minEvictableIdleTimeMillis
- * The default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleTimeMillis()} for each
- * per user pool.
+ * @return The default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleDuration()} for each per
+ * user pool.
+ * @deprecated Use {@link #getDefaultMinEvictableIdleDuration()}.
*/
- public void setDefaultMinEvictableIdleTimeMillis(final long minEvictableIdleTimeMillis) {
- assertInitializationAllowed();
- this.defaultMinEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
+ @Deprecated
+ public long getDefaultMinEvictableIdleTimeMillis() {
+ return this.defaultMinEvictableIdleDuration.toMillis();
}
/**
@@ -341,17 +408,6 @@ public abstract class InstanceKeyDataSource implements DataSource, Referenceable
}
/**
- * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMinIdlePerKey()} for each per user pool.
- *
- * @param minIdle
- * The default value for {@link GenericKeyedObjectPoolConfig#getMinIdlePerKey()} for each per user pool.
- */
- public void setDefaultMinIdle(final int minIdle) {
- assertInitializationAllowed();
- this.defaultMinIdle = minIdle;
- }
-
- /**
* Gets the default value for {@link GenericKeyedObjectPoolConfig#getNumTestsPerEvictionRun()} for each per user
* pool.
*
@@ -363,16 +419,15 @@ public abstract class InstanceKeyDataSource implements DataSource, Referenceable
}
/**
- * Sets the default value for {@link GenericKeyedObjectPoolConfig#getNumTestsPerEvictionRun()} for each per user
- * pool.
+ * Gets the default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+ * GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool.
*
- * @param numTestsPerEvictionRun
- * The default value for {@link GenericKeyedObjectPoolConfig#getNumTestsPerEvictionRun()} for each per
- * user pool.
+ * @return The default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+ * GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool.
+ * @since 2.10.0
*/
- public void setDefaultNumTestsPerEvictionRun(final int numTestsPerEvictionRun) {
- assertInitializationAllowed();
- this.defaultNumTestsPerEvictionRun = numTestsPerEvictionRun;
+ public Duration getDefaultSoftMinEvictableIdleDuration() {
+ return this.defaultSoftMinEvictableIdleDuration;
}
/**
@@ -381,22 +436,22 @@ public abstract class InstanceKeyDataSource implements DataSource, Referenceable
*
* @return The default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
* GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool.
+ * @deprecated Use {@link #getDefaultSoftMinEvictableIdleDuration()}.
*/
+ @Deprecated
public long getDefaultSoftMinEvictableIdleTimeMillis() {
- return this.defaultSoftMinEvictableIdleTimeMillis;
+ return this.defaultSoftMinEvictableIdleDuration.toMillis();
}
/**
- * Sets the default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
- * GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool.
+ * Gets the default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+ * GenericObjectPool#getTestOnBorrow()} for each per user pool.
*
- * @param softMinEvictableIdleTimeMillis
- * The default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
- * GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool.
+ * @return The default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+ * GenericObjectPool#getTestOnBorrow()} for each per user pool.
*/
- public void setDefaultSoftMinEvictableIdleTimeMillis(final long softMinEvictableIdleTimeMillis) {
- assertInitializationAllowed();
- this.defaultSoftMinEvictableIdleTimeMillis = softMinEvictableIdleTimeMillis;
+ public boolean getDefaultTestOnBorrow() {
+ return this.defaultTestOnBorrow;
}
/**
@@ -411,206 +466,440 @@ public abstract class InstanceKeyDataSource implements DataSource, Referenceable
}
/**
- * Sets the default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
- * GenericObjectPool#getTestOnCreate()} for each per user pool.
+ * Gets the default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+ * GenericObjectPool#getTestOnReturn()} for each per user pool.
*
- * @param testOnCreate
- * The default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
- * GenericObjectPool#getTestOnCreate()} for each per user pool.
+ * @return The default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+ * GenericObjectPool#getTestOnReturn()} for each per user pool.
*/
- public void setDefaultTestOnCreate(final boolean testOnCreate) {
- assertInitializationAllowed();
- this.defaultTestOnCreate = testOnCreate;
+ public boolean getDefaultTestOnReturn() {
+ return this.defaultTestOnReturn;
}
/**
* Gets the default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
- * GenericObjectPool#getTestOnBorrow()} for each per user pool.
+ * GenericObjectPool#getTestWhileIdle()} for each per user pool.
*
* @return The default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
- * GenericObjectPool#getTestOnBorrow()} for each per user pool.
+ * GenericObjectPool#getTestWhileIdle()} for each per user pool.
*/
- public boolean getDefaultTestOnBorrow() {
- return this.defaultTestOnBorrow;
+ public boolean getDefaultTestWhileIdle() {
+ return this.defaultTestWhileIdle;
}
/**
- * Sets the default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
- * GenericObjectPool#getTestOnBorrow()} for each per user pool.
+ * Gets the default value for {@link GenericObjectPool#getDurationBetweenEvictionRuns ()} for each per user pool.
*
- * @param testOnBorrow
- * The default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
- * GenericObjectPool#getTestOnBorrow()} for each per user pool.
+ * @return The default value for {@link GenericObjectPool#getDurationBetweenEvictionRuns ()} for each per user pool.
+ * @deprecated Use {@link #getDefaultDurationBetweenEvictionRuns()}.
*/
- public void setDefaultTestOnBorrow(final boolean testOnBorrow) {
- assertInitializationAllowed();
- this.defaultTestOnBorrow = testOnBorrow;
+ @Deprecated
+ public long getDefaultTimeBetweenEvictionRunsMillis() {
+ return this.defaultDurationBetweenEvictionRuns.toMillis();
}
/**
- * Gets the default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
- * GenericObjectPool#getTestOnReturn()} for each per user pool.
+ * Gets the value of defaultTransactionIsolation, which defines the state of connections handed out from this pool.
+ * The value can be changed on the Connection using Connection.setTransactionIsolation(int). If this method returns
+ * -1, the default is JDBC driver dependent.
*
- * @return The default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
- * GenericObjectPool#getTestOnReturn()} for each per user pool.
+ * @return value of defaultTransactionIsolation.
*/
- public boolean getDefaultTestOnReturn() {
- return this.defaultTestOnReturn;
+ public int getDefaultTransactionIsolation() {
+ return defaultTransactionIsolation;
}
/**
- * Sets the default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
- * GenericObjectPool#getTestOnReturn()} for each per user pool.
+ * Gets the description. This property is defined by JDBC as for use with GUI (or other) tools that might deploy the
+ * datasource. It serves no internal purpose.
*
- * @param testOnReturn
- * The default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
- * GenericObjectPool#getTestOnReturn()} for each per user pool.
+ * @return value of description.
*/
- public void setDefaultTestOnReturn(final boolean testOnReturn) {
- assertInitializationAllowed();
- this.defaultTestOnReturn = testOnReturn;
+ public String getDescription() {
+ return description;
}
/**
- * Gets the default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
- * GenericObjectPool#getTestWhileIdle()} for each per user pool.
+ * Gets the instance key.
*
- * @return The default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
- * GenericObjectPool#getTestWhileIdle()} for each per user pool.
+ * @return the instance key.
*/
- public boolean getDefaultTestWhileIdle() {
- return this.defaultTestWhileIdle;
+ protected String getInstanceKey() {
+ return instanceKey;
}
/**
- * Sets the default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
- * GenericObjectPool#getTestWhileIdle()} for each per user pool.
+ * Gets the value of jndiEnvironment which is used when instantiating a JNDI InitialContext. This InitialContext is
+ * used to locate the back end ConnectionPoolDataSource.
*
- * @param testWhileIdle
- * The default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
- * GenericObjectPool#getTestWhileIdle()} for each per user pool.
+ * @param key
+ * JNDI environment key.
+ * @return value of jndiEnvironment.
*/
- public void setDefaultTestWhileIdle(final boolean testWhileIdle) {
- assertInitializationAllowed();
- this.defaultTestWhileIdle = testWhileIdle;
+ public String getJndiEnvironment(final String key) {
+ String value = null;
+ if (jndiEnvironment != null) {
+ value = jndiEnvironment.getProperty(key);
+ }
+ return value;
}
/**
- * Gets the default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
- * GenericObjectPool#getTimeBetweenEvictionRunsMillis ()} for each per user pool.
+ * Gets the value of loginTimeout.
*
- * @return The default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
- * GenericObjectPool#getTimeBetweenEvictionRunsMillis ()} for each per user pool.
+ * @return value of loginTimeout.
+ * @deprecated Use {@link #getLoginTimeoutDuration()}.
*/
- public long getDefaultTimeBetweenEvictionRunsMillis() {
- return this.defaultTimeBetweenEvictionRunsMillis;
+ @Deprecated
+ @Override
+ public int getLoginTimeout() {
+ return (int) loginTimeoutDuration.getSeconds();
}
/**
- * Sets the default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
- * GenericObjectPool#getTimeBetweenEvictionRunsMillis ()} for each per user pool.
+ * Gets the value of loginTimeout.
*
- * @param timeBetweenEvictionRunsMillis
- * The default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
- * GenericObjectPool#getTimeBetweenEvictionRunsMillis ()} for each per user pool.
+ * @return value of loginTimeout.
+ * @since 2.10.0
*/
- public void setDefaultTimeBetweenEvictionRunsMillis(final long timeBetweenEvictionRunsMillis) {
- assertInitializationAllowed();
- this.defaultTimeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
+ public Duration getLoginTimeoutDuration() {
+ return loginTimeoutDuration;
}
/**
- * Gets the value of connectionPoolDataSource. This method will return null, if the backing data source is being
- * accessed via JNDI.
+ * Gets the value of logWriter.
*
- * @return value of connectionPoolDataSource.
+ * @return value of logWriter.
*/
- public ConnectionPoolDataSource getConnectionPoolDataSource() {
- return dataSource;
+ @Override
+ public PrintWriter getLogWriter() {
+ if (logWriter == null) {
+ logWriter = new PrintWriter(new OutputStreamWriter(System.out, StandardCharsets.UTF_8));
+ }
+ return logWriter;
+ }
+
+ /**
+ * Gets the maximum permitted lifetime of a connection. A value of zero or less indicates an
+ * infinite lifetime.
+ *
+ * @return The maximum permitted lifetime of a connection. A value of zero or less indicates an
+ * infinite lifetime.
+ * @since 2.10.0
+ */
+ public Duration getMaxConnDuration() {
+ return maxConnDuration;
+ }
+
+ /**
+ * Gets the maximum permitted lifetime of a connection. A value of zero or less indicates an
+ * infinite lifetime.
+ *
+ * @return The maximum permitted lifetime of a connection. A value of zero or less indicates an
+ * infinite lifetime.
+ * @deprecated Use {@link #getMaxConnDuration()}.
+ */
+ @Deprecated
+ public Duration getMaxConnLifetime() {
+ return maxConnDuration;
+ }
+
+ /**
+ * Gets the maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an
+ * infinite lifetime.
+ *
+ * @return The maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an
+ * infinite lifetime.
+ * @deprecated Use {@link #getMaxConnLifetime()}.
+ */
+ @Deprecated
+ public long getMaxConnLifetimeMillis() {
+ return maxConnDuration.toMillis();
+ }
+
+ @Override
+ public Logger getParentLogger() throws SQLFeatureNotSupportedException {
+ throw new SQLFeatureNotSupportedException();
+ }
+
+ /**
+ * This method is protected but can only be implemented in this package because PooledConnectionAndInfo is a package
+ * private type.
+ *
+ * @param userName The user name.
+ * @param userPassword The user password.
+ * @return Matching PooledConnectionAndInfo.
+ * @throws SQLException Connection or registration failure.
+ */
+ protected abstract PooledConnectionAndInfo getPooledConnectionAndInfo(String userName, String userPassword)
+ throws SQLException;
+
+ /**
+ * Gets the SQL query that will be used to validate connections from this pool before returning them to the caller.
+ * If specified, this query <strong>MUST</strong> be an SQL SELECT statement that returns at least one row. If not
+ * specified, {@link Connection#isValid(int)} will be used to validate connections.
+ *
+ * @return The SQL query that will be used to validate connections from this pool before returning them to the
+ * caller.
+ */
+ public String getValidationQuery() {
+ return this.validationQuery;
+ }
+
+ /**
+ * Returns the timeout in seconds before the validation query fails.
+ *
+ * @return The timeout in seconds before the validation query fails.
+ * @deprecated Use {@link #getValidationQueryTimeoutDuration()}.
+ */
+ @Deprecated
+ public int getValidationQueryTimeout() {
+ return (int) validationQueryTimeoutDuration.getSeconds();
+ }
+
+ /**
+ * Returns the timeout Duration before the validation query fails.
+ *
+ * @return The timeout Duration before the validation query fails.
+ */
+ public Duration getValidationQueryTimeoutDuration() {
+ return validationQueryTimeoutDuration;
+ }
+
+ /**
+ * Gets the value of defaultAutoCommit, which defines the state of connections handed out from this pool. The value
+ * can be changed on the Connection using Connection.setAutoCommit(boolean). The default is <code>null</code> which
+ * will use the default value for the drive.
+ *
+ * @return value of defaultAutoCommit.
+ */
+ public Boolean isDefaultAutoCommit() {
+ return defaultAutoCommit;
+ }
+
+ /**
+ * Gets the value of defaultReadOnly, which defines the state of connections handed out from this pool. The value
+ * can be changed on the Connection using Connection.setReadOnly(boolean). The default is <code>null</code> which
+ * will use the default value for the drive.
+ *
+ * @return value of defaultReadOnly.
+ */
+ public Boolean isDefaultReadOnly() {
+ return defaultReadOnly;
+ }
+
+ /**
+ * Whether a rollback will be issued after executing the SQL query that will be used to validate connections from
+ * this pool before returning them to the caller.
+ *
+ * @return true if a rollback will be issued after executing the validation query
+ */
+ public boolean isRollbackAfterValidation() {
+ return this.rollbackAfterValidation;
+ }
+
+ @Override
+ public boolean isWrapperFor(final Class<?> iface) throws SQLException {
+ return iface.isInstance(this);
}
/**
* Sets the back end ConnectionPoolDataSource. This property should not be set if using JNDI to access the
* data source.
*
- * @param v
+ * @param dataSource
* Value to assign to connectionPoolDataSource.
*/
- public void setConnectionPoolDataSource(final ConnectionPoolDataSource v) {
+ public void setConnectionPoolDataSource(final ConnectionPoolDataSource dataSource) {
assertInitializationAllowed();
if (dataSourceName != null) {
throw new IllegalStateException("Cannot set the DataSource, if JNDI is used.");
}
- if (dataSource != null) {
+ if (this.dataSource != null) {
throw new IllegalStateException("The CPDS has already been set. It cannot be altered.");
}
- dataSource = v;
+ this.dataSource = dataSource;
instanceKey = InstanceKeyDataSourceFactory.registerNewInstance(this);
}
/**
- * Gets the name of the ConnectionPoolDataSource which backs this pool. This name is used to look up the data source
- * from a JNDI service provider.
- *
- * @return value of dataSourceName.
- */
- public String getDataSourceName() {
- return dataSourceName;
- }
-
- /**
* Sets the name of the ConnectionPoolDataSource which backs this pool. This name is used to look up the data source
* from a JNDI service provider.
*
- * @param v
+ * @param dataSourceName
* Value to assign to dataSourceName.
*/
- public void setDataSourceName(final String v) {
+ public void setDataSourceName(final String dataSourceName) {
assertInitializationAllowed();
if (dataSource != null) {
throw new IllegalStateException("Cannot set the JNDI name for the DataSource, if already "
+ "set using setConnectionPoolDataSource.");
}
- if (dataSourceName != null) {
+ if (this.dataSourceName != null) {
throw new IllegalStateException("The DataSourceName has already been set. " + "It cannot be altered.");
}
- this.dataSourceName = v;
+ this.dataSourceName = dataSourceName;
instanceKey = InstanceKeyDataSourceFactory.registerNewInstance(this);
}
/**
- * Gets the value of defaultAutoCommit, which defines the state of connections handed out from this pool. The value
+ * Sets the value of defaultAutoCommit, which defines the state of connections handed out from this pool. The value
* can be changed on the Connection using Connection.setAutoCommit(boolean). The default is <code>null</code> which
* will use the default value for the drive.
*
- * @return value of defaultAutoCommit.
+ * @param defaultAutoCommit
+ * Value to assign to defaultAutoCommit.
*/
- public Boolean isDefaultAutoCommit() {
- return defaultAutoCommit;
+ public void setDefaultAutoCommit(final Boolean defaultAutoCommit) {
+ assertInitializationAllowed();
+ this.defaultAutoCommit = defaultAutoCommit;
}
/**
- * Sets the value of defaultAutoCommit, which defines the state of connections handed out from this pool. The value
- * can be changed on the Connection using Connection.setAutoCommit(boolean). The default is <code>null</code> which
- * will use the default value for the drive.
+ * Sets the default value for {@link GenericKeyedObjectPoolConfig#getBlockWhenExhausted()} for each per user pool.
*
- * @param v
- * Value to assign to defaultAutoCommit.
+ * @param blockWhenExhausted
+ * The default value for {@link GenericKeyedObjectPoolConfig#getBlockWhenExhausted()} for each per user
+ * pool.
*/
- public void setDefaultAutoCommit(final Boolean v) {
+ public void setDefaultBlockWhenExhausted(final boolean blockWhenExhausted) {
assertInitializationAllowed();
- this.defaultAutoCommit = v;
+ this.defaultBlockWhenExhausted = blockWhenExhausted;
}
/**
- * Gets the value of defaultReadOnly, which defines the state of connections handed out from this pool. The value
- * can be changed on the Connection using Connection.setReadOnly(boolean). The default is <code>null</code> which
- * will use the default value for the drive.
+ * Sets the default value for {@link GenericObjectPool#getDurationBetweenEvictionRuns ()} for each per user pool.
*
- * @return value of defaultReadOnly.
+ * @param defaultDurationBetweenEvictionRuns The default value for
+ * {@link GenericObjectPool#getDurationBetweenEvictionRuns ()} for each per user pool.
+ * @since 2.10.0
*/
- public Boolean isDefaultReadOnly() {
- return defaultReadOnly;
+ public void setDefaultDurationBetweenEvictionRuns(final Duration defaultDurationBetweenEvictionRuns) {
+ assertInitializationAllowed();
+ this.defaultDurationBetweenEvictionRuns = defaultDurationBetweenEvictionRuns;
+ }
+
+ /**
+ * Sets the default value for {@link GenericKeyedObjectPoolConfig#getEvictionPolicyClassName()} for each per user
+ * pool.
+ *
+ * @param evictionPolicyClassName
+ * The default value for {@link GenericKeyedObjectPoolConfig#getEvictionPolicyClassName()} for each per
+ * user pool.
+ */
+ public void setDefaultEvictionPolicyClassName(final String evictionPolicyClassName) {
+ assertInitializationAllowed();
+ this.defaultEvictionPolicyClassName = evictionPolicyClassName;
+ }
+
+ /**
+ * Sets the default value for {@link GenericKeyedObjectPoolConfig#getLifo()} for each per user pool.
+ *
+ * @param lifo
+ * The default value for {@link GenericKeyedObjectPoolConfig#getLifo()} for each per user pool.
+ */
+ public void setDefaultLifo(final boolean lifo) {
+ assertInitializationAllowed();
+ this.defaultLifo = lifo;
+ }
+
+ /**
+ * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMaxIdlePerKey()} for each per user pool.
+ *
+ * @param maxIdle
+ * The default value for {@link GenericKeyedObjectPoolConfig#getMaxIdlePerKey()} for each per user pool.
+ */
+ public void setDefaultMaxIdle(final int maxIdle) {
+ assertInitializationAllowed();
+ this.defaultMaxIdle = maxIdle;
+ }
+
+ /**
+ * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMaxTotalPerKey()} for each per user pool.
+ *
+ * @param maxTotal
+ * The default value for {@link GenericKeyedObjectPoolConfig#getMaxTotalPerKey()} for each per user pool.
+ */
+ public void setDefaultMaxTotal(final int maxTotal) {
+ assertInitializationAllowed();
+ this.defaultMaxTotal = maxTotal;
+ }
+
+ /**
+ * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitDuration()} for each per user pool.
+ *
+ * @param maxWaitMillis
+ * The default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitDuration()} for each per user pool.
+ * @since 2.9.0
+ */
+ public void setDefaultMaxWait(final Duration maxWaitMillis) {
+ assertInitializationAllowed();
+ this.defaultMaxWaitDuration = maxWaitMillis;
+ }
+
+ /**
+ * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitMillis()} for each per user pool.
+ *
+ * @param maxWaitMillis
+ * The default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitMillis()} for each per user pool.
+ * @deprecated Use {@link #setDefaultMaxWait(Duration)}.
+ */
+ @Deprecated
+ public void setDefaultMaxWaitMillis(final long maxWaitMillis) {
+ setDefaultMaxWait(Duration.ofMillis(maxWaitMillis));
+ }
+
+ /**
+ * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleDuration()} for each per user
+ * pool.
+ *
+ * @param defaultMinEvictableIdleDuration
+ * The default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleDuration()} for each
+ * per user pool.
+ * @since 2.10.0
+ */
+ public void setDefaultMinEvictableIdle(final Duration defaultMinEvictableIdleDuration) {
+ assertInitializationAllowed();
+ this.defaultMinEvictableIdleDuration = defaultMinEvictableIdleDuration;
+ }
+
+ /**
+ * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleDuration()} for each per user
+ * pool.
+ *
+ * @param minEvictableIdleTimeMillis
+ * The default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleDuration()} for each
+ * per user pool.
+ * @deprecated Use {@link #setDefaultMinEvictableIdle(Duration)}.
+ */
+ @Deprecated
+ public void setDefaultMinEvictableIdleTimeMillis(final long minEvictableIdleTimeMillis) {
+ assertInitializationAllowed();
+ this.defaultMinEvictableIdleDuration = Duration.ofMillis(minEvictableIdleTimeMillis);
+ }
+
+ /**
+ * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMinIdlePerKey()} for each per user pool.
+ *
+ * @param minIdle
+ * The default value for {@link GenericKeyedObjectPoolConfig#getMinIdlePerKey()} for each per user pool.
+ */
+ public void setDefaultMinIdle(final int minIdle) {
+ assertInitializationAllowed();
+ this.defaultMinIdle = minIdle;
+ }
+
+ /**
+ * Sets the default value for {@link GenericKeyedObjectPoolConfig#getNumTestsPerEvictionRun()} for each per user
+ * pool.
+ *
+ * @param numTestsPerEvictionRun
+ * The default value for {@link GenericKeyedObjectPoolConfig#getNumTestsPerEvictionRun()} for each per
+ * user pool.
+ */
+ public void setDefaultNumTestsPerEvictionRun(final int numTestsPerEvictionRun) {
+ assertInitializationAllowed();
+ this.defaultNumTestsPerEvictionRun = numTestsPerEvictionRun;
}
/**
@@ -618,103 +907,140 @@ public abstract class InstanceKeyDataSource implements DataSource, Referenceable
* can be changed on the Connection using Connection.setReadOnly(boolean). The default is <code>null</code> which
* will use the default value for the drive.
*
- * @param v
+ * @param defaultReadOnly
* Value to assign to defaultReadOnly.
*/
- public void setDefaultReadOnly(final Boolean v) {
+ public void setDefaultReadOnly(final Boolean defaultReadOnly) {
assertInitializationAllowed();
- this.defaultReadOnly = v;
+ this.defaultReadOnly = defaultReadOnly;
}
/**
- * Gets the value of defaultTransactionIsolation, which defines the state of connections handed out from this pool.
- * The value can be changed on the Connection using Connection.setTransactionIsolation(int). If this method returns
- * -1, the default is JDBC driver dependent.
+ * Sets the default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+ * GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool.
*
- * @return value of defaultTransactionIsolation.
+ * @param defaultSoftMinEvictableIdleDuration
+ * The default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+ * GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool.
+ * @since 2.10.0
*/
- public int getDefaultTransactionIsolation() {
- return defaultTransactionIsolation;
+ public void setDefaultSoftMinEvictableIdle(final Duration defaultSoftMinEvictableIdleDuration) {
+ assertInitializationAllowed();
+ this.defaultSoftMinEvictableIdleDuration = defaultSoftMinEvictableIdleDuration;
}
/**
- * Sets the value of defaultTransactionIsolation, which defines the state of connections handed out from this pool.
- * The value can be changed on the Connection using Connection.setTransactionIsolation(int). The default is JDBC
- * driver dependent.
+ * Sets the default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+ * GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool.
*
- * @param v
- * Value to assign to defaultTransactionIsolation
+ * @param softMinEvictableIdleTimeMillis
+ * The default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+ * GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool.
+ * @deprecated Use {@link #setDefaultSoftMinEvictableIdle(Duration)}.
*/
- public void setDefaultTransactionIsolation(final int v) {
+ @Deprecated
+ public void setDefaultSoftMinEvictableIdleTimeMillis(final long softMinEvictableIdleTimeMillis) {
assertInitializationAllowed();
- switch (v) {
- case Connection.TRANSACTION_NONE:
- case Connection.TRANSACTION_READ_COMMITTED:
- case Connection.TRANSACTION_READ_UNCOMMITTED:
- case Connection.TRANSACTION_REPEATABLE_READ:
- case Connection.TRANSACTION_SERIALIZABLE:
- break;
- default:
- throw new IllegalArgumentException(BAD_TRANSACTION_ISOLATION);
- }
- this.defaultTransactionIsolation = v;
+ this.defaultSoftMinEvictableIdleDuration = Duration.ofMillis(softMinEvictableIdleTimeMillis);
}
/**
- * Gets the description. This property is defined by JDBC as for use with GUI (or other) tools that might deploy the
- * datasource. It serves no internal purpose.
+ * Sets the default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+ * GenericObjectPool#getTestOnBorrow()} for each per user pool.
*
- * @return value of description.
+ * @param testOnBorrow
+ * The default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+ * GenericObjectPool#getTestOnBorrow()} for each per user pool.
*/
- public String getDescription() {
- return description;
+ public void setDefaultTestOnBorrow(final boolean testOnBorrow) {
+ assertInitializationAllowed();
+ this.defaultTestOnBorrow = testOnBorrow;
}
/**
- * Sets the description. This property is defined by JDBC as for use with GUI (or other) tools that might deploy the
- * datasource. It serves no internal purpose.
+ * Sets the default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+ * GenericObjectPool#getTestOnCreate()} for each per user pool.
*
- * @param v
- * Value to assign to description.
+ * @param testOnCreate
+ * The default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+ * GenericObjectPool#getTestOnCreate()} for each per user pool.
+ */
+ public void setDefaultTestOnCreate(final boolean testOnCreate) {
+ assertInitializationAllowed();
+ this.defaultTestOnCreate = testOnCreate;
+ }
+
+ /**
+ * Sets the default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+ * GenericObjectPool#getTestOnReturn()} for each per user pool.
+ *
+ * @param testOnReturn
+ * The default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+ * GenericObjectPool#getTestOnReturn()} for each per user pool.
*/
- public void setDescription(final String v) {
- this.description = v;
+ public void setDefaultTestOnReturn(final boolean testOnReturn) {
+ assertInitializationAllowed();
+ this.defaultTestOnReturn = testOnReturn;
}
- protected String getInstanceKey() {
- return instanceKey;
+ /**
+ * Sets the default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+ * GenericObjectPool#getTestWhileIdle()} for each per user pool.
+ *
+ * @param testWhileIdle
+ * The default value for {@link org.apache.tomcat.dbcp.pool2.impl.GenericObjectPool
+ * GenericObjectPool#getTestWhileIdle()} for each per user pool.
+ */
+ public void setDefaultTestWhileIdle(final boolean testWhileIdle) {
+ assertInitializationAllowed();
+ this.defaultTestWhileIdle = testWhileIdle;
}
/**
- * Gets the value of jndiEnvironment which is used when instantiating a JNDI InitialContext. This InitialContext is
- * used to locate the back end ConnectionPoolDataSource.
+ * Sets the default value for {@link GenericObjectPool#getDurationBetweenEvictionRuns()} for each per user pool.
*
- * @param key
- * JNDI environment key.
- * @return value of jndiEnvironment.
+ * @param timeBetweenEvictionRunsMillis The default value for
+ * {@link GenericObjectPool#getDurationBetweenEvictionRuns()} for each per user pool.
+ * @deprecated Use {@link #setDefaultDurationBetweenEvictionRuns(Duration)}.
*/
- public String getJndiEnvironment(final String key) {
- String value = null;
- if (jndiEnvironment != null) {
- value = jndiEnvironment.getProperty(key);
+ @Deprecated
+ public void setDefaultTimeBetweenEvictionRunsMillis(final long timeBetweenEvictionRunsMillis) {
+ assertInitializationAllowed();
+ this.defaultDurationBetweenEvictionRuns = Duration.ofMillis(timeBetweenEvictionRunsMillis);
+ }
+
+ /**
+ * Sets the value of defaultTransactionIsolation, which defines the state of connections handed out from this pool.
+ * The value can be changed on the Connection using Connection.setTransactionIsolation(int). The default is JDBC
+ * driver dependent.
+ *
+ * @param defaultTransactionIsolation
+ * Value to assign to defaultTransactionIsolation
+ */
+ public void setDefaultTransactionIsolation(final int defaultTransactionIsolation) {
+ assertInitializationAllowed();
+ switch (defaultTransactionIsolation) {
+ case Connection.TRANSACTION_NONE:
+ case Connection.TRANSACTION_READ_COMMITTED:
+ case Connection.TRANSACTION_READ_UNCOMMITTED:
+ case Connection.TRANSACTION_REPEATABLE_READ:
+ case Connection.TRANSACTION_SERIALIZABLE:
+ break;
+ default:
+ throw new IllegalArgumentException(BAD_TRANSACTION_ISOLATION);
}
- return value;
+ this.defaultTransactionIsolation = defaultTransactionIsolation;
}
/**
- * Sets the value of the given JNDI environment property to be used when instantiating a JNDI InitialContext. This
- * InitialContext is used to locate the back end ConnectionPoolDataSource.
+ * Sets the description. This property is defined by JDBC as for use with GUI (or other) tools that might deploy the
+ * datasource. It serves no internal purpose.
*
- * @param key
- * the JNDI environment property to set.
- * @param value
- * the value assigned to specified JNDI environment property.
+ * @param description
+ * Value to assign to description.
*/
- public void setJndiEnvironment(final String key, final String value) {
- if (jndiEnvironment == null) {
- jndiEnvironment = new Properties();
- }
- jndiEnvironment.setProperty(key, value);
+ public void setDescription(final String description) {
+ this.description = description;
}
/**
@@ -734,103 +1060,95 @@ public abstract class InstanceKeyDataSource implements DataSource, Referenceable
}
/**
- * Gets the value of loginTimeout.
+ * Sets the value of the given JNDI environment property to be used when instantiating a JNDI InitialContext. This
+ * InitialContext is used to locate the back end ConnectionPoolDataSource.
*
- * @return value of loginTimeout.
+ * @param key
+ * the JNDI environment property to set.
+ * @param value
+ * the value assigned to specified JNDI environment property.
*/
- @Override
- public int getLoginTimeout() {
- return loginTimeout;
+ public void setJndiEnvironment(final String key, final String value) {
+ if (jndiEnvironment == null) {
+ jndiEnvironment = new Properties();
+ }
+ jndiEnvironment.setProperty(key, value);
}
/**
* Sets the value of loginTimeout.
*
- * @param v
+ * @param loginTimeout
* Value to assign to loginTimeout.
+ * @since 2.10.0
*/
- @Override
- public void setLoginTimeout(final int v) {
- this.loginTimeout = v;
+ public void setLoginTimeout(final Duration loginTimeout) {
+ this.loginTimeoutDuration = loginTimeout;
}
/**
- * Gets the value of logWriter.
+ * Sets the value of loginTimeout.
*
- * @return value of logWriter.
+ * @param loginTimeout
+ * Value to assign to loginTimeout.
+ * @deprecated Use {@link #setLoginTimeout(Duration)}.
*/
+ @Deprecated
@Override
- public PrintWriter getLogWriter() {
- if (logWriter == null) {
- logWriter = new PrintWriter(new OutputStreamWriter(System.out, StandardCharsets.UTF_8));
- }
- return logWriter;
+ public void setLoginTimeout(final int loginTimeout) {
+ this.loginTimeoutDuration = Duration.ofSeconds(loginTimeout);
}
/**
* Sets the value of logWriter.
*
- * @param v
+ * @param logWriter
* Value to assign to logWriter.
*/
@Override
- public void setLogWriter(final PrintWriter v) {
- this.logWriter = v;
- }
-
- /**
- * Gets the SQL query that will be used to validate connections from this pool before returning them to the caller.
- * If specified, this query <strong>MUST</strong> be an SQL SELECT statement that returns at least one row. If not
- * specified, {@link Connection#isValid(int)} will be used to validate connections.
- *
- * @return The SQL query that will be used to validate connections from this pool before returning them to the
- * caller.
- */
- public String getValidationQuery() {
- return this.validationQuery;
- }
-
- /**
- * Sets the SQL query that will be used to validate connections from this pool before returning them to the caller.
- * If specified, this query <strong>MUST</strong> be an SQL SELECT statement that returns at least one row. If not
- * specified, connections will be validated using {@link Connection#isValid(int)}.
- *
- * @param validationQuery
- * The SQL query that will be used to validate connections from this pool before returning them to the
- * caller.
- */
- public void setValidationQuery(final String validationQuery) {
- assertInitializationAllowed();
- this.validationQuery = validationQuery;
- }
-
- /**
- * Returns the timeout in seconds before the validation query fails.
- *
- * @return The timeout in seconds before the validation query fails.
- */
- public int getValidationQueryTimeout() {
- return validationQueryTimeoutSeconds;
+ public void setLogWriter(final PrintWriter logWriter) {
+ this.logWriter = logWriter;
}
/**
- * Sets the timeout in seconds before the validation query fails.
+ * <p>
+ * Sets the maximum permitted lifetime of a connection. A value of zero or less indicates an
+ * infinite lifetime.
+ * </p>
+ * <p>
+ * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+ * time one of the following methods is invoked: <code>getConnection, setLogwriter,
+ * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+ * </p>
*
- * @param validationQueryTimeoutSeconds
- * The new timeout in seconds
+ * @param maxConnLifetimeMillis
+ * The maximum permitted lifetime of a connection. A value of zero or less indicates an
+ * infinite lifetime.
+ * @since 2.9.0
*/
- public void setValidationQueryTimeout(final int validationQueryTimeoutSeconds) {
- this.validationQueryTimeoutSeconds = validationQueryTimeoutSeconds;
+ public void setMaxConnLifetime(final Duration maxConnLifetimeMillis) {
+ this.maxConnDuration = maxConnLifetimeMillis;
}
/**
- * Whether a rollback will be issued after executing the SQL query that will be used to validate connections from
- * this pool before returning them to the caller.
+ * <p>
+ * Sets the maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an
+ * infinite lifetime.
+ * </p>
+ * <p>
+ * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+ * time one of the following methods is invoked: <code>getConnection, setLogwriter,
+ * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+ * </p>
*
- * @return true if a rollback will be issued after executing the validation query
+ * @param maxConnLifetimeMillis
+ * The maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an
+ * infinite lifetime.
+ * @deprecated Use {@link #setMaxConnLifetime(Duration)}.
*/
- public boolean isRollbackAfterValidation() {
- return this.rollbackAfterValidation;
+ @Deprecated
+ public void setMaxConnLifetimeMillis(final long maxConnLifetimeMillis) {
+ setMaxConnLifetime(Duration.ofMillis(maxConnLifetimeMillis));
}
/**
@@ -846,157 +1164,42 @@ public abstract class InstanceKeyDataSource implements DataSource, Referenceable
this.rollbackAfterValidation = rollbackAfterValidation;
}
- /**
- * Returns the maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an
- * infinite lifetime.
- *
- * @return The maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an
- * infinite lifetime.
- */
- public long getMaxConnLifetimeMillis() {
- return maxConnLifetimeMillis;
- }
+ protected abstract void setupDefaults(Connection connection, String userName) throws SQLException;
/**
- * <p>
- * Sets the maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an
- * infinite lifetime.
- * </p>
- * <p>
- * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
- * time one of the following methods is invoked: <code>getConnection, setLogwriter,
- * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
- * </p>
+ * Sets the SQL query that will be used to validate connections from this pool before returning them to the caller.
+ * If specified, this query <strong>MUST</strong> be an SQL SELECT statement that returns at least one row. If not
+ * specified, connections will be validated using {@link Connection#isValid(int)}.
*
- * @param maxConnLifetimeMillis
- * The maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an
- * infinite lifetime.
+ * @param validationQuery
+ * The SQL query that will be used to validate connections from this pool before returning them to the
+ * caller.
*/
- public void setMaxConnLifetimeMillis(final long maxConnLifetimeMillis) {
- this.maxConnLifetimeMillis = maxConnLifetimeMillis;
+ public void setValidationQuery(final String validationQuery) {
+ assertInitializationAllowed();
+ this.validationQuery = validationQuery;
}
- // ----------------------------------------------------------------------
- // Instrumentation Methods
-
- // ----------------------------------------------------------------------
- // DataSource implementation
-
/**
- * Attempts to establish a database connection.
+ * Sets the timeout duration before the validation query fails.
+ *
+ * @param validationQueryTimeoutDuration
+ * The new timeout duration.
*/
- @Override
- public Connection getConnection() throws SQLException {
- return getConnection(null, null);
+ public void setValidationQueryTimeout(final Duration validationQueryTimeoutDuration) {
+ this.validationQueryTimeoutDuration = validationQueryTimeoutDuration;
}
/**
- * Attempts to retrieve a database connection using {@link #getPooledConnectionAndInfo(String, String)} with the
- * provided user name and password. The password on the {@link PooledConnectionAndInfo} instance returned by
- * <code>getPooledConnectionAndInfo</code> is compared to the <code>password</code> parameter. If the comparison
- * fails, a database connection using the supplied user name and password is attempted. If the connection attempt
- * fails, an SQLException is thrown, indicating that the given password did not match the password used to create
- * the pooled connection. If the connection attempt succeeds, this means that the database password has been
- * changed. In this case, the <code>PooledConnectionAndInfo</code> instance retrieved with the old password is
- * destroyed and the <code>getPooledConnectionAndInfo</code> is repeatedly invoked until a
- * <code>PooledConnectionAndInfo</code> instance with the new password is returned.
+ * Sets the timeout in seconds before the validation query fails.
+ *
+ * @param validationQueryTimeoutSeconds
+ * The new timeout in seconds
+ * @deprecated Use {@link #setValidationQueryTimeout(Duration)}.
*/
- @Override
- public Connection getConnection(final String userName, final String userPassword) throws SQLException {
- if (instanceKey == null) {
- throw new SQLException("Must set the ConnectionPoolDataSource "
- + "through setDataSourceName or setConnectionPoolDataSource" + " before calling getConnection.");
- }
- getConnectionCalled = true;
- PooledConnectionAndInfo info = null;
- try {
- info = getPooledConnectionAndInfo(userName, userPassword);
- } catch (final RuntimeException | SQLException e) {
- closeDueToException(info);
- throw e;
- } catch (final Exception e) {
- closeDueToException(info);
- throw new SQLException("Cannot borrow connection from pool", e);
- }
-
- // Password on PooledConnectionAndInfo does not match
- if (!(null == userPassword ? null == info.getPassword() : userPassword.equals(info.getPassword()))) {
- try { // See if password has changed by attempting connection
- testCPDS(userName, userPassword);
- } catch (final SQLException ex) {
- // Password has not changed, so refuse client, but return connection to the pool
- closeDueToException(info);
- throw new SQLException(
- "Given password did not match password used" + " to create the PooledConnection.", ex);
- } catch (final javax.naming.NamingException ne) {
- throw new SQLException("NamingException encountered connecting to database", ne);
- }
- /*
- * Password must have changed -> destroy connection and keep retrying until we get a new, good one,
- * destroying any idle connections with the old password as we pull them from the pool.
- */
- final UserPassKey upkey = info.getUserPassKey();
- final PooledConnectionManager manager = getConnectionManager(upkey);
- // Destroy and remove from pool
- manager.invalidate(info.getPooledConnection());
- // Reset the password on the factory if using CPDSConnectionFactory
- manager.setPassword(upkey.getPassword());
- info = null;
- for (int i = 0; i < 10; i++) { // Bound the number of retries - only needed if bad instances return
- try {
- info = getPooledConnectionAndInfo(userName, userPassword);
- } catch (final RuntimeException | SQLException e) {
- closeDueToException(info);
- throw e;
- } catch (final Exception e) {
- closeDueToException(info);
- throw new SQLException("Cannot borrow connection from pool", e);
- }
- if (info != null && userPassword != null && userPassword.equals(info.getPassword())) {
- break;
- }
- if (info != null) {
- manager.invalidate(info.getPooledConnection());
- }
- info = null;
- }
- if (info == null) {
- throw new SQLException("Cannot borrow connection from pool - password change failure.");
- }
- }
-
- final Connection con = info.getPooledConnection().getConnection();
- try {
- setupDefaults(con, userName);
- con.clearWarnings();
- return con;
- } catch (final SQLException ex) {
- try {
- con.close();
- } catch (final Exception exc) {
- getLogWriter().println("ignoring exception during close: " + exc);
- }
- throw ex;
- }
- }
-
- protected abstract PooledConnectionAndInfo getPooledConnectionAndInfo(String userName, String userPassword)
- throws SQLException;
-
- protected abstract void setupDefaults(Connection connection, String userName) throws SQLException;
-
- private void closeDueToException(final PooledConnectionAndInfo info) {
- if (info != null) {
- try {
- info.getPooledConnection().getConnection().close();
- } catch (final Exception e) {
- // do not throw this exception because we are in the middle
- // of handling another exception. But record it because
- // it potentially leaks connections from the pool.
- getLogWriter().println("[ERROR] Could not return connection to " + "pool during exception handling. "
- + e.getMessage());
- }
- }
+ @Deprecated
+ public void setValidationQueryTimeout(final int validationQueryTimeoutSeconds) {
+ this.validationQueryTimeoutDuration = Duration.ofSeconds(validationQueryTimeoutSeconds);
}
protected ConnectionPoolDataSource testCPDS(final String userName, final String userPassword)
@@ -1011,12 +1214,11 @@ public abstract class InstanceKeyDataSource implements DataSource, Referenceable
ctx = new InitialContext(jndiEnvironment);
}
final Object ds = ctx.lookup(dataSourceName);
- if (ds instanceof ConnectionPoolDataSource) {
- cpds = (ConnectionPoolDataSource) ds;
- } else {
+ if (!(ds instanceof ConnectionPoolDataSource)) {
throw new SQLException("Illegal configuration: " + "DataSource " + dataSourceName + " ("
+ ds.getClass().getName() + ")" + " doesn't implement javax.sql.ConnectionPoolDataSource");
}
+ cpds = (ConnectionPoolDataSource) ds;
}
// try to get a connection with the supplied userName/password
@@ -1065,8 +1267,8 @@ public abstract class InstanceKeyDataSource implements DataSource, Referenceable
builder.append(description);
builder.append(", jndiEnvironment=");
builder.append(jndiEnvironment);
- builder.append(", loginTimeout=");
- builder.append(loginTimeout);
+ builder.append(", loginTimeoutDuration=");
+ builder.append(loginTimeoutDuration);
builder.append(", logWriter=");
builder.append(logWriter);
builder.append(", instanceKey=");
@@ -1081,16 +1283,16 @@ public abstract class InstanceKeyDataSource implements DataSource, Referenceable
builder.append(defaultMaxIdle);
builder.append(", defaultMaxTotal=");
builder.append(defaultMaxTotal);
- builder.append(", defaultMaxWaitMillis=");
- builder.append(defaultMaxWaitMillis);
- builder.append(", defaultMinEvictableIdleTimeMillis=");
- builder.append(defaultMinEvictableIdleTimeMillis);
+ builder.append(", defaultMaxWaitDuration=");
+ builder.append(defaultMaxWaitDuration);
+ builder.append(", defaultMinEvictableIdleDuration=");
+ builder.append(defaultMinEvictableIdleDuration);
builder.append(", defaultMinIdle=");
builder.append(defaultMinIdle);
builder.append(", defaultNumTestsPerEvictionRun=");
builder.append(defaultNumTestsPerEvictionRun);
- builder.append(", defaultSoftMinEvictableIdleTimeMillis=");
- builder.append(defaultSoftMinEvictableIdleTimeMillis);
+ builder.append(", defaultSoftMinEvictableIdleDuration=");
+ builder.append(defaultSoftMinEvictableIdleDuration);
builder.append(", defaultTestOnCreate=");
builder.append(defaultTestOnCreate);
builder.append(", defaultTestOnBorrow=");
@@ -1099,16 +1301,16 @@ public abstract class InstanceKeyDataSource implements DataSource, Referenceable
builder.append(defaultTestOnReturn);
builder.append(", defaultTestWhileIdle=");
builder.append(defaultTestWhileIdle);
- builder.append(", defaultTimeBetweenEvictionRunsMillis=");
- builder.append(defaultTimeBetweenEvictionRunsMillis);
+ builder.append(", defaultDurationBetweenEvictionRuns=");
+ builder.append(defaultDurationBetweenEvictionRuns);
builder.append(", validationQuery=");
builder.append(validationQuery);
- builder.append(", validationQueryTimeoutSeconds=");
- builder.append(validationQueryTimeoutSeconds);
+ builder.append(", validationQueryTimeoutDuration=");
+ builder.append(validationQueryTimeoutDuration);
builder.append(", rollbackAfterValidation=");
builder.append(rollbackAfterValidation);
- builder.append(", maxConnLifetimeMillis=");
- builder.append(maxConnLifetimeMillis);
+ builder.append(", maxConnDuration=");
+ builder.append(maxConnDuration);
builder.append(", defaultAutoCommit=");
builder.append(defaultAutoCommit);
builder.append(", defaultTransactionIsolation=");
@@ -1116,4 +1318,14 @@ public abstract class InstanceKeyDataSource implements DataSource, Referenceable
builder.append(", defaultReadOnly=");
builder.append(defaultReadOnly);
}
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> T unwrap(final Class<T> iface) throws SQLException {
+ if (isWrapperFor(iface)) {
+ return (T) this;
+ }
+ throw new SQLException(this + " is not a wrapper for " + iface);
+ }
+ /* JDBC_4_ANT_KEY_END */
}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSourceFactory.java b/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSourceFactory.java
index defa46a..ad01b8a 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSourceFactory.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSourceFactory.java
@@ -19,6 +19,7 @@ package org.apache.tomcat.dbcp.dbcp2.datasources;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
+import java.time.Duration;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
@@ -34,6 +35,7 @@ import javax.naming.Reference;
import javax.naming.spi.ObjectFactory;
import org.apache.tomcat.dbcp.dbcp2.ListException;
+import org.apache.tomcat.dbcp.dbcp2.Utils;
/**
* A JNDI ObjectFactory which creates <code>SharedPoolDataSource</code>s or <code>PerUserPoolDataSource</code>s
@@ -42,31 +44,7 @@ import org.apache.tomcat.dbcp.dbcp2.ListException;
*/
abstract class InstanceKeyDataSourceFactory implements ObjectFactory {
- private static final Map<String, InstanceKeyDataSource> instanceMap = new ConcurrentHashMap<>();
-
- static synchronized String registerNewInstance(final InstanceKeyDataSource ds) {
- int max = 0;
- for (final String s : instanceMap.keySet()) {
- if (s != null) {
- try {
- max = Math.max(max, Integer.parseInt(s));
- } catch (final NumberFormatException e) {
- // no sweat, ignore those keys
- }
- }
- }
- final String instanceKey = String.valueOf(max + 1);
- // Put a placeholder here for now, so other instances will not
- // take our key. We will replace with a pool when ready.
- instanceMap.put(instanceKey, ds);
- return instanceKey;
- }
-
- static void removeInstance(final String key) {
- if (key != null) {
- instanceMap.remove(key);
- }
- }
+ private static final Map<String, InstanceKeyDataSource> INSTANCE_MAP = new ConcurrentHashMap<>();
/**
* Closes all pools associated with this class.
@@ -80,8 +58,8 @@ abstract class InstanceKeyDataSourceFactory implements ObjectFactory {
*/
public static void closeAll() throws Exception {
// Get iterator to loop over all instances of this data source.
- final List<Throwable> exceptionList = new ArrayList<>(instanceMap.size());
- for (final Entry<String, InstanceKeyDataSource> next : instanceMap.entrySet()) {
+ final List<Throwable> exceptionList = new ArrayList<>(INSTANCE_MAP.size());
+ for (final Entry<String, InstanceKeyDataSource> next : INSTANCE_MAP.entrySet()) {
// Bullet-proof to avoid anything else but problems from InstanceKeyDataSource#close().
if (next != null) {
final InstanceKeyDataSource value = next.getValue();
@@ -94,13 +72,75 @@ abstract class InstanceKeyDataSourceFactory implements ObjectFactory {
}
}
}
- instanceMap.clear();
+ INSTANCE_MAP.clear();
if (!exceptionList.isEmpty()) {
throw new ListException("Could not close all InstanceKeyDataSource instances.", exceptionList);
}
}
/**
+ * Deserializes the provided byte array to create an object.
+ *
+ * @param data
+ * Data to deserialize to create the configuration parameter.
+ *
+ * @return The Object created by deserializing the data.
+ *
+ * @throws ClassNotFoundException
+ * If a class cannot be found during the deserialization of a configuration parameter.
+ * @throws IOException
+ * If an I/O error occurs during the deserialization of a configuration parameter.
+ */
+ protected static final Object deserialize(final byte[] data) throws IOException, ClassNotFoundException {
+ ObjectInputStream in = null;
+ try {
+ in = new ObjectInputStream(new ByteArrayInputStream(data));
+ return in.readObject();
+ } finally {
+ Utils.closeQuietly(in);
+ }
+ }
+
+ static synchronized String registerNewInstance(final InstanceKeyDataSource ds) {
+ int max = 0;
+ for (final String s : INSTANCE_MAP.keySet()) {
+ if (s != null) {
+ try {
+ max = Math.max(max, Integer.parseInt(s));
+ } catch (final NumberFormatException e) {
+ // no sweat, ignore those keys
+ }
+ }
+ }
+ final String instanceKey = String.valueOf(max + 1);
+ // Put a placeholder here for now, so other instances will not
+ // take our key. We will replace with a pool when ready.
+ INSTANCE_MAP.put(instanceKey, ds);
+ return instanceKey;
+ }
+
+ static void removeInstance(final String key) {
+ if (key != null) {
+ INSTANCE_MAP.remove(key);
+ }
+ }
+
+ /**
+ * Creates an instance of the subclass and sets any properties contained in the Reference.
+ *
+ * @param ref
+ * The properties to be set on the created DataSource
+ *
+ * @return A configured DataSource of the appropriate type.
+ *
+ * @throws ClassNotFoundException
+ * If a class cannot be found during the deserialization of a configuration parameter.
+ * @throws IOException
+ * If an I/O error occurs during the deserialization of a configuration parameter.
+ */
+ protected abstract InstanceKeyDataSource getNewInstance(Reference ref) throws IOException, ClassNotFoundException;
+
+ /**
* Implements ObjectFactory to create an instance of SharedPoolDataSource or PerUserPoolDataSource
*/
@Override
@@ -115,7 +155,7 @@ abstract class InstanceKeyDataSourceFactory implements ObjectFactory {
final RefAddr refAddr = ref.get("instanceKey");
if (refAddr != null && refAddr.getContent() != null) {
// object was bound to JNDI via Referenceable API.
- obj = instanceMap.get(refAddr.getContent());
+ obj = INSTANCE_MAP.get(refAddr.getContent());
} else {
// Tomcat JNDI creates a Reference out of server.xml
// <ResourceParam> configuration and passes it to an
@@ -123,14 +163,14 @@ abstract class InstanceKeyDataSourceFactory implements ObjectFactory {
String key = null;
if (name != null) {
key = name.toString();
- obj = instanceMap.get(key);
+ obj = INSTANCE_MAP.get(key);
}
if (obj == null) {
final InstanceKeyDataSource ds = getNewInstance(ref);
setCommonProperties(ref, ds);
obj = ds;
if (key != null) {
- instanceMap.put(key, ds);
+ INSTANCE_MAP.put(key, ds);
}
}
}
@@ -139,17 +179,39 @@ abstract class InstanceKeyDataSourceFactory implements ObjectFactory {
return obj;
}
+ /**
+ * Tests if className is the value returned from getClass().getName().toString().
+ *
+ * @param className
+ * The class name to test.
+ *
+ * @return true if and only if className is the value returned from getClass().getName().toString()
+ */
+ protected abstract boolean isCorrectClass(String className);
+
+ boolean parseBoolean(final RefAddr refAddr) {
+ return Boolean.parseBoolean(toString(refAddr));
+ }
+
+ int parseInt(final RefAddr refAddr) {
+ return Integer.parseInt(toString(refAddr));
+ }
+
+ long parseLong(final RefAddr refAddr) {
+ return Long.parseLong(toString(refAddr));
+ }
+
private void setCommonProperties(final Reference ref, final InstanceKeyDataSource ikds)
throws IOException, ClassNotFoundException {
RefAddr refAddr = ref.get("dataSourceName");
if (refAddr != null && refAddr.getContent() != null) {
- ikds.setDataSourceName(refAddr.getContent().toString());
+ ikds.setDataSourceName(toString(refAddr));
}
refAddr = ref.get("description");
if (refAddr != null && refAddr.getContent() != null) {
- ikds.setDescription(refAddr.getContent().toString());
+ ikds.setDescription(toString(refAddr));
}
refAddr = ref.get("jndiEnvironment");
@@ -160,175 +222,127 @@ abstract class InstanceKeyDataSourceFactory implements ObjectFactory {
refAddr = ref.get("loginTimeout");
if (refAddr != null && refAddr.getContent() != null) {
- ikds.setLoginTimeout(Integer.parseInt(refAddr.getContent().toString()));
+ ikds.setLoginTimeout(Duration.ofSeconds(parseInt(refAddr)));
}
// Pool properties
refAddr = ref.get("blockWhenExhausted");
if (refAddr != null && refAddr.getContent() != null) {
- ikds.setDefaultBlockWhenExhausted(Boolean.parseBoolean(refAddr.getContent().toString()));
+ ikds.setDefaultBlockWhenExhausted(parseBoolean(refAddr));
}
refAddr = ref.get("evictionPolicyClassName");
if (refAddr != null && refAddr.getContent() != null) {
- ikds.setDefaultEvictionPolicyClassName(refAddr.getContent().toString());
+ ikds.setDefaultEvictionPolicyClassName(toString(refAddr));
}
// Pool properties
refAddr = ref.get("lifo");
if (refAddr != null && refAddr.getContent() != null) {
- ikds.setDefaultLifo(Boolean.parseBoolean(refAddr.getContent().toString()));
+ ikds.setDefaultLifo(parseBoolean(refAddr));
}
refAddr = ref.get("maxIdlePerKey");
if (refAddr != null && refAddr.getContent() != null) {
- ikds.setDefaultMaxIdle(Integer.parseInt(refAddr.getContent().toString()));
+ ikds.setDefaultMaxIdle(parseInt(refAddr));
}
refAddr = ref.get("maxTotalPerKey");
if (refAddr != null && refAddr.getContent() != null) {
- ikds.setDefaultMaxTotal(Integer.parseInt(refAddr.getContent().toString()));
+ ikds.setDefaultMaxTotal(parseInt(refAddr));
}
refAddr = ref.get("maxWaitMillis");
if (refAddr != null && refAddr.getContent() != null) {
- ikds.setDefaultMaxWaitMillis(Long.parseLong(refAddr.getContent().toString()));
+ ikds.setDefaultMaxWait(Duration.ofMillis(parseLong(refAddr)));
}
refAddr = ref.get("minEvictableIdleTimeMillis");
if (refAddr != null && refAddr.getContent() != null) {
- ikds.setDefaultMinEvictableIdleTimeMillis(Long.parseLong(refAddr.getContent().toString()));
+ ikds.setDefaultMinEvictableIdle(Duration.ofMillis(parseLong(refAddr)));
}
refAddr = ref.get("minIdlePerKey");
if (refAddr != null && refAddr.getContent() != null) {
- ikds.setDefaultMinIdle(Integer.parseInt(refAddr.getContent().toString()));
+ ikds.setDefaultMinIdle(parseInt(refAddr));
}
refAddr = ref.get("numTestsPerEvictionRun");
if (refAddr != null && refAddr.getContent() != null) {
- ikds.setDefaultNumTestsPerEvictionRun(Integer.parseInt(refAddr.getContent().toString()));
+ ikds.setDefaultNumTestsPerEvictionRun(parseInt(refAddr));
}
refAddr = ref.get("softMinEvictableIdleTimeMillis");
if (refAddr != null && refAddr.getContent() != null) {
- ikds.setDefaultSoftMinEvictableIdleTimeMillis(Long.parseLong(refAddr.getContent().toString()));
+ ikds.setDefaultSoftMinEvictableIdle(Duration.ofMillis(parseLong(refAddr)));
}
refAddr = ref.get("testOnCreate");
if (refAddr != null && refAddr.getContent() != null) {
- ikds.setDefaultTestOnCreate(Boolean.parseBoolean(refAddr.getContent().toString()));
+ ikds.setDefaultTestOnCreate(parseBoolean(refAddr));
}
refAddr = ref.get("testOnBorrow");
if (refAddr != null && refAddr.getContent() != null) {
- ikds.setDefaultTestOnBorrow(Boolean.parseBoolean(refAddr.getContent().toString()));
+ ikds.setDefaultTestOnBorrow(parseBoolean(refAddr));
}
refAddr = ref.get("testOnReturn");
if (refAddr != null && refAddr.getContent() != null) {
- ikds.setDefaultTestOnReturn(Boolean.parseBoolean(refAddr.getContent().toString()));
+ ikds.setDefaultTestOnReturn(parseBoolean(refAddr));
}
refAddr = ref.get("testWhileIdle");
if (refAddr != null && refAddr.getContent() != null) {
- ikds.setDefaultTestWhileIdle(Boolean.parseBoolean(refAddr.getContent().toString()));
+ ikds.setDefaultTestWhileIdle(parseBoolean(refAddr));
}
refAddr = ref.get("timeBetweenEvictionRunsMillis");
if (refAddr != null && refAddr.getContent() != null) {
- ikds.setDefaultTimeBetweenEvictionRunsMillis(Long.parseLong(refAddr.getContent().toString()));
+ ikds.setDefaultDurationBetweenEvictionRuns(Duration.ofMillis(parseLong(refAddr)));
}
// Connection factory properties
refAddr = ref.get("validationQuery");
if (refAddr != null && refAddr.getContent() != null) {
- ikds.setValidationQuery(refAddr.getContent().toString());
+ ikds.setValidationQuery(toString(refAddr));
}
refAddr = ref.get("validationQueryTimeout");
if (refAddr != null && refAddr.getContent() != null) {
- ikds.setValidationQueryTimeout(Integer.parseInt(refAddr.getContent().toString()));
+ ikds.setValidationQueryTimeout(Duration.ofSeconds(parseInt(refAddr)));
}
refAddr = ref.get("rollbackAfterValidation");
if (refAddr != null && refAddr.getContent() != null) {
- ikds.setRollbackAfterValidation(Boolean.parseBoolean(refAddr.getContent().toString()));
+ ikds.setRollbackAfterValidation(parseBoolean(refAddr));
}
refAddr = ref.get("maxConnLifetimeMillis");
if (refAddr != null && refAddr.getContent() != null) {
- ikds.setMaxConnLifetimeMillis(Long.parseLong(refAddr.getContent().toString()));
+ ikds.setMaxConnLifetime(Duration.ofMillis(parseLong(refAddr)));
}
// Connection properties
refAddr = ref.get("defaultAutoCommit");
if (refAddr != null && refAddr.getContent() != null) {
- ikds.setDefaultAutoCommit(Boolean.valueOf(refAddr.getContent().toString()));
+ ikds.setDefaultAutoCommit(Boolean.valueOf(toString(refAddr)));
}
refAddr = ref.get("defaultTransactionIsolation");
if (refAddr != null && refAddr.getContent() != null) {
- ikds.setDefaultTransactionIsolation(Integer.parseInt(refAddr.getContent().toString()));
+ ikds.setDefaultTransactionIsolation(parseInt(refAddr));
}
refAddr = ref.get("defaultReadOnly");
if (refAddr != null && refAddr.getContent() != null) {
- ikds.setDefaultReadOnly(Boolean.valueOf(refAddr.getContent().toString()));
+ ikds.setDefaultReadOnly(Boolean.valueOf(toString(refAddr)));
}
}
- /**
- * @param className
- * The class name to test.
- *
- * @return true if and only if className is the value returned from getClass().getName().toString()
- */
- protected abstract boolean isCorrectClass(String className);
-
- /**
- * Creates an instance of the subclass and sets any properties contained in the Reference.
- *
- * @param ref
- * The properties to be set on the created DataSource
- *
- * @return A configured DataSource of the appropriate type.
- *
- * @throws ClassNotFoundException
- * If a class cannot be found during the deserialization of a configuration parameter.
- * @throws IOException
- * If an I/O error occurs during the deserialization of a configuration parameter.
- */
- protected abstract InstanceKeyDataSource getNewInstance(Reference ref) throws IOException, ClassNotFoundException;
-
- /**
- * Deserializes the provided byte array to create an object.
- *
- * @param data
- * Data to deserialize to create the configuration parameter.
- *
- * @return The Object created by deserializing the data.
- *
- * @throws ClassNotFoundException
- * If a class cannot be found during the deserialization of a configuration parameter.
- * @throws IOException
- * If an I/O error occurs during the deserialization of a configuration parameter.
- */
- protected static final Object deserialize(final byte[] data) throws IOException, ClassNotFoundException {
- ObjectInputStream in = null;
- try {
- in = new ObjectInputStream(new ByteArrayInputStream(data));
- return in.readObject();
- } finally {
- if (in != null) {
- try {
- in.close();
- } catch (final IOException ex) {
- // ignore
- }
- }
- }
+ String toString(final RefAddr refAddr) {
+ return refAddr.getContent().toString();
}
}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/datasources/KeyedCPDSConnectionFactory.java b/java/org/apache/tomcat/dbcp/dbcp2/datasources/KeyedCPDSConnectionFactory.java
index 77108ee..10595ff 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/datasources/KeyedCPDSConnectionFactory.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/datasources/KeyedCPDSConnectionFactory.java
@@ -20,6 +20,8 @@ import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
+import java.time.Duration;
+import java.time.Instant;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
@@ -50,10 +52,10 @@ class KeyedCPDSConnectionFactory implements KeyedPooledObjectFactory<UserPassKey
private final ConnectionPoolDataSource cpds;
private final String validationQuery;
- private final int validationQueryTimeoutSeconds;
+ private final Duration validationQueryTimeoutDuration;
private final boolean rollbackAfterValidation;
private KeyedObjectPool<UserPassKey, PooledConnectionAndInfo> pool;
- private long maxConnLifetimeMillis = -1;
+ private Duration maxConnLifetime = Duration.ofMillis(-1);
/**
* Map of PooledConnections for which close events are ignored. Connections are muted when they are being validated.
@@ -66,7 +68,7 @@ class KeyedCPDSConnectionFactory implements KeyedPooledObjectFactory<UserPassKey
private final Map<PooledConnection, PooledConnectionAndInfo> pcMap = new ConcurrentHashMap<>();
/**
- * Create a new {@code KeyedPoolableConnectionFactory}.
+ * Creates a new {@code KeyedPoolableConnectionFactory}.
*
* @param cpds
* the ConnectionPoolDataSource from which to obtain PooledConnections
@@ -75,151 +77,58 @@ class KeyedCPDSConnectionFactory implements KeyedPooledObjectFactory<UserPassKey
* row. May be {@code null} in which case3 {@link Connection#isValid(int)} will be used to validate
* connections.
* @param validationQueryTimeoutSeconds
- * The time, in seconds, to allow for the validation query to complete
+ * The Duration to allow for the validation query to complete
* @param rollbackAfterValidation
* whether a rollback should be issued after {@link #validateObject validating} {@link Connection}s.
+ * @since 2.10.0
*/
public KeyedCPDSConnectionFactory(final ConnectionPoolDataSource cpds, final String validationQuery,
- final int validationQueryTimeoutSeconds, final boolean rollbackAfterValidation) {
+ final Duration validationQueryTimeoutSeconds, final boolean rollbackAfterValidation) {
this.cpds = cpds;
this.validationQuery = validationQuery;
- this.validationQueryTimeoutSeconds = validationQueryTimeoutSeconds;
+ this.validationQueryTimeoutDuration = validationQueryTimeoutSeconds;
this.rollbackAfterValidation = rollbackAfterValidation;
... 2608 lines suppressed ...
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org