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 2019/05/03 18:41:47 UTC
[tomcat] 01/02: Align fork of Commons DBCP 2 with the 9.0.x copy
excluding JDBC 4.2
This is an automated email from the ASF dual-hosted git repository.
markt pushed a commit to branch 8.5.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit f9efa75376e7f16689b62aae9b93e4d69cb9b625
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Fri May 3 19:27:09 2019 +0100
Align fork of Commons DBCP 2 with the 9.0.x copy excluding JDBC 4.2
---
.../apache/tomcat/dbcp/dbcp2/BasicDataSource.java | 3388 ++++++++++----------
.../tomcat/dbcp/dbcp2/BasicDataSourceFactory.java | 224 +-
.../dbcp/dbcp2/DataSourceConnectionFactory.java | 26 +-
.../tomcat/dbcp/dbcp2/DelegatingConnection.java | 12 +-
.../dbcp/dbcp2/DelegatingDatabaseMetaData.java | 6 +-
.../dbcp/dbcp2/DelegatingPreparedStatement.java | 2 +-
.../tomcat/dbcp/dbcp2/DelegatingResultSet.java | 8 +-
.../tomcat/dbcp/dbcp2/DelegatingStatement.java | 6 +-
.../tomcat/dbcp/dbcp2/DriverConnectionFactory.java | 24 +
.../dbcp/dbcp2/DriverManagerConnectionFactory.java | 62 +-
.../org/apache/tomcat/dbcp/dbcp2/Jdbc41Bridge.java | 482 +++
.../tomcat/dbcp/dbcp2/LocalStrings.properties | 6 +-
.../tomcat/dbcp/dbcp2/ObjectNameWrapper.java | 9 +
.../tomcat/dbcp/dbcp2/PoolableConnection.java | 16 +
.../dbcp/dbcp2/PoolableConnectionFactory.java | 680 ++--
.../tomcat/dbcp/dbcp2/PoolingConnection.java | 2 +-
.../tomcat/dbcp/dbcp2/PoolingDataSource.java | 2 +-
java/org/apache/tomcat/dbcp/dbcp2/Utils.java | 68 +-
.../dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java | 45 +
.../dbcp2/cpdsadapter/PooledConnectionImpl.java | 3 +-
.../dbcp2/datasources/CPDSConnectionFactory.java | 26 +
.../dbcp2/datasources/InstanceKeyDataSource.java | 75 +
.../dbcp2/datasources/SharedPoolDataSource.java | 7 +
.../tomcat/dbcp/dbcp2/datasources/UserPassKey.java | 7 +-
java/org/apache/tomcat/dbcp/dbcp2/overview.html | 26 -
webapps/docs/changelog.xml | 5 +
26 files changed, 3055 insertions(+), 2162 deletions(-)
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSource.java b/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSource.java
index 7f07797..ba3e38a 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSource.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSource.java
@@ -63,8 +63,21 @@ import org.apache.tomcat.dbcp.pool2.impl.GenericObjectPoolConfig;
*/
public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBeanRegistration, AutoCloseable {
+ /**
+ * @since 2.0
+ */
+ private class PaGetConnection implements PrivilegedExceptionAction<Connection> {
+
+ @Override
+ public Connection run() throws SQLException {
+ return createDataSource().getConnection();
+ }
+ }
+
private static final Log log = LogFactory.getLog(BasicDataSource.class);
+ // ------------------------------------------------------------- Properties
+
static {
// Attempt to prevent deadlocks - see DBCP - 272
DriverManager.getDrivers();
@@ -95,7 +108,22 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
}
- // ------------------------------------------------------------- Properties
+ protected static void validateConnectionFactory(final PoolableConnectionFactory connectionFactory)
+ throws Exception {
+ PoolableConnection conn = null;
+ PooledObject<PoolableConnection> p = null;
+ try {
+ p = connectionFactory.makeObject();
+ conn = p.getObject();
+ connectionFactory.activateObject(p);
+ connectionFactory.validateConnection(conn);
+ connectionFactory.passivateObject(p);
+ } finally {
+ if (p != null) {
+ connectionFactory.destroyObject(p);
+ }
+ }
+ }
/**
* The default auto-commit state of connections created by this pool.
@@ -103,1756 +131,1503 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
private volatile Boolean defaultAutoCommit;
/**
- * Returns the default auto-commit property.
- *
- * @return true if default auto-commit is enabled
+ * The default read-only state of connections created by this pool.
*/
- @Override
- public Boolean getDefaultAutoCommit() {
- return defaultAutoCommit;
- }
+ private transient Boolean defaultReadOnly;
/**
- * <p>
- * Sets default auto-commit state of connections returned by this datasource.
- * </p>
- * <p>
- * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
- * time one of the following methods is invoked: <code>getConnection, setLogwriter,
- * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
- * </p>
- *
- * @param defaultAutoCommit
- * default auto-commit value
+ * The default TransactionIsolation state of connections created by this pool.
*/
- public void setDefaultAutoCommit(final Boolean defaultAutoCommit) {
- this.defaultAutoCommit = defaultAutoCommit;
- }
+ private volatile int defaultTransactionIsolation = PoolableConnectionFactory.UNKNOWN_TRANSACTION_ISOLATION;
+
+ private Integer defaultQueryTimeoutSeconds;
/**
- * The default read-only state of connections created by this pool.
+ * The default "catalog" of connections created by this pool.
*/
- private transient Boolean defaultReadOnly;
+ private volatile String defaultCatalog;
/**
- * Returns the default readOnly property.
- *
- * @return true if connections are readOnly by default
+ * The default "schema" of connections created by this pool.
*/
- @Override
- public Boolean getDefaultReadOnly() {
- return defaultReadOnly;
- }
+ private volatile String defaultSchema;
/**
- * <p>
- * Sets defaultReadonly property.
- * </p>
- * <p>
- * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
- * time one of the following methods is invoked: <code>getConnection, setLogwriter,
- * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
- * </p>
- *
- * @param defaultReadOnly
- * default read-only value
+ * The property that controls if the pooled connections cache some state rather than query the database for current
+ * state to improve performance.
*/
- public void setDefaultReadOnly(final Boolean defaultReadOnly) {
- this.defaultReadOnly = defaultReadOnly;
- }
+ private boolean cacheState = true;
/**
- * The default TransactionIsolation state of connections created by this pool.
+ * The instance of the JDBC Driver to use.
*/
- private volatile int defaultTransactionIsolation = PoolableConnectionFactory.UNKNOWN_TRANSACTIONISOLATION;
+ private Driver driver;
/**
- * Returns the default transaction isolation state of returned connections.
- *
- * @return the default value for transaction isolation state
- * @see Connection#getTransactionIsolation
+ * The fully qualified Java class name of the JDBC driver to be used.
*/
- @Override
- public int getDefaultTransactionIsolation() {
- return this.defaultTransactionIsolation;
- }
+ private String driverClassName;
/**
- * <p>
- * Sets the default transaction isolation state for returned connections.
- * </p>
- * <p>
- * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
- * time one of the following methods is invoked: <code>getConnection, setLogwriter,
- * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
- * </p>
- *
- * @param defaultTransactionIsolation
- * the default transaction isolation state
- * @see Connection#getTransactionIsolation
+ * The class loader instance to use to load the JDBC driver. If not specified, {@link Class#forName(String)} is used
+ * to load the JDBC driver. If specified, {@link Class#forName(String, boolean, ClassLoader)} is used.
*/
- public void setDefaultTransactionIsolation(final int defaultTransactionIsolation) {
- this.defaultTransactionIsolation = defaultTransactionIsolation;
- }
+ private ClassLoader driverClassLoader;
- private Integer defaultQueryTimeoutSeconds;
+ /**
+ * True means that borrowObject returns the most recently used ("last in") connection in the pool (if there are idle
+ * connections available). False means that the pool behaves as a FIFO queue - connections are taken from the idle
+ * instance pool in the order that they are returned to the pool.
+ */
+ private boolean lifo = BaseObjectPoolConfig.DEFAULT_LIFO;
/**
- * Gets the default query timeout that will be used for {@link java.sql.Statement Statement}s created from this
- * connection. <code>null</code> means that the driver default will be used.
- *
- * @return The default query timeout in seconds.
+ * The maximum number of active connections that can be allocated from this pool at the same time, or negative for
+ * no limit.
*/
- public Integer getDefaultQueryTimeout() {
- return defaultQueryTimeoutSeconds;
- }
+ private int maxTotal = GenericObjectPoolConfig.DEFAULT_MAX_TOTAL;
/**
- * 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.
+ * The maximum number of connections that can remain idle in the pool, without extra ones being destroyed, or
+ * negative for no limit. If maxIdle is set too low on heavily loaded systems it is possible you will see
+ * connections being closed and almost immediately new connections being opened. This is a result of the active
+ * threads momentarily closing connections faster than they are opening them, causing the number of idle connections
+ * to rise above maxIdle. The best value for maxIdle for heavily loaded system will vary but the default is a good
+ * starting point.
*/
- public void setDefaultQueryTimeout(final Integer defaultQueryTimeoutSeconds) {
- this.defaultQueryTimeoutSeconds = defaultQueryTimeoutSeconds;
- }
+ private int maxIdle = GenericObjectPoolConfig.DEFAULT_MAX_IDLE;
/**
- * The default "catalog" of connections created by this pool.
+ * The minimum number of active connections that can remain idle in the pool, without extra ones being created when
+ * the evictor runs, or 0 to create none. The pool attempts to ensure that minIdle connections are available when
+ * the idle object evictor runs. The value of this property has no effect unless
+ * {@link #timeBetweenEvictionRunsMillis} has a positive value.
*/
- private volatile String defaultCatalog;
+ private int minIdle = GenericObjectPoolConfig.DEFAULT_MIN_IDLE;
/**
- * The default "schema" of connections created by this pool.
+ * The initial number of connections that are created when the pool is started.
*/
- private volatile String defaultSchema;
+ private int initialSize = 0;
/**
- * Returns the default catalog.
- *
- * @return the default catalog
+ * The maximum number of milliseconds that the pool will wait (when there are no available connections) for a
+ * connection to be returned before throwing an exception, or <= 0 to wait indefinitely.
*/
- @Override
- public String getDefaultCatalog() {
- return this.defaultCatalog;
- }
+ private long maxWaitMillis = BaseObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS;
/**
- * Returns the default schema.
- *
- * @return the default schema.
- * @since 2.5.0
+ * Prepared statement pooling for this pool. When this property is set to <code>true</code> both PreparedStatements
+ * and CallableStatements are pooled.
*/
- @Override
- public String getDefaultSchema() {
- return this.defaultSchema;
- }
+ private boolean poolPreparedStatements = false;
/**
* <p>
- * Sets the default catalog.
+ * The maximum number of open statements that can be allocated from the statement pool at the same time, or negative
+ * for no limit. Since a connection usually only uses one or two statements at a time, this is mostly used to help
+ * detect resource leaks.
* </p>
* <p>
- * Note: 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>
+ * Note: As of version 1.3, CallableStatements (those produced by {@link Connection#prepareCall}) are pooled along
+ * with PreparedStatements (produced by {@link Connection#prepareStatement}) and
+ * <code>maxOpenPreparedStatements</code> limits the total number of prepared or callable statements that may be in
+ * use at a given time.
* </p>
- *
- * @param defaultCatalog
- * the default catalog
*/
- public void setDefaultCatalog(final String defaultCatalog) {
- if (defaultCatalog != null && defaultCatalog.trim().length() > 0) {
- this.defaultCatalog = defaultCatalog;
- } else {
- this.defaultCatalog = null;
- }
- }
+ private int maxOpenPreparedStatements = GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL;
/**
- * <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,
- * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
- * </p>
- *
- * @param defaultSchema
- * the default catalog
- * @since 2.5.0
+ * 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.
*/
- public void setDefaultSchema(final String defaultSchema) {
- if (defaultSchema != null && defaultSchema.trim().length() > 0) {
- this.defaultSchema = defaultSchema;
- } else {
- this.defaultSchema = null;
- }
- }
+ private boolean testOnCreate = false;
/**
- * The property that controls if the pooled connections cache some state rather than query the database for current
- * state to improve performance.
+ * The indication of whether objects will be validated before being borrowed from the pool. If the object fails to
+ * validate, it will be dropped from the pool, and we will attempt to borrow another.
*/
- private boolean cacheState = true;
+ private boolean testOnBorrow = true;
/**
- * Returns the state caching flag.
- *
- * @return the state caching flag
+ * The indication of whether objects will be validated before being returned to the pool.
*/
- @Override
- public boolean getCacheState() {
- return cacheState;
- }
+ private boolean testOnReturn = false;
/**
- * Sets the state caching flag.
- *
- * @param cacheState
- * The new value for the state caching flag
+ * 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.
*/
- public void setCacheState(final boolean cacheState) {
- this.cacheState = cacheState;
- }
+ private long timeBetweenEvictionRunsMillis = BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
/**
- * The instance of the JDBC Driver to use.
+ * The number of objects to examine during each run of the idle object evictor thread (if any).
*/
- private Driver driver;
+ private int numTestsPerEvictionRun = BaseObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
/**
- * Returns the JDBC Driver that has been configured for use by this pool.
- * <p>
- * Note: This getter only returns the last value set by a call to {@link #setDriver(Driver)}. It does not return any
- * driver instance that may have been created from the value set via {@link #setDriverClassName(String)}.
- * </p>
- *
- * @return the JDBC Driver that has been configured for use by this pool
+ * 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).
*/
- public synchronized Driver getDriver() {
- return driver;
- }
+ private long minEvictableIdleTimeMillis = BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
/**
- * Sets the JDBC Driver instance to use for this pool.
- * <p>
- * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
- * time one of the following methods is invoked: <code>getConnection, setLogwriter,
- * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
- * </p>
- *
- * @param driver
- * The JDBC Driver instance to use for this pool.
+ * 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()}.
*/
- public synchronized void setDriver(final Driver driver) {
- this.driver = driver;
- }
+ private long softMinEvictableIdleTimeMillis = BaseObjectPoolConfig.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
+
+ private String evictionPolicyClassName = BaseObjectPoolConfig.DEFAULT_EVICTION_POLICY_CLASS_NAME;
/**
- * The fully qualified Java class name of the JDBC driver to be used.
+ * 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 String driverClassName;
+ private boolean testWhileIdle = false;
/**
- * Returns the JDBC driver class name.
- * <p>
- * Note: This getter only returns the last value set by a call to {@link #setDriverClassName(String)}. It does not
- * return the class name of any driver that may have been set via {@link #setDriver(Driver)}.
- * </p>
- *
- * @return the JDBC driver class name
+ * The connection password to be passed to our JDBC driver to establish a connection.
*/
- @Override
- public synchronized String getDriverClassName() {
- return this.driverClassName;
- }
+ private volatile String password;
/**
- * <p>
- * Sets the JDBC driver class name.
- * </p>
- * <p>
- * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
- * time one of the following methods is invoked: <code>getConnection, setLogwriter,
- * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
- * </p>
- *
- * @param driverClassName
- * the class name of the JDBC driver
+ * The connection URL to be passed to our JDBC driver to establish a connection.
*/
- public synchronized void setDriverClassName(final String driverClassName) {
- if (driverClassName != null && driverClassName.trim().length() > 0) {
- this.driverClassName = driverClassName;
- } else {
- this.driverClassName = null;
- }
- }
+ private String url;
/**
- * The class loader instance to use to load the JDBC driver. If not specified, {@link Class#forName(String)} is used
- * to load the JDBC driver. If specified, {@link Class#forName(String, boolean, ClassLoader)} is used.
+ * The connection user name to be passed to our JDBC driver to establish a connection.
*/
- private ClassLoader driverClassLoader;
+ private String userName;
/**
- * Returns the class loader specified for loading the JDBC driver. Returns <code>null</code> if no class loader has
- * been explicitly specified.
- * <p>
- * Note: This getter only returns the last value set by a call to {@link #setDriverClassLoader(ClassLoader)}. It
- * does not return the class loader of any driver that may have been set via {@link #setDriver(Driver)}.
- * </p>
- *
- * @return The class loader specified for loading the JDBC driver.
+ * 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.
*/
- public synchronized ClassLoader getDriverClassLoader() {
- return this.driverClassLoader;
- }
+ private volatile String validationQuery;
/**
+ * Timeout in seconds before connection validation queries fail.
+ */
+ private volatile int validationQueryTimeoutSeconds = -1;
+
+ /**
+ * These SQL statements run once after a Connection is created.
* <p>
- * Sets the class loader to be used to load the JDBC driver.
- * </p>
- * <p>
- * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
- * time one of the following methods is invoked: <code>getConnection, setLogwriter,
- * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+ * This property can be used for example to run ALTER SESSION SET NLS_SORT=XCYECH in an Oracle Database only once
+ * after connection creation.
* </p>
- *
- * @param driverClassLoader
- * the class loader with which to load the JDBC driver
*/
- public synchronized void setDriverClassLoader(final ClassLoader driverClassLoader) {
- this.driverClassLoader = driverClassLoader;
- }
+ private volatile List<String> connectionInitSqls;
/**
- * True means that borrowObject returns the most recently used ("last in") connection in the pool (if there are idle
- * connections available). False means that the pool behaves as a FIFO queue - connections are taken from the idle
- * instance pool in the order that they are returned to the pool.
+ * Controls access to the underlying connection.
*/
- private boolean lifo = BaseObjectPoolConfig.DEFAULT_LIFO;
+ private boolean accessToUnderlyingConnectionAllowed = false;
+
+ private long maxConnLifetimeMillis = -1;
+
+ private boolean logExpiredConnections = true;
+
+ private String jmxName;
+
+ private boolean autoCommitOnReturn = true;
+
+ private boolean rollbackOnReturn = true;
+
+ private volatile Set<String> disconnectionSqlCodes;
+
+ private boolean fastFailValidation;
/**
- * Returns the LIFO property.
- *
- * @return true if connection pool behaves as a LIFO queue.
+ * The object pool that internally manages our connections.
*/
- @Override
- public synchronized boolean getLifo() {
- return this.lifo;
- }
+ private volatile GenericObjectPool<PoolableConnection> connectionPool;
/**
- * Sets the LIFO property. True means the pool behaves as a LIFO queue; false means FIFO.
- *
- * @param lifo
- * the new value for the LIFO property
+ * The connection properties that will be sent to our JDBC driver when establishing new connections.
+ * <strong>NOTE</strong> - The "user" and "password" properties will be passed explicitly, so they do not need to be
+ * included here.
*/
- public synchronized void setLifo(final boolean lifo) {
- this.lifo = lifo;
- if (connectionPool != null) {
- connectionPool.setLifo(lifo);
- }
- }
+ private Properties connectionProperties = new Properties();
/**
- * The maximum number of active connections that can be allocated from this pool at the same time, or negative for
- * no limit.
+ * The data source we will use to manage connections. This object should be acquired <strong>ONLY</strong> by calls
+ * to the <code>createDataSource()</code> method.
*/
- private int maxTotal = GenericObjectPoolConfig.DEFAULT_MAX_TOTAL;
+ private volatile DataSource dataSource;
/**
- * <p>
- * Returns the maximum number of active connections that can be allocated at the same time.
- * </p>
- * <p>
- * A negative number means that there is no limit.
- * </p>
- *
- * @return the maximum number of active connections
+ * The PrintWriter to which log messages should be directed.
*/
- @Override
- public synchronized int getMaxTotal() {
- return this.maxTotal;
- }
+ private volatile PrintWriter logWriter = new PrintWriter(
+ new OutputStreamWriter(System.out, StandardCharsets.UTF_8));
+
+ private AbandonedConfig abandonedConfig;
+
+ private boolean closed;
/**
- * Sets the maximum total number of idle and borrows connections that can be active at the same time. Use a negative
- * value for no limit.
- *
- * @param maxTotal
- * the new value for maxTotal
- * @see #getMaxTotal()
+ * Actual name under which this component has been registered.
*/
- public synchronized void setMaxTotal(final int maxTotal) {
- this.maxTotal = maxTotal;
- if (connectionPool != null) {
- connectionPool.setMaxTotal(maxTotal);
- }
- }
+ private ObjectNameWrapper registeredJmxObjectName;
/**
- * The maximum number of connections that can remain idle in the pool, without extra ones being destroyed, or
- * negative for no limit. If maxIdle is set too low on heavily loaded systems it is possible you will see
- * connections being closed and almost immediately new connections being opened. This is a result of the active
- * threads momentarily closing connections faster than they are opening them, causing the number of idle connections
- * to rise above maxIdle. The best value for maxIdle for heavily loaded system will vary but the default is a good
- * starting point.
+ * Adds a custom connection property to the set that will be passed to our JDBC driver. This <strong>MUST</strong>
+ * be called before the first connection is retrieved (along with all the other configuration property setters).
+ * Calls to this method after the connection pool has been initialized have no effect.
+ *
+ * @param name
+ * Name of the custom connection property
+ * @param value
+ * Value of the custom connection property
*/
- private int maxIdle = GenericObjectPoolConfig.DEFAULT_MAX_IDLE;
+ public void addConnectionProperty(final String name, final String value) {
+ connectionProperties.put(name, value);
+ }
/**
* <p>
- * Returns the maximum number of connections that can remain idle in the pool. Excess idle connections are destroyed
- * on return to the pool.
+ * Closes and releases all idle connections that are currently stored in the connection pool associated with this
+ * data source.
* </p>
* <p>
- * A negative value indicates that there is no limit
+ * Connections that are checked out to clients when this method is invoked are not affected. When client
+ * applications subsequently invoke {@link Connection#close()} to return these connections to the pool, the
+ * underlying JDBC connections are closed.
+ * </p>
+ * <p>
+ * Attempts to acquire connections using {@link #getConnection()} after this method has been invoked result in
+ * SQLExceptions.
+ * </p>
+ * <p>
+ * This method is idempotent - i.e., closing an already closed BasicDataSource has no effect and does not generate
+ * exceptions.
* </p>
*
- * @return the maximum number of idle connections
+ * @throws SQLException
+ * if an error occurs closing idle connections
*/
@Override
- public synchronized int getMaxIdle() {
- return this.maxIdle;
+ public synchronized void close() throws SQLException {
+ if (registeredJmxObjectName != null) {
+ registeredJmxObjectName.unregisterMBean();
+ registeredJmxObjectName = null;
+ }
+ closed = true;
+ final GenericObjectPool<?> oldPool = connectionPool;
+ connectionPool = null;
+ dataSource = null;
+ try {
+ if (oldPool != null) {
+ oldPool.close();
+ }
+ } catch (final RuntimeException e) {
+ throw e;
+ } catch (final Exception e) {
+ throw new SQLException(Utils.getMessage("pool.close.fail"), e);
+ }
}
/**
- * Sets the maximum number of connections that can remain idle in the pool. Excess idle connections are destroyed on
- * return to the pool.
- *
- * @see #getMaxIdle()
- * @param maxIdle
- * the new value for maxIdle
+ * Closes the connection pool, silently swallowing any exception that occurs.
*/
- public synchronized void setMaxIdle(final int maxIdle) {
- this.maxIdle = maxIdle;
- if (connectionPool != null) {
- connectionPool.setMaxIdle(maxIdle);
- }
- }
-
- /**
- * The minimum number of active connections that can remain idle in the pool, without extra ones being created when
- * the evictor runs, or 0 to create none. The pool attempts to ensure that minIdle connections are available when
- * the idle object evictor runs. The value of this property has no effect unless
- * {@link #timeBetweenEvictionRunsMillis} has a positive value.
- */
- private int minIdle = GenericObjectPoolConfig.DEFAULT_MIN_IDLE;
-
- /**
- * Returns the minimum number of idle connections in the pool. The pool attempts to ensure that minIdle connections
- * are available when the idle object evictor runs. The value of this property has no effect unless
- * {@link #timeBetweenEvictionRunsMillis} has a positive value.
- *
- * @return the minimum number of idle connections
- * @see GenericObjectPool#getMinIdle()
- */
- @Override
- public synchronized int getMinIdle() {
- return this.minIdle;
- }
-
- /**
- * Sets the minimum number of idle connections in the pool. The pool attempts to ensure that minIdle connections are
- * available when the idle object evictor runs. The value of this property has no effect unless
- * {@link #timeBetweenEvictionRunsMillis} has a positive value.
- *
- * @param minIdle
- * the new value for minIdle
- * @see GenericObjectPool#setMinIdle(int)
- */
- public synchronized void setMinIdle(final int minIdle) {
- this.minIdle = minIdle;
- if (connectionPool != null) {
- connectionPool.setMinIdle(minIdle);
+ private void closeConnectionPool() {
+ final GenericObjectPool<?> oldPool = connectionPool;
+ connectionPool = null;
+ try {
+ if (oldPool != null) {
+ oldPool.close();
+ }
+ } catch (final Exception e) {
+ /* Ignore */
}
}
/**
- * The initial number of connections that are created when the pool is started.
- */
- private int initialSize = 0;
-
- /**
- * Returns the initial size of the connection pool.
+ * Creates a JDBC connection factory for this datasource. The JDBC driver is loaded using the following algorithm:
+ * <ol>
+ * <li>If a Driver instance has been specified via {@link #setDriver(Driver)} use it</li>
+ * <li>If no Driver instance was specified and {@link #driverClassName} is specified that class is loaded using the
+ * {@link ClassLoader} of this class or, if {@link #driverClassLoader} is set, {@link #driverClassName} is loaded
+ * with the specified {@link ClassLoader}.</li>
+ * <li>If {@link #driverClassName} is specified and the previous attempt fails, the class is loaded using the
+ * context class loader of the current thread.</li>
+ * <li>If a driver still isn't loaded one is loaded via the {@link DriverManager} using the specified {@link #url}.
+ * </ol>
+ * This method exists so subclasses can replace the implementation class.
*
- * @return the number of connections created when the pool is initialized
- */
- @Override
- public synchronized int getInitialSize() {
- return this.initialSize;
- }
-
- /**
- * <p>
- * Sets the initial size of the connection pool.
- * </p>
- * <p>
- * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
- * time one of the following methods is invoked: <code>getConnection, setLogwriter,
- * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
- * </p>
+ * @return A new connection factory.
*
- * @param initialSize
- * the number of connections created when the pool is initialized
+ * @throws SQLException
+ * If the connection factort cannot be created
*/
- public synchronized void setInitialSize(final int initialSize) {
- this.initialSize = initialSize;
- }
+ protected ConnectionFactory createConnectionFactory() throws SQLException {
+ // Load the JDBC driver class
+ Driver driverToUse = this.driver;
- /**
- * The maximum number of milliseconds that the pool will wait (when there are no available connections) for a
- * connection to be returned before throwing an exception, or <= 0 to wait indefinitely.
- */
- private long maxWaitMillis = BaseObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS;
+ if (driverToUse == null) {
+ Class<?> driverFromCCL = null;
+ if (driverClassName != null) {
+ try {
+ try {
+ if (driverClassLoader == null) {
+ driverFromCCL = Class.forName(driverClassName);
+ } else {
+ driverFromCCL = Class.forName(driverClassName, true, driverClassLoader);
+ }
+ } catch (final ClassNotFoundException cnfe) {
+ driverFromCCL = Thread.currentThread().getContextClassLoader().loadClass(driverClassName);
+ }
+ } catch (final Exception t) {
+ final String message = "Cannot load JDBC driver class '" + driverClassName + "'";
+ logWriter.println(message);
+ t.printStackTrace(logWriter);
+ throw new SQLException(message, t);
+ }
+ }
- /**
- * Returns the maximum number of milliseconds that the pool will wait for a connection to be returned before
- * throwing an exception. A value less than or equal to zero means the pool is set to wait indefinitely.
- *
- * @return the maxWaitMillis property value
- */
- @Override
- public synchronized long getMaxWaitMillis() {
- return this.maxWaitMillis;
- }
+ try {
+ if (driverFromCCL == null) {
+ driverToUse = DriverManager.getDriver(url);
+ } else {
+ // Usage of DriverManager is not possible, as it does not
+ // respect the ContextClassLoader
+ // N.B. This cast may cause ClassCastException which is handled below
+ driverToUse = (Driver) driverFromCCL.getConstructor().newInstance();
+ if (!driverToUse.acceptsURL(url)) {
+ throw new SQLException("No suitable driver", "08001");
+ }
+ }
+ } catch (final Exception t) {
+ final String message = "Cannot create JDBC driver of class '"
+ + (driverClassName != null ? driverClassName : "") + "' for connect URL '" + url + "'";
+ logWriter.println(message);
+ t.printStackTrace(logWriter);
+ throw new SQLException(message, t);
+ }
+ }
- /**
- * Sets the MaxWaitMillis property. Use -1 to make the pool wait indefinitely.
- *
- * @param maxWaitMillis
- * the new value for MaxWaitMillis
- * @see #getMaxWaitMillis()
- */
- public synchronized void setMaxWaitMillis(final long maxWaitMillis) {
- this.maxWaitMillis = maxWaitMillis;
- if (connectionPool != null) {
- connectionPool.setMaxWaitMillis(maxWaitMillis);
+ // Set up the driver connection factory we will use
+ final String user = userName;
+ if (user != null) {
+ connectionProperties.put("user", user);
+ } else {
+ log("DBCP DataSource configured without a 'username'");
}
- }
- /**
- * 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;
+ final String pwd = password;
+ if (pwd != null) {
+ connectionProperties.put("password", pwd);
+ } else {
+ log("DBCP DataSource configured without a 'password'");
+ }
- /**
- * Returns true if we are pooling statements.
- *
- * @return true if prepared and callable statements are pooled
- */
- @Override
- public synchronized boolean isPoolPreparedStatements() {
- return this.poolPreparedStatements;
+ final ConnectionFactory driverConnectionFactory = new DriverConnectionFactory(driverToUse, url,
+ connectionProperties);
+ return driverConnectionFactory;
}
/**
+ * Creates a connection pool for this datasource. This method only exists so subclasses can replace the
+ * implementation class.
* <p>
- * Sets whether to pool statements or not.
- * </p>
- * <p>
- * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
- * time one of the following methods is invoked: <code>getConnection, setLogwriter,
- * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+ * This implementation configures all pool properties other than timeBetweenEvictionRunsMillis. Setting that
+ * property is deferred to {@link #startPoolMaintenance()}, since setting timeBetweenEvictionRunsMillis to a
+ * positive value causes {@link GenericObjectPool}'s eviction timer to be started.
* </p>
*
- * @param poolingStatements
- * pooling on or off
+ * @param factory
+ * The factory to use to create new connections for this pool.
*/
- public synchronized void setPoolPreparedStatements(final boolean poolingStatements) {
- this.poolPreparedStatements = poolingStatements;
+ protected void createConnectionPool(final PoolableConnectionFactory factory) {
+ // Create an object pool to contain our active connections
+ final GenericObjectPoolConfig<PoolableConnection> config = new GenericObjectPoolConfig<>();
+ updateJmxName(config);
+ // Disable JMX on the underlying pool if the DS is not registered:
+ config.setJmxEnabled(registeredJmxObjectName != null);
+ final GenericObjectPool<PoolableConnection> gop = createObjectPool(factory, config, abandonedConfig);
+ gop.setMaxTotal(maxTotal);
+ gop.setMaxIdle(maxIdle);
+ gop.setMinIdle(minIdle);
+ gop.setMaxWaitMillis(maxWaitMillis);
+ gop.setTestOnCreate(testOnCreate);
+ gop.setTestOnBorrow(testOnBorrow);
+ gop.setTestOnReturn(testOnReturn);
+ gop.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
+ gop.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
+ gop.setSoftMinEvictableIdleTimeMillis(softMinEvictableIdleTimeMillis);
+ gop.setTestWhileIdle(testWhileIdle);
+ gop.setLifo(lifo);
+ gop.setSwallowedExceptionListener(new SwallowedExceptionLogger(log, logExpiredConnections));
+ gop.setEvictionPolicyClassName(evictionPolicyClassName);
+ factory.setPool(gop);
+ connectionPool = gop;
}
/**
* <p>
- * The maximum number of open statements that can be allocated from the statement pool at the same time, or negative
- * for no limit. Since a connection usually only uses one or two statements at a time, this is mostly used to help
- * detect resource leaks.
- * </p>
- * <p>
- * Note: As of version 1.3, CallableStatements (those produced by {@link Connection#prepareCall}) are pooled along
- * with PreparedStatements (produced by {@link Connection#prepareStatement}) and
- * <code>maxOpenPreparedStatements</code> limits the total number of prepared or callable statements that may be in
- * use at a given time.
+ * Creates (if necessary) and return the internal data source we are using to manage our connections.
* </p>
- */
- private int maxOpenPreparedStatements = GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL;
-
- /**
- * Gets the value of the <code>maxOpenPreparedStatements</code> property.
*
- * @return the maximum number of open statements
+ * @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.
*/
- @Override
- public synchronized int getMaxOpenPreparedStatements() {
- return this.maxOpenPreparedStatements;
- }
+ protected DataSource createDataSource() throws SQLException {
+ if (closed) {
+ throw new SQLException("Data source is closed");
+ }
- /**
- * <p>
- * Sets the value of the <code>maxOpenPreparedStatements</code> property.
- * </p>
- * <p>
- * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
- * time one of the following methods is invoked: <code>getConnection, setLogwriter,
- * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
- * </p>
- *
- * @param maxOpenStatements
- * the new maximum number of prepared statements
- */
- public synchronized void setMaxOpenPreparedStatements(final int maxOpenStatements) {
- this.maxOpenPreparedStatements = maxOpenStatements;
- }
+ // Return the pool if we have already created it
+ // This is double-checked locking. This is safe since dataSource is
+ // volatile and the code is targeted at Java 5 onwards.
+ if (dataSource != null) {
+ return dataSource;
+ }
+ synchronized (this) {
+ if (dataSource != null) {
+ return dataSource;
+ }
- /**
- * 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;
+ jmxRegister();
- /**
- * Returns the {@link #testOnCreate} property.
- *
- * @return true if objects are validated immediately after they are created by the pool
- * @see #testOnCreate
- */
- @Override
- public synchronized boolean getTestOnCreate() {
- return this.testOnCreate;
- }
+ // create factory which returns raw physical connections
+ final ConnectionFactory driverConnectionFactory = createConnectionFactory();
- /**
- * Sets the {@link #testOnCreate} property. This property determines whether or not the pool will validate objects
- * immediately after they are created by the pool
- *
- * @param testOnCreate
- * new value for testOnCreate property
- */
- public synchronized void setTestOnCreate(final boolean testOnCreate) {
- this.testOnCreate = testOnCreate;
- if (connectionPool != null) {
- connectionPool.setTestOnCreate(testOnCreate);
+ // Set up the poolable connection factory
+ boolean success = false;
+ PoolableConnectionFactory poolableConnectionFactory;
+ try {
+ poolableConnectionFactory = createPoolableConnectionFactory(driverConnectionFactory);
+ poolableConnectionFactory.setPoolStatements(poolPreparedStatements);
+ poolableConnectionFactory.setMaxOpenPreparedStatements(maxOpenPreparedStatements);
+ success = true;
+ } catch (final SQLException se) {
+ throw se;
+ } catch (final RuntimeException rte) {
+ throw rte;
+ } catch (final Exception ex) {
+ throw new SQLException("Error creating connection factory", ex);
+ }
+
+ if (success) {
+ // create a pool for our connections
+ createConnectionPool(poolableConnectionFactory);
+ }
+
+ // Create the pooling data source to manage connections
+ DataSource newDataSource;
+ success = false;
+ try {
+ newDataSource = createDataSourceInstance();
+ newDataSource.setLogWriter(logWriter);
+ success = true;
+ } catch (final SQLException se) {
+ throw se;
+ } catch (final RuntimeException rte) {
+ throw rte;
+ } catch (final Exception ex) {
+ throw new SQLException("Error creating datasource", ex);
+ } finally {
+ if (!success) {
+ closeConnectionPool();
+ }
+ }
+
+ // If initialSize > 0, preload the pool
+ try {
+ for (int i = 0; i < initialSize; i++) {
+ connectionPool.addObject();
+ }
+ } catch (final Exception e) {
+ closeConnectionPool();
+ throw new SQLException("Error preloading the connection pool", e);
+ }
+
+ // If timeBetweenEvictionRunsMillis > 0, start the pool's evictor task
+ startPoolMaintenance();
+
+ dataSource = newDataSource;
+ return dataSource;
}
}
/**
- * The indication of whether objects will be validated before being borrowed from the pool. If the object fails to
- * validate, it will be dropped from the pool, and we will attempt to borrow another.
- */
- private boolean testOnBorrow = true;
-
- /**
- * Returns the {@link #testOnBorrow} property.
+ * Creates the actual data source instance. This method only exists so that subclasses can replace the
+ * implementation class.
*
- * @return true if objects are validated before being borrowed from the pool
+ * @throws SQLException
+ * if unable to create a datasource instance
*
- * @see #testOnBorrow
+ * @return A new DataSource instance
*/
- @Override
- public synchronized boolean getTestOnBorrow() {
- return this.testOnBorrow;
+ protected DataSource createDataSourceInstance() throws SQLException {
+ final PoolingDataSource<PoolableConnection> pds = new PoolingDataSource<>(connectionPool);
+ pds.setAccessToUnderlyingConnectionAllowed(isAccessToUnderlyingConnectionAllowed());
+ return pds;
}
/**
- * Sets the {@link #testOnBorrow} property. This property determines whether or not the pool will validate objects
- * before they are borrowed from the pool.
+ * Creates an object pool used to provide pooling support for {@link Connection JDBC connections}.
*
- * @param testOnBorrow
- * new value for testOnBorrow property
+ * @param factory
+ * the object factory
+ * @param poolConfig
+ * the object pool configuration
+ * @param abandonedConfig
+ * the abandoned objects configuration
+ * @return a non-null instance
*/
- public synchronized void setTestOnBorrow(final boolean testOnBorrow) {
- this.testOnBorrow = testOnBorrow;
- if (connectionPool != null) {
- connectionPool.setTestOnBorrow(testOnBorrow);
+ protected GenericObjectPool<PoolableConnection> createObjectPool(final PoolableConnectionFactory factory,
+ final GenericObjectPoolConfig<PoolableConnection> poolConfig, final AbandonedConfig abandonedConfig) {
+ GenericObjectPool<PoolableConnection> gop;
+ if (abandonedConfig != null && (abandonedConfig.getRemoveAbandonedOnBorrow()
+ || abandonedConfig.getRemoveAbandonedOnMaintenance())) {
+ gop = new GenericObjectPool<>(factory, poolConfig, abandonedConfig);
+ } else {
+ gop = new GenericObjectPool<>(factory, poolConfig);
}
+ return gop;
}
/**
- * The indication of whether objects will be validated before being returned to the pool.
+ * Creates the PoolableConnectionFactory and attaches it to the connection pool. This method only exists so
+ * subclasses can replace the default implementation.
+ *
+ * @param driverConnectionFactory
+ * JDBC connection factory
+ * @throws SQLException
+ * if an error occurs creating the PoolableConnectionFactory
+ *
+ * @return A new PoolableConnectionFactory configured with the current configuration of this BasicDataSource
*/
- private boolean testOnReturn = false;
+ protected PoolableConnectionFactory createPoolableConnectionFactory(final ConnectionFactory driverConnectionFactory)
+ throws SQLException {
+ PoolableConnectionFactory connectionFactory = null;
+ try {
+ connectionFactory = new PoolableConnectionFactory(driverConnectionFactory,
+ ObjectNameWrapper.unwrap(registeredJmxObjectName));
+ connectionFactory.setValidationQuery(validationQuery);
+ connectionFactory.setValidationQueryTimeout(validationQueryTimeoutSeconds);
+ connectionFactory.setConnectionInitSql(connectionInitSqls);
+ connectionFactory.setDefaultReadOnly(defaultReadOnly);
+ connectionFactory.setDefaultAutoCommit(defaultAutoCommit);
+ connectionFactory.setDefaultTransactionIsolation(defaultTransactionIsolation);
+ connectionFactory.setDefaultCatalog(defaultCatalog);
+ connectionFactory.setDefaultSchema(defaultSchema);
+ connectionFactory.setCacheState(cacheState);
+ connectionFactory.setPoolStatements(poolPreparedStatements);
+ connectionFactory.setMaxOpenPreparedStatements(maxOpenPreparedStatements);
+ connectionFactory.setMaxConnLifetimeMillis(maxConnLifetimeMillis);
+ connectionFactory.setRollbackOnReturn(getRollbackOnReturn());
+ connectionFactory.setAutoCommitOnReturn(getAutoCommitOnReturn());
+ connectionFactory.setDefaultQueryTimeout(getDefaultQueryTimeout());
+ connectionFactory.setFastFailValidation(fastFailValidation);
+ connectionFactory.setDisconnectionSqlCodes(disconnectionSqlCodes);
+ validateConnectionFactory(connectionFactory);
+ } catch (final RuntimeException e) {
+ throw e;
+ } catch (final Exception e) {
+ throw new SQLException("Cannot create PoolableConnectionFactory (" + e.getMessage() + ")", e);
+ }
+ return connectionFactory;
+ }
/**
- * Returns the value of the {@link #testOnReturn} property.
+ * Gets the print writer used by this configuration to log information on abandoned objects.
*
- * @return true if objects are validated before being returned to the pool
- * @see #testOnReturn
+ * @return The print writer used by this configuration to log information on abandoned objects.
*/
- public synchronized boolean getTestOnReturn() {
- return this.testOnReturn;
+ public PrintWriter getAbandonedLogWriter() {
+ if (abandonedConfig != null) {
+ return abandonedConfig.getLogWriter();
+ }
+ return null;
}
/**
- * Sets the <code>testOnReturn</code> property. This property determines whether or not the pool will validate
- * objects before they are returned to the pool.
+ * If the connection pool implements {@link org.apache.tomcat.dbcp.pool2.UsageTracking UsageTracking}, should the
+ * connection pool record a stack trace every time a method is called on a pooled connection and retain the most
+ * recent stack trace to aid debugging of abandoned connections?
*
- * @param testOnReturn
- * new value for testOnReturn property
+ * @return <code>true</code> if usage tracking is enabled
*/
- public synchronized void setTestOnReturn(final boolean testOnReturn) {
- this.testOnReturn = testOnReturn;
- if (connectionPool != null) {
- connectionPool.setTestOnReturn(testOnReturn);
+ @Override
+ public boolean getAbandonedUsageTracking() {
+ if (abandonedConfig != null) {
+ return abandonedConfig.getUseUsageTracking();
}
+ return false;
}
/**
- * 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.
+ * Returns the value of the flag that controls whether or not connections being returned to the pool will be checked
+ * and configured with {@link Connection#setAutoCommit(boolean) Connection.setAutoCommit(true)} if the auto commit
+ * setting is {@code false} when the connection is returned. It is <code>true</code> by default.
+ *
+ * @return Whether or not connections being returned to the pool will be checked and configured with auto-commit.
*/
- private long timeBetweenEvictionRunsMillis = BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
+ public boolean getAutoCommitOnReturn() {
+ return autoCommitOnReturn;
+ }
/**
- * Returns the value of the {@link #timeBetweenEvictionRunsMillis} property.
+ * Returns the state caching flag.
*
- * @return the time (in milliseconds) between evictor runs
- * @see #timeBetweenEvictionRunsMillis
+ * @return the state caching flag
*/
@Override
- public synchronized long getTimeBetweenEvictionRunsMillis() {
- return this.timeBetweenEvictionRunsMillis;
+ public boolean getCacheState() {
+ return cacheState;
}
/**
- * Sets the {@link #timeBetweenEvictionRunsMillis} property.
+ * Creates (if necessary) and return a connection to the database.
*
- * @param timeBetweenEvictionRunsMillis
- * the new time between evictor runs
- * @see #timeBetweenEvictionRunsMillis
+ * @throws SQLException
+ * if a database access error occurs
+ * @return a database connection
*/
- public synchronized void setTimeBetweenEvictionRunsMillis(final long timeBetweenEvictionRunsMillis) {
- this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
- if (connectionPool != null) {
- connectionPool.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
- }
- }
-
- /**
- * The number of objects to examine during each run of the idle object evictor thread (if any).
- */
- private int numTestsPerEvictionRun = BaseObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
+ @Override
+ public Connection getConnection() throws SQLException {
+ if (Utils.IS_SECURITY_ENABLED) {
+ final PrivilegedExceptionAction<Connection> action = new PaGetConnection();
+ try {
+ return AccessController.doPrivileged(action);
+ } catch (final PrivilegedActionException e) {
+ final Throwable cause = e.getCause();
+ if (cause instanceof SQLException) {
+ throw (SQLException) cause;
+ }
+ throw new SQLException(e);
+ }
+ }
+ return createDataSource().getConnection();
+ }
/**
- * Returns the value of the {@link #numTestsPerEvictionRun} property.
+ * <strong>BasicDataSource does NOT support this method.</strong>
*
- * @return the number of objects to examine during idle object evictor runs
- * @see #numTestsPerEvictionRun
+ * @param user
+ * Database user on whose behalf the Connection is being made
+ * @param pass
+ * The database user's password
+ *
+ * @throws UnsupportedOperationException
+ * always thrown.
+ * @throws SQLException
+ * if a database access error occurs
+ * @return nothing - always throws UnsupportedOperationException
*/
@Override
- public synchronized int getNumTestsPerEvictionRun() {
- return this.numTestsPerEvictionRun;
+ public Connection getConnection(final String user, final String pass) throws SQLException {
+ // This method isn't supported by the PoolingDataSource returned by the createDataSource
+ throw new UnsupportedOperationException("Not supported by BasicDataSource");
}
/**
- * Sets the value of the {@link #numTestsPerEvictionRun} property.
+ * Returns the list of SQL statements executed when a physical connection is first created. Returns an empty list if
+ * there are no initialization statements configured.
*
- * @param numTestsPerEvictionRun
- * the new {@link #numTestsPerEvictionRun} value
- * @see #numTestsPerEvictionRun
+ * @return initialization SQL statements
*/
- public synchronized void setNumTestsPerEvictionRun(final int numTestsPerEvictionRun) {
- this.numTestsPerEvictionRun = numTestsPerEvictionRun;
- if (connectionPool != null) {
- connectionPool.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
+ public List<String> getConnectionInitSqls() {
+ final List<String> result = connectionInitSqls;
+ if (result == null) {
+ return Collections.emptyList();
}
+ return result;
}
/**
- * 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).
+ * Provides the same data as {@link #getConnectionInitSqls()} but in an array so it is accessible via JMX.
*/
- private long minEvictableIdleTimeMillis = BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
+ @Override
+ public String[] getConnectionInitSqlsAsArray() {
+ final Collection<String> result = getConnectionInitSqls();
+ return result.toArray(new String[result.size()]);
+ }
+
+ protected GenericObjectPool<PoolableConnection> getConnectionPool() {
+ return connectionPool;
+ }
+
+ // For unit testing
+ Properties getConnectionProperties() {
+ return connectionProperties;
+ }
/**
- * Returns the {@link #minEvictableIdleTimeMillis} property.
+ * Returns the default auto-commit property.
*
- * @return the value of the {@link #minEvictableIdleTimeMillis} property
- * @see #minEvictableIdleTimeMillis
+ * @return true if default auto-commit is enabled
*/
@Override
- public synchronized long getMinEvictableIdleTimeMillis() {
- return this.minEvictableIdleTimeMillis;
+ public Boolean getDefaultAutoCommit() {
+ return defaultAutoCommit;
}
/**
- * Sets the {@link #minEvictableIdleTimeMillis} property.
+ * Returns the default catalog.
*
- * @param minEvictableIdleTimeMillis
- * the minimum amount of time an object may sit idle in the pool
- * @see #minEvictableIdleTimeMillis
+ * @return the default catalog
*/
- public synchronized void setMinEvictableIdleTimeMillis(final long minEvictableIdleTimeMillis) {
- this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
- if (connectionPool != null) {
- connectionPool.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
- }
+ @Override
+ public String getDefaultCatalog() {
+ return this.defaultCatalog;
}
/**
- * 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()}.
+ * Gets the default query timeout that will be used for {@link java.sql.Statement Statement}s created from this
+ * connection. <code>null</code> means that the driver default will be used.
+ *
+ * @return The default query timeout in seconds.
*/
- private long softMinEvictableIdleTimeMillis = BaseObjectPoolConfig.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
+ public Integer getDefaultQueryTimeout() {
+ return defaultQueryTimeoutSeconds;
+ }
/**
- * 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.
+ * Returns the default readOnly property.
*
- * @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
+ * @return true if connections are readOnly by default
*/
- public synchronized void setSoftMinEvictableIdleTimeMillis(final long softMinEvictableIdleTimeMillis) {
- this.softMinEvictableIdleTimeMillis = softMinEvictableIdleTimeMillis;
- if (connectionPool != null) {
- connectionPool.setSoftMinEvictableIdleTimeMillis(softMinEvictableIdleTimeMillis);
- }
+ @Override
+ public Boolean getDefaultReadOnly() {
+ return defaultReadOnly;
}
/**
- * <p>
- * Returns the minimum amount of time a connection may sit idle in the pool before it is eligible for eviction by
- * the idle object evictor, with the extra condition that at least "minIdle" connections remain in the pool.
- * </p>
- *
- * <p>
- * When {@link #getMinEvictableIdleTimeMillis() minEvictableIdleTimeMillis} is set to a positive value,
- * minEvictableIdleTimeMillis is examined first by the idle connection evictor - i.e. when idle connections are
- * visited by the evictor, idle time is first compared against {@code minEvictableIdleTimeMillis} (without
- * considering the number of idle connections in the pool) and then against {@code softMinEvictableIdleTimeMillis},
- * including the {@code minIdle}, constraint.
- * </p>
+ * Returns the default schema.
*
- * @return minimum amount of time a connection may sit idle in the pool before it is eligible for eviction, assuming
- * there are minIdle idle connections in the pool
+ * @return the default schema.
+ * @since 2.5.0
*/
@Override
- public synchronized long getSoftMinEvictableIdleTimeMillis() {
- return softMinEvictableIdleTimeMillis;
+ public String getDefaultSchema() {
+ return this.defaultSchema;
}
- private String evictionPolicyClassName = BaseObjectPoolConfig.DEFAULT_EVICTION_POLICY_CLASS_NAME;
-
/**
- * Gets the EvictionPolicy implementation in use with this connection pool.
+ * Returns the default transaction isolation state of returned connections.
*
- * @return The EvictionPolicy implementation in use with this connection pool.
+ * @return the default value for transaction isolation state
+ * @see Connection#getTransactionIsolation
*/
- public synchronized String getEvictionPolicyClassName() {
- return evictionPolicyClassName;
+ @Override
+ public int getDefaultTransactionIsolation() {
+ return this.defaultTransactionIsolation;
}
/**
- * Sets the EvictionPolicy implementation to use with this connection pool.
+ * Returns the set of SQL_STATE codes considered to signal fatal conditions.
*
- * @param evictionPolicyClassName
- * The fully qualified class name of the EvictionPolicy implementation
+ * @return fatal disconnection state codes
+ * @see #setDisconnectionSqlCodes(Collection)
+ * @since 2.1
*/
- public synchronized void setEvictionPolicyClassName(final String evictionPolicyClassName) {
- if (connectionPool != null) {
- connectionPool.setEvictionPolicyClassName(evictionPolicyClassName);
+ public Set<String> getDisconnectionSqlCodes() {
+ final Set<String> result = disconnectionSqlCodes;
+ if (result == null) {
+ return Collections.emptySet();
}
- this.evictionPolicyClassName = evictionPolicyClassName;
+ return result;
}
/**
- * The indication of whether objects will be validated by the idle object evictor (if any). If an object fails to
- * validate, it will be dropped from the pool.
- */
- private boolean testWhileIdle = false;
-
- /**
- * Returns the value of the {@link #testWhileIdle} property.
+ * Provides the same data as {@link #getDisconnectionSqlCodes} but in an array so it is accessible via JMX.
*
- * @return true if objects examined by the idle object evictor are validated
- * @see #testWhileIdle
+ * @since 2.1
*/
@Override
- public synchronized boolean getTestWhileIdle() {
- return this.testWhileIdle;
+ public String[] getDisconnectionSqlCodesAsArray() {
+ final Collection<String> result = getDisconnectionSqlCodes();
+ return result.toArray(new String[result.size()]);
}
/**
- * Sets the <code>testWhileIdle</code> property. This property determines whether or not the idle object evictor
- * will validate connections.
+ * Returns the JDBC Driver that has been configured for use by this pool.
+ * <p>
+ * Note: This getter only returns the last value set by a call to {@link #setDriver(Driver)}. It does not return any
+ * driver instance that may have been created from the value set via {@link #setDriverClassName(String)}.
+ * </p>
*
- * @param testWhileIdle
- * new value for testWhileIdle property
+ * @return the JDBC Driver that has been configured for use by this pool
*/
- public synchronized void setTestWhileIdle(final boolean testWhileIdle) {
- this.testWhileIdle = testWhileIdle;
- if (connectionPool != null) {
- connectionPool.setTestWhileIdle(testWhileIdle);
- }
+ public synchronized Driver getDriver() {
+ return driver;
}
/**
- * [Read Only] The current number of active connections that have been allocated from this data source.
+ * Returns the class loader specified for loading the JDBC driver. Returns <code>null</code> if no class loader has
+ * been explicitly specified.
+ * <p>
+ * Note: This getter only returns the last value set by a call to {@link #setDriverClassLoader(ClassLoader)}. It
+ * does not return the class loader of any driver that may have been set via {@link #setDriver(Driver)}.
+ * </p>
*
- * @return the current number of active connections
+ * @return The class loader specified for loading the JDBC driver.
*/
- @Override
- public int getNumActive() {
- // Copy reference to avoid NPE if close happens after null check
- final GenericObjectPool<PoolableConnection> pool = connectionPool;
- if (pool != null) {
- return pool.getNumActive();
- }
- return 0;
+ public synchronized ClassLoader getDriverClassLoader() {
+ return this.driverClassLoader;
}
/**
- * [Read Only] The current number of idle connections that are waiting to be allocated from this data source.
+ * Returns the JDBC driver class name.
+ * <p>
+ * Note: This getter only returns the last value set by a call to {@link #setDriverClassName(String)}. It does not
+ * return the class name of any driver that may have been set via {@link #setDriver(Driver)}.
+ * </p>
*
- * @return the current number of idle connections
+ * @return the JDBC driver class name
*/
@Override
- public int getNumIdle() {
- // Copy reference to avoid NPE if close happens after null check
- final GenericObjectPool<PoolableConnection> pool = connectionPool;
- if (pool != null) {
- return pool.getNumIdle();
- }
- return 0;
+ public synchronized String getDriverClassName() {
+ return this.driverClassName;
}
/**
- * The connection password to be passed to our JDBC driver to establish a connection.
+ * Returns the value of the flag that controls whether or not connections being returned to the pool will be checked
+ * and configured with {@link Connection#setAutoCommit(boolean) Connection.setAutoCommit(true)} if the auto commit
+ * setting is {@code false} when the connection is returned. It is <code>true</code> by default.
+ *
+ * @return Whether or not connections being returned to the pool will be checked and configured with auto-commit.
+ * @deprecated Use {@link #getAutoCommitOnReturn()}.
*/
- private volatile String password;
+ @Deprecated
+ public boolean getEnableAutoCommitOnReturn() {
+ return autoCommitOnReturn;
+ }
/**
- * Returns the password passed to the JDBC driver to establish connections.
+ * Gets the EvictionPolicy implementation in use with this connection pool.
*
- * @return the connection password
+ * @return The EvictionPolicy implementation in use with this connection pool.
+ */
+ public synchronized String getEvictionPolicyClassName() {
+ return evictionPolicyClassName;
+ }
+
+ /**
+ * True means that validation will fail immediately for connections that have previously thrown SQLExceptions with
+ * SQL_STATE indicating fatal disconnection errors.
+ *
+ * @return true if connections created by this datasource will fast fail validation.
+ * @see #setDisconnectionSqlCodes(Collection)
+ * @since 2.1
*/
@Override
- public String getPassword() {
- return this.password;
+ public boolean getFastFailValidation() {
+ return fastFailValidation;
}
/**
- * <p>
- * Sets the {@link #password}.
- * </p>
- * <p>
- * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
- * time one of the following methods is invoked: <code>getConnection, setLogwriter,
- * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
- * </p>
+ * Returns the initial size of the connection pool.
*
- * @param password
- * new value for the password
+ * @return the number of connections created when the pool is initialized
*/
- public void setPassword(final String password) {
- this.password = password;
+ @Override
+ public synchronized int getInitialSize() {
+ return this.initialSize;
}
/**
- * The connection URL to be passed to our JDBC driver to establish a connection.
+ * Returns the JMX name that has been requested for this DataSource. If the requested name is not valid, an
+ * alternative may be chosen.
+ *
+ * @return The JMX name that has been requested for this DataSource.
*/
- private String url;
+ public String getJmxName() {
+ return jmxName;
+ }
/**
- * Returns the JDBC connection {@link #url} property.
+ * Returns the LIFO property.
*
- * @return the {@link #url} passed to the JDBC driver to establish connections
+ * @return true if connection pool behaves as a LIFO queue.
*/
@Override
- public synchronized String getUrl() {
- return this.url;
+ public synchronized boolean getLifo() {
+ return this.lifo;
}
/**
* <p>
- * Sets the {@link #url}.
+ * Flag to log stack traces for application code which abandoned a Statement or Connection.
* </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>
+ * Defaults to false.
+ * </p>
+ * <p>
+ * Logging of abandoned Statements and Connections adds overhead for every Connection open or new Statement because
+ * a stack trace has to be generated.
* </p>
- *
- * @param url
- * the new value for the JDBC connection url
*/
- public synchronized void setUrl(final String url) {
- this.url = url;
+ @Override
+ public boolean getLogAbandoned() {
+ if (abandonedConfig != null) {
+ return abandonedConfig.getLogAbandoned();
+ }
+ return false;
}
/**
- * The connection user name to be passed to our JDBC driver to establish a connection.
- */
- private String userName;
-
- /**
- * Returns the JDBC connection {@link #userName} property.
+ * When {@link #getMaxConnLifetimeMillis()} is set to limit connection lifetime, this property determines whether or
+ * not log messages are generated when the pool closes connections due to maximum lifetime exceeded.
*
- * @return the {@link #userName} passed to the JDBC driver to establish connections
+ * @since 2.1
*/
@Override
- public String getUsername() {
- return this.userName;
+ public boolean getLogExpiredConnections() {
+ return logExpiredConnections;
}
/**
+ * <strong>BasicDataSource does NOT support this method.</strong>
+ *
* <p>
- * Sets the {@link #userName}.
+ * Returns the login timeout (in seconds) for connecting to the database.
* </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>
+ * Calls {@link #createDataSource()}, so has the side effect of initializing the connection pool.
* </p>
*
- * @param userName
- * the new value for the JDBC connection user name
+ * @throws SQLException
+ * if a database access error occurs
+ * @throws UnsupportedOperationException
+ * If the DataSource implementation does not support the login timeout feature.
+ * @return login timeout in seconds
*/
- public void setUsername(final String userName) {
- this.userName = userName;
+ @Override
+ public int getLoginTimeout() throws SQLException {
+ // This method isn't supported by the PoolingDataSource returned by the createDataSource
+ throw new UnsupportedOperationException("Not supported by BasicDataSource");
}
/**
- * 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.
+ * <p>
+ * Returns the log writer being used by this data source.
+ * </p>
+ * <p>
+ * Calls {@link #createDataSource()}, so has the side effect of initializing the connection pool.
+ * </p>
+ *
+ * @throws SQLException
+ * if a database access error occurs
+ * @return log writer in use
*/
- private volatile String validationQuery;
+ @Override
+ public PrintWriter getLogWriter() throws SQLException {
+ return createDataSource().getLogWriter();
+ }
/**
- * Returns the validation query used to validate connections before returning them.
- *
- * @return the SQL validation query
- * @see #validationQuery
+ * Returns the maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an
+ * infinite lifetime.
*/
@Override
- public String getValidationQuery() {
- return this.validationQuery;
+ public long getMaxConnLifetimeMillis() {
+ return maxConnLifetimeMillis;
}
/**
* <p>
- * Sets the {@link #validationQuery}.
+ * Returns the maximum number of connections that can remain idle in the pool. Excess idle connections are destroyed
+ * on return to the pool.
* </p>
* <p>
- * 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>
+ * A negative value indicates that there is no limit
* </p>
*
- * @param validationQuery
- * the new value for the validation query
+ * @return the maximum number of idle connections
*/
- public void setValidationQuery(final String validationQuery) {
- if (validationQuery != null && validationQuery.trim().length() > 0) {
- this.validationQuery = validationQuery;
- } else {
- this.validationQuery = null;
- }
+ @Override
+ public synchronized int getMaxIdle() {
+ return this.maxIdle;
}
/**
- * Timeout in seconds before connection validation queries fail.
- */
- private volatile int validationQueryTimeoutSeconds = -1;
-
- /**
- * Returns the validation query timeout.
+ * Gets the value of the <code>maxOpenPreparedStatements</code> property.
*
- * @return the timeout in seconds before connection validation queries fail.
+ * @return the maximum number of open statements
*/
@Override
- public int getValidationQueryTimeout() {
- return validationQueryTimeoutSeconds;
+ public synchronized int getMaxOpenPreparedStatements() {
+ return this.maxOpenPreparedStatements;
}
/**
- * 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>
+ * Returns the maximum number of active connections that can be allocated at the same time.
+ * </p>
+ * <p>
+ * A negative number means that there is no limit.
* </p>
*
- * @param validationQueryTimeoutSeconds
- * new validation query timeout value in seconds
+ * @return the maximum number of active connections
*/
- public void setValidationQueryTimeout(final int validationQueryTimeoutSeconds) {
- this.validationQueryTimeoutSeconds = validationQueryTimeoutSeconds;
+ @Override
+ public synchronized int getMaxTotal() {
+ return this.maxTotal;
}
/**
- * These SQL statements run once after a Connection is created.
- * <p>
- * This property can be used for example to run ALTER SESSION SET NLS_SORT=XCYECH in an Oracle Database only once
- * after connection creation.
- * </p>
+ * Returns the maximum number of milliseconds that the pool will wait for a connection to be returned before
+ * throwing an exception. A value less than or equal to zero means the pool is set to wait indefinitely.
+ *
+ * @return the maxWaitMillis property value
*/
- private volatile List<String> connectionInitSqls;
+ @Override
+ public synchronized long getMaxWaitMillis() {
+ return this.maxWaitMillis;
+ }
/**
- * Returns the list of SQL statements executed when a physical connection is first created. Returns an empty list if
- * there are no initialization statements configured.
+ * Returns the {@link #minEvictableIdleTimeMillis} property.
*
- * @return initialization SQL statements
+ * @return the value of the {@link #minEvictableIdleTimeMillis} property
+ * @see #minEvictableIdleTimeMillis
*/
- public List<String> getConnectionInitSqls() {
- final List<String> result = connectionInitSqls;
- if (result == null) {
- return Collections.emptyList();
- }
- return result;
+ @Override
+ public synchronized long getMinEvictableIdleTimeMillis() {
+ return this.minEvictableIdleTimeMillis;
}
/**
- * Provides the same data as {@link #getConnectionInitSqls()} but in an array so it is accessible via JMX.
+ * Returns the minimum number of idle connections in the pool. The pool attempts to ensure that minIdle connections
+ * are available when the idle object evictor runs. The value of this property has no effect unless
+ * {@link #timeBetweenEvictionRunsMillis} has a positive value.
+ *
+ * @return the minimum number of idle connections
+ * @see GenericObjectPool#getMinIdle()
*/
@Override
- public String[] getConnectionInitSqlsAsArray() {
- final Collection<String> result = getConnectionInitSqls();
- return result.toArray(new String[result.size()]);
+ public synchronized int getMinIdle() {
+ return this.minIdle;
}
/**
- * Sets the list of SQL statements to be executed when a physical connection is first created.
- * <p>
- * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
- * time one of the following methods is invoked: <code>getConnection, setLogwriter,
- * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
- * </p>
+ * [Read Only] The current number of active connections that have been allocated from this data source.
*
- * @param connectionInitSqls
- * Collection of SQL statements to execute on connection creation
+ * @return the current number of active connections
*/
- public void setConnectionInitSqls(final Collection<String> connectionInitSqls) {
- if (connectionInitSqls != null && connectionInitSqls.size() > 0) {
- ArrayList<String> newVal = null;
- for (final String s : connectionInitSqls) {
- if (s != null && s.trim().length() > 0) {
- if (newVal == null) {
- newVal = new ArrayList<>();
- }
- newVal.add(s);
- }
- }
- this.connectionInitSqls = newVal;
- } else {
- this.connectionInitSqls = null;
+ @Override
+ public int getNumActive() {
+ // Copy reference to avoid NPE if close happens after null check
+ final GenericObjectPool<PoolableConnection> pool = connectionPool;
+ if (pool != null) {
+ return pool.getNumActive();
}
+ return 0;
}
/**
- * Controls access to the underlying connection.
- */
- private boolean accessToUnderlyingConnectionAllowed = false;
-
- /**
- * Returns the value of the accessToUnderlyingConnectionAllowed property.
+ * [Read Only] The current number of idle connections that are waiting to be allocated from this data source.
*
- * @return true if access to the underlying connection is allowed, false otherwise.
+ * @return the current number of idle connections
*/
@Override
- public synchronized boolean isAccessToUnderlyingConnectionAllowed() {
- return this.accessToUnderlyingConnectionAllowed;
+ public int getNumIdle() {
+ // Copy reference to avoid NPE if close happens after null check
+ final GenericObjectPool<PoolableConnection> pool = connectionPool;
+ if (pool != null) {
+ return pool.getNumIdle();
+ }
+ return 0;
}
/**
- * <p>
- * Sets the value of the accessToUnderlyingConnectionAllowed property. It controls if the PoolGuard allows access to
- * the underlying connection. (Default: false)
- * </p>
- * <p>
- * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
- * time one of the following methods is invoked: <code>getConnection, setLogwriter,
- * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
- * </p>
+ * Returns the value of the {@link #numTestsPerEvictionRun} property.
*
- * @param allow
- * Access to the underlying connection is granted when true.
+ * @return the number of objects to examine during idle object evictor runs
+ * @see #numTestsPerEvictionRun
*/
- public synchronized void setAccessToUnderlyingConnectionAllowed(final boolean allow) {
- this.accessToUnderlyingConnectionAllowed = allow;
+ @Override
+ public synchronized int getNumTestsPerEvictionRun() {
+ return this.numTestsPerEvictionRun;
}
- private long maxConnLifetimeMillis = -1;
+ @Override
+ public Logger getParentLogger() throws SQLFeatureNotSupportedException {
+ throw new SQLFeatureNotSupportedException();
+ }
/**
- * Returns the maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an
- * infinite lifetime.
+ * Returns the password passed to the JDBC driver to establish connections.
+ *
+ * @return the connection password
*/
@Override
- public long getMaxConnLifetimeMillis() {
- return maxConnLifetimeMillis;
+ public String getPassword() {
+ return this.password;
}
- private boolean logExpiredConnections = true;
+ protected ObjectName getRegisteredJmxName() {
+ return ObjectNameWrapper.unwrap(registeredJmxObjectName);
+ }
/**
- * When {@link #getMaxConnLifetimeMillis()} is set to limit connection lifetime, this property determines whether or
- * not log messages are generated when the pool closes connections due to maximum lifetime exceeded.
+ * <p>
+ * Flag to remove abandoned connections if they exceed the removeAbandonedTimeout when borrowObject is invoked.
+ * </p>
+ * <p>
+ * The default value is false.
+ * </p>
+ * <p>
+ * If set to true a connection is considered abandoned and eligible for removal if it has not been used for more
+ * than {@link #getRemoveAbandonedTimeout() removeAbandonedTimeout} seconds.
+ * </p>
+ * <p>
+ * Abandoned connections are identified and removed when {@link #getConnection()} is invoked and all of the
+ * following conditions hold:
+ * </p>
+ * <ul>
+ * <li>{@link #getRemoveAbandonedOnBorrow()}</li>
+ * <li>{@link #getNumActive()} > {@link #getMaxTotal()} - 3</li>
+ * <li>{@link #getNumIdle()} < 2</li>
+ * </ul>
*
- * @since 2.1
+ * @see #getRemoveAbandonedTimeout()
*/
@Override
- public boolean getLogExpiredConnections() {
- return logExpiredConnections;
+ public boolean getRemoveAbandonedOnBorrow() {
+ if (abandonedConfig != null) {
+ return abandonedConfig.getRemoveAbandonedOnBorrow();
+ }
+ return false;
}
/**
* <p>
- * Sets the maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an
- * infinite lifetime.
+ * Flag to remove abandoned connections if they exceed the removeAbandonedTimeout during pool maintenance.
* </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>
+ * The default value is false.
* </p>
*
- * @param maxConnLifetimeMillis
- * The maximum permitted lifetime of a connection in milliseconds.
+ * <p>
+ * If set to true a connection is considered abandoned and eligible for removal if it has not been used for more
+ * than {@link #getRemoveAbandonedTimeout() removeAbandonedTimeout} seconds.
+ * </p>
+ *
+ * @see #getRemoveAbandonedTimeout()
*/
- public void setMaxConnLifetimeMillis(final long maxConnLifetimeMillis) {
- this.maxConnLifetimeMillis = maxConnLifetimeMillis;
+ @Override
+ public boolean getRemoveAbandonedOnMaintenance() {
+ if (abandonedConfig != null) {
+ return abandonedConfig.getRemoveAbandonedOnMaintenance();
+ }
+ return false;
}
/**
- * When {@link #getMaxConnLifetimeMillis()} is set to limit connection lifetime, this property determines whether or
- * not log messages are generated when the pool closes connections due to maximum lifetime exceeded. Set this
- * property to false to suppress log messages when connections expire.
- *
- * @param logExpiredConnections
- * Whether or not log messages are generated when the pool closes connections due to maximum lifetime
- * exceeded.
+ * <p>
+ * Timeout in seconds before an abandoned connection can be removed.
+ * </p>
+ * <p>
+ * Creating a Statement, PreparedStatement or CallableStatement or using one of these to execute a query (using one
+ * of the execute methods) resets the lastUsed property of the parent connection.
+ * </p>
+ * <p>
+ * Abandoned connection cleanup happens when:
+ * </p>
+ * <ul>
+ * <li>{@link #getRemoveAbandonedOnBorrow()} or {@link #getRemoveAbandonedOnMaintenance()} = true</li>
+ * <li>{@link #getNumIdle() numIdle} < 2</li>
+ * <li>{@link #getNumActive() numActive} > {@link #getMaxTotal() maxTotal} - 3</li>
+ * </ul>
+ * <p>
+ * The default value is 300 seconds.
+ * </p>
*/
- public void setLogExpiredConnections(final boolean logExpiredConnections) {
- this.logExpiredConnections = logExpiredConnections;
+ @Override
+ public int getRemoveAbandonedTimeout() {
+ if (abandonedConfig != null) {
+ return abandonedConfig.getRemoveAbandonedTimeout();
+ }
+ return 300;
}
- private String jmxName;
-
/**
- * Returns the JMX name that has been requested for this DataSource. If the requested name is not valid, an
- * alternative may be chosen.
+ * Gets the current value of the flag that controls whether a connection will be rolled back when it is returned to
+ * the pool if auto commit is not enabled and the connection is not read only.
*
- * @return The JMX name that has been requested for this DataSource.
+ * @return whether a connection will be rolled back when it is returned to the pool.
*/
- public String getJmxName() {
- return jmxName;
+ public boolean getRollbackOnReturn() {
+ return rollbackOnReturn;
}
/**
- * Sets the JMX name that has been requested for this DataSource. If the requested name is not valid, an alternative
- * may be chosen. This DataSource will attempt to register itself using this name. If another component registers
- * this DataSource with JMX and this name is valid this name will be used in preference to any specified by the
- * other component.
+ * <p>
+ * Returns the minimum amount of time a connection may sit idle in the pool before it is eligible for eviction by
+ * the idle object evictor, with the extra condition that at least "minIdle" connections remain in the pool.
+ * </p>
*
- * @param jmxName
- * The JMX name that has been requested for this DataSource
+ * <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
*/
- public void setJmxName(final String jmxName) {
- this.jmxName = jmxName;
+ @Override
+ public synchronized long getSoftMinEvictableIdleTimeMillis() {
+ return softMinEvictableIdleTimeMillis;
}
- private boolean enableAutoCommitOnReturn = true;
-
/**
- * Returns the value of the flag that controls whether or not connections being returned to the pool will be checked
- * and configured with {@link Connection#setAutoCommit(boolean) Connection.setAutoCommit(true)} if the auto commit
- * setting is {@code false} when the connection is returned. It is <code>true</code> by default.
+ * Returns the {@link #testOnBorrow} property.
*
- * @return Whether or not connections being returned to the pool will be checked and configured with auto-commit.
+ * @return true if objects are validated before being borrowed from the pool
+ *
+ * @see #testOnBorrow
*/
- public boolean getEnableAutoCommitOnReturn() {
- return enableAutoCommitOnReturn;
+ @Override
+ public synchronized boolean getTestOnBorrow() {
+ return this.testOnBorrow;
}
/**
- * Sets the value of the flag that controls whether or not connections being returned to the pool will be checked
- * and configured with {@link Connection#setAutoCommit(boolean) Connection.setAutoCommit(true)} if the auto commit
- * setting is {@code false} when the connection is returned. It is <code>true</code> by default.
+ * Returns the {@link #testOnCreate} property.
*
- * @param enableAutoCommitOnReturn
- * Whether or not connections being returned to the pool will be checked and configured with auto-commit.
+ * @return true if objects are validated immediately after they are created by the pool
+ * @see #testOnCreate
*/
- public void setEnableAutoCommitOnReturn(final boolean enableAutoCommitOnReturn) {
- this.enableAutoCommitOnReturn = enableAutoCommitOnReturn;
+ @Override
+ public synchronized boolean getTestOnCreate() {
+ return this.testOnCreate;
}
- private boolean rollbackOnReturn = true;
-
/**
- * Gets the current value of the flag that controls whether a connection will be rolled back when it is returned to
- * the pool if auto commit is not enabled and the connection is not read only.
+ * Returns the value of the {@link #testOnReturn} property.
*
- * @return whether a connection will be rolled back when it is returned to the pool.
+ * @return true if objects are validated before being returned to the pool
+ * @see #testOnReturn
*/
- public boolean getRollbackOnReturn() {
- return rollbackOnReturn;
+ public synchronized boolean getTestOnReturn() {
+ return this.testOnReturn;
}
/**
- * Sets the flag that controls if a connection will be rolled back when it is returned to the pool if auto commit is
- * not enabled and the connection is not read only.
+ * Returns the value of the {@link #testWhileIdle} property.
*
- * @param rollbackOnReturn
- * whether a connection will be rolled back when it is returned to the pool.
+ * @return true if objects examined by the idle object evictor are validated
+ * @see #testWhileIdle
*/
- public void setRollbackOnReturn(final boolean rollbackOnReturn) {
- this.rollbackOnReturn = rollbackOnReturn;
+ @Override
+ public synchronized boolean getTestWhileIdle() {
+ return this.testWhileIdle;
}
- private volatile Set<String> disconnectionSqlCodes;
-
/**
- * Returns the set of SQL_STATE codes considered to signal fatal conditions.
+ * Returns the value of the {@link #timeBetweenEvictionRunsMillis} property.
*
- * @return fatal disconnection state codes
- * @see #setDisconnectionSqlCodes(Collection)
- * @since 2.1
+ * @return the time (in milliseconds) between evictor runs
+ * @see #timeBetweenEvictionRunsMillis
*/
- public Set<String> getDisconnectionSqlCodes() {
- final Set<String> result = disconnectionSqlCodes;
- if (result == null) {
- return Collections.emptySet();
- }
- return result;
+ @Override
+ public synchronized long getTimeBetweenEvictionRunsMillis() {
+ return this.timeBetweenEvictionRunsMillis;
}
/**
- * Provides the same data as {@link #getDisconnectionSqlCodes} but in an array so it is accessible via JMX.
+ * Returns the JDBC connection {@link #url} property.
*
- * @since 2.1
+ * @return the {@link #url} passed to the JDBC driver to establish connections
*/
@Override
- public String[] getDisconnectionSqlCodesAsArray() {
- final Collection<String> result = getDisconnectionSqlCodes();
- return result.toArray(new String[result.size()]);
+ public synchronized String getUrl() {
+ return this.url;
}
/**
- * Sets the SQL_STATE codes considered to signal fatal conditions.
- * <p>
- * Overrides the defaults in {@link Utils#DISCONNECTION_SQL_CODES} (plus anything starting with
- * {@link Utils#DISCONNECTION_SQL_CODE_PREFIX}). If this property is non-null and {@link #getFastFailValidation()}
- * is {@code true}, whenever connections created by this datasource generate exceptions with SQL_STATE codes in this
- * list, they will be marked as "fatally disconnected" and subsequent validations will fail fast (no attempt at
- * isValid or validation query).
- * </p>
- * <p>
- * If {@link #getFastFailValidation()} is {@code false} setting this property has no effect.
- * </p>
- * <p>
- * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
- * time one of the following methods is invoked: {@code getConnection, setLogwriter,
- * setLoginTimeout, getLoginTimeout, getLogWriter}.
- * </p>
+ * Returns the JDBC connection {@link #userName} property.
*
- * @param disconnectionSqlCodes
- * SQL_STATE codes considered to signal fatal conditions
- * @since 2.1
+ * @return the {@link #userName} passed to the JDBC driver to establish connections
*/
- public void setDisconnectionSqlCodes(final Collection<String> disconnectionSqlCodes) {
- if (disconnectionSqlCodes != null && disconnectionSqlCodes.size() > 0) {
- HashSet<String> newVal = null;
- for (final String s : disconnectionSqlCodes) {
- if (s != null && s.trim().length() > 0) {
- if (newVal == null) {
- newVal = new HashSet<>();
- }
- newVal.add(s);
- }
- }
- this.disconnectionSqlCodes = newVal;
- } else {
- this.disconnectionSqlCodes = null;
- }
+ @Override
+ public String getUsername() {
+ return this.userName;
}
- private boolean fastFailValidation;
-
/**
- * True means that validation will fail immediately for connections that have previously thrown SQLExceptions with
- * SQL_STATE indicating fatal disconnection errors.
+ * Returns the validation query used to validate connections before returning them.
*
- * @return true if connections created by this datasource will fast fail validation.
- * @see #setDisconnectionSqlCodes(Collection)
- * @since 2.1
+ * @return the SQL validation query
+ * @see #validationQuery
*/
@Override
- public boolean getFastFailValidation() {
- return fastFailValidation;
+ public String getValidationQuery() {
+ return this.validationQuery;
}
/**
- * @see #getFastFailValidation()
- * @param fastFailValidation
- * true means connections created by this factory will fast fail validation
- * @since 2.1
+ * Returns the validation query timeout.
+ *
+ * @return the timeout in seconds before connection validation queries fail.
*/
- public void setFastFailValidation(final boolean fastFailValidation) {
- this.fastFailValidation = fastFailValidation;
+ @Override
+ public int getValidationQueryTimeout() {
+ return validationQueryTimeoutSeconds;
}
/**
- * The object pool that internally manages our connections.
+ * Manually invalidates a connection, effectively requesting the pool to try to close it, remove it from the pool
+ * and reclaim pool capacity.
+ *
+ * @param connection
+ * The Connection to invalidate.
+ *
+ * @throws IllegalStateException
+ * if invalidating the connection failed.
+ * @since 2.1
*/
- private volatile GenericObjectPool<PoolableConnection> connectionPool;
-
- protected GenericObjectPool<PoolableConnection> getConnectionPool() {
- return connectionPool;
- }
+ public void invalidateConnection(final Connection connection) throws IllegalStateException {
+ if (connection == null) {
+ return;
+ }
+ if (connectionPool == null) {
+ throw new IllegalStateException("Cannot invalidate connection: ConnectionPool is null.");
+ }
- /**
- * The connection properties that will be sent to our JDBC driver when establishing new connections.
- * <strong>NOTE</strong> - The "user" and "password" properties will be passed explicitly, so they do not need to be
- * included here.
- */
- private Properties connectionProperties = new Properties();
+ final PoolableConnection poolableConnection;
+ try {
+ poolableConnection = connection.unwrap(PoolableConnection.class);
+ if (poolableConnection == null) {
+ throw new IllegalStateException(
+ "Cannot invalidate connection: Connection is not a poolable connection.");
+ }
+ } catch (final SQLException e) {
+ throw new IllegalStateException("Cannot invalidate connection: Unwrapping poolable connection failed.", e);
+ }
- // For unit testing
- Properties getConnectionProperties() {
- return connectionProperties;
+ try {
+ connectionPool.invalidateObject(poolableConnection);
+ } catch (final Exception e) {
+ throw new IllegalStateException("Invalidating connection threw unexpected exception", e);
+ }
}
/**
- * The data source we will use to manage connections. This object should be acquired <strong>ONLY</strong> by calls
- * to the <code>createDataSource()</code> method.
- */
- private volatile DataSource dataSource;
-
- /**
- * The PrintWriter to which log messages should be directed.
- */
- private volatile PrintWriter logWriter = new PrintWriter(
- new OutputStreamWriter(System.out, StandardCharsets.UTF_8));
-
- // ----------------------------------------------------- DataSource Methods
-
- /**
- * Creates (if necessary) and return a connection to the database.
+ * Manually evicts idle connections.
*
- * @throws SQLException
- * if a database access error occurs
- * @return a database connection
+ * @throws Exception Thrown by {@link GenericObjectPool#evict()}.
+ * @see GenericObjectPool#evict()
*/
- @Override
- public Connection getConnection() throws SQLException {
- if (Utils.IS_SECURITY_ENABLED) {
- final PrivilegedExceptionAction<Connection> action = new PaGetConnection();
- try {
- return AccessController.doPrivileged(action);
- } catch (final PrivilegedActionException e) {
- final Throwable cause = e.getCause();
- if (cause instanceof SQLException) {
- throw (SQLException) cause;
- }
- throw new SQLException(e);
- }
+ public void evict() throws Exception {
+ if (connectionPool != null) {
+ connectionPool.evict();
}
- return createDataSource().getConnection();
}
/**
- * <strong>BasicDataSource does NOT support this method.</strong>
- *
- * @param user
- * Database user on whose behalf the Connection is being made
- * @param pass
- * The database user's password
+ * Returns the value of the accessToUnderlyingConnectionAllowed property.
*
- * @throws UnsupportedOperationException
- * always thrown.
- * @throws SQLException
- * if a database access error occurs
- * @return nothing - always throws UnsupportedOperationException
+ * @return true if access to the underlying connection is allowed, false otherwise.
*/
@Override
- public Connection getConnection(final String user, final String pass) throws SQLException {
- // This method isn't supported by the PoolingDataSource returned by the createDataSource
- throw new UnsupportedOperationException("Not supported by BasicDataSource");
+ public synchronized boolean isAccessToUnderlyingConnectionAllowed() {
+ return this.accessToUnderlyingConnectionAllowed;
}
/**
- * <strong>BasicDataSource does NOT support this method.</strong>
- *
- * <p>
- * Returns the login timeout (in seconds) for connecting to the database.
- * </p>
- * <p>
- * Calls {@link #createDataSource()}, so has the side effect of initializing the connection pool.
- * </p>
+ * If true, this data source is closed and no more connections can be retrieved from this datasource.
*
- * @throws SQLException
- * if a database access error occurs
- * @throws UnsupportedOperationException
- * If the DataSource implementation does not support the login timeout feature.
- * @return login timeout in seconds
+ * @return true, if the data source is closed; false otherwise
*/
@Override
- public int getLoginTimeout() throws SQLException {
- // This method isn't supported by the PoolingDataSource returned by the createDataSource
- throw new UnsupportedOperationException("Not supported by BasicDataSource");
+ public synchronized boolean isClosed() {
+ return closed;
}
/**
- * <p>
- * Returns the log writer being used by this data source.
- * </p>
- * <p>
- * Calls {@link #createDataSource()}, so has the side effect of initializing the connection pool.
- * </p>
+ * Returns true if we are pooling statements.
*
- * @throws SQLException
- * if a database access error occurs
- * @return log writer in use
+ * @return true if prepared and callable statements are pooled
*/
@Override
- public PrintWriter getLogWriter() throws SQLException {
- return createDataSource().getLogWriter();
+ public synchronized boolean isPoolPreparedStatements() {
+ return this.poolPreparedStatements;
}
- /**
- * <strong>BasicDataSource does NOT support this method. </strong>
- *
- * <p>
- * Set the login timeout (in seconds) for connecting to the database.
- * </p>
- * <p>
- * Calls {@link #createDataSource()}, so has the side effect of initializing the connection pool.
- * </p>
- *
- * @param loginTimeout
- * The new login timeout, or zero for no timeout
- * @throws UnsupportedOperationException
- * If the DataSource implementation does not support the login timeout feature.
- * @throws SQLException
- * if a database access error occurs
- */
@Override
- public void setLoginTimeout(final int loginTimeout) throws SQLException {
- // This method isn't supported by the PoolingDataSource returned by the createDataSource
- throw new UnsupportedOperationException("Not supported by BasicDataSource");
+ public boolean isWrapperFor(final Class<?> iface) throws SQLException {
+ return false;
}
- /**
- * <p>
- * Sets the log writer being used by this data source.
- * </p>
- * <p>
- * Calls {@link #createDataSource()}, so has the side effect of initializing the connection pool.
- * </p>
- *
- * @param logWriter
- * The new log writer
- * @throws SQLException
- * if a database access error occurs
- */
- @Override
- public void setLogWriter(final PrintWriter logWriter) throws SQLException {
- createDataSource().setLogWriter(logWriter);
- this.logWriter = logWriter;
+ private void jmxRegister() {
+ // Return immediately if this DataSource has already been registered
+ if (registeredJmxObjectName != null) {
+ return;
+ }
+ // Return immediately if no JMX name has been specified
+ final String requestedName = getJmxName();
+ if (requestedName == null) {
+ return;
+ }
+ try {
+ ObjectNameWrapper.wrap(requestedName).registerMBean(this);
+ } catch (final MalformedObjectNameException e) {
+ log.warn("The requested JMX name [" + requestedName + "] was not valid and will be ignored.");
+ }
}
- private AbandonedConfig abandonedConfig;
+ protected void log(final String message) {
+ if (logWriter != null) {
+ logWriter.println(message);
+ }
+ }
- /**
- * <p>
- * Flag to remove abandoned connections if they exceed the removeAbandonedTimeout when borrowObject is invoked.
- * </p>
- * <p>
- * The default value is false.
- * </p>
- * <p>
- * If set to true a connection is considered abandoned and eligible for removal if it has not been used for more
- * than {@link #getRemoveAbandonedTimeout() removeAbandonedTimeout} seconds.
- * </p>
- * <p>
- * Abandoned connections are identified and removed when {@link #getConnection()} is invoked and all of the
- * following conditions hold:
- * </p>
- * <ul>
- * <li>{@link #getRemoveAbandonedOnBorrow()}</li>
- * <li>{@link #getNumActive()} > {@link #getMaxTotal()} - 3</li>
- * <li>{@link #getNumIdle()} < 2</li>
- * </ul>
- *
- * @see #getRemoveAbandonedTimeout()
- */
@Override
- public boolean getRemoveAbandonedOnBorrow() {
- if (abandonedConfig != null) {
- return abandonedConfig.getRemoveAbandonedOnBorrow();
- }
- return false;
- }
-
- /**
- * @param removeAbandonedOnMaintenance
- * true means abandoned connections may be removed on pool maintenance.
- * @see #getRemoveAbandonedOnMaintenance()
- */
- public void setRemoveAbandonedOnMaintenance(final boolean removeAbandonedOnMaintenance) {
- if (abandonedConfig == null) {
- abandonedConfig = new AbandonedConfig();
- }
- abandonedConfig.setRemoveAbandonedOnMaintenance(removeAbandonedOnMaintenance);
- final GenericObjectPool<?> gop = this.connectionPool;
- if (gop != null) {
- gop.setAbandonedConfig(abandonedConfig);
- }
+ public void postDeregister() {
+ // NO-OP
}
- /**
- * <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.
- * </p>
- *
- * @see #getRemoveAbandonedTimeout()
- */
@Override
- public boolean getRemoveAbandonedOnMaintenance() {
- if (abandonedConfig != null) {
- return abandonedConfig.getRemoveAbandonedOnMaintenance();
- }
- return false;
- }
-
- /**
- * @param removeAbandonedOnBorrow
- * true means abandoned connections may be removed when connections are borrowed from the pool.
- * @see #getRemoveAbandonedOnBorrow()
- */
- public void setRemoveAbandonedOnBorrow(final boolean removeAbandonedOnBorrow) {
- if (abandonedConfig == null) {
- abandonedConfig = new AbandonedConfig();
- }
- abandonedConfig.setRemoveAbandonedOnBorrow(removeAbandonedOnBorrow);
- final GenericObjectPool<?> gop = this.connectionPool;
- if (gop != null) {
- gop.setAbandonedConfig(abandonedConfig);
- }
+ public void postRegister(final Boolean registrationDone) {
+ // NO-OP
}
- /**
- * <p>
- * Timeout in seconds before an abandoned connection can be removed.
- * </p>
- * <p>
- * Creating a Statement, PreparedStatement or CallableStatement or using one of these to execute a query (using one
- * of the execute methods) resets the lastUsed property of the parent connection.
- * </p>
- * <p>
- * Abandoned connection cleanup happens when:
- * </p>
- * <ul>
- * <li>{@link #getRemoveAbandonedOnBorrow()} or {@link #getRemoveAbandonedOnMaintenance()} = true</li>
- * <li>{@link #getNumIdle() numIdle} < 2</li>
- * <li>{@link #getNumActive() numActive} > {@link #getMaxTotal() maxTotal} - 3</li>
- * </ul>
- * <p>
- * The default value is 300 seconds.
- * </p>
- */
@Override
- public int getRemoveAbandonedTimeout() {
- if (abandonedConfig != null) {
- return abandonedConfig.getRemoveAbandonedTimeout();
- }
- return 300;
- }
-
- /**
- * <p>
- * Sets the timeout in seconds before an abandoned connection can be removed.
- * </p>
- *
- * <p>
- * Setting this property has no effect if {@link #getRemoveAbandonedOnBorrow()} and
- * {@link #getRemoveAbandonedOnMaintenance()} are false.
- * </p>
- *
- * @param removeAbandonedTimeout
- * new abandoned timeout in seconds
- * @see #getRemoveAbandonedTimeout()
- * @see #getRemoveAbandonedOnBorrow()
- * @see #getRemoveAbandonedOnMaintenance()
- */
- public void setRemoveAbandonedTimeout(final int removeAbandonedTimeout) {
- if (abandonedConfig == null) {
- abandonedConfig = new AbandonedConfig();
- }
- abandonedConfig.setRemoveAbandonedTimeout(removeAbandonedTimeout);
- final GenericObjectPool<?> gop = this.connectionPool;
- if (gop != null) {
- gop.setAbandonedConfig(abandonedConfig);
- }
+ public void preDeregister() throws Exception {
+ // NO-OP
}
- /**
- * <p>
- * Flag to log stack traces for application code which abandoned a Statement or Connection.
- * </p>
- * <p>
- * Defaults to false.
- * </p>
- * <p>
- * Logging of abandoned Statements and Connections adds overhead for every Connection open or new Statement because
- * a stack trace has to be generated.
- * </p>
- */
@Override
- public boolean getLogAbandoned() {
- if (abandonedConfig != null) {
- return abandonedConfig.getLogAbandoned();
- }
- return false;
- }
-
- /**
- * @param logAbandoned
- * new logAbandoned property value
- */
- public void setLogAbandoned(final boolean logAbandoned) {
- if (abandonedConfig == null) {
- abandonedConfig = new AbandonedConfig();
+ public ObjectName preRegister(final MBeanServer server, final ObjectName objectName) {
+ final String requestedName = getJmxName();
+ if (requestedName != null) {
+ try {
+ registeredJmxObjectName = ObjectNameWrapper.wrap(requestedName);
+ } catch (final MalformedObjectNameException e) {
+ log.warn("The requested JMX name [" + requestedName + "] was not valid and will be ignored.");
+ }
}
- abandonedConfig.setLogAbandoned(logAbandoned);
- final GenericObjectPool<?> gop = this.connectionPool;
- if (gop != null) {
- gop.setAbandonedConfig(abandonedConfig);
+ if (registeredJmxObjectName == null) {
+ registeredJmxObjectName = ObjectNameWrapper.wrap(objectName);
}
+ return ObjectNameWrapper.unwrap(registeredJmxObjectName);
}
/**
- * Gets the print writer used by this configuration to log information on abandoned objects.
+ * Removes a custom connection property.
*
- * @return The print writer used by this configuration to log information on abandoned objects.
+ * @param name
+ * Name of the custom connection property to remove
+ * @see #addConnectionProperty(String, String)
*/
- public PrintWriter getAbandonedLogWriter() {
- if (abandonedConfig != null) {
- return abandonedConfig.getLogWriter();
- }
- return null;
+ public void removeConnectionProperty(final String name) {
+ connectionProperties.remove(name);
}
/**
@@ -1873,21 +1648,6 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * If the connection pool implements {@link org.apache.tomcat.dbcp.pool2.UsageTracking UsageTracking}, should the
- * connection pool record a stack trace every time a method is called on a pooled connection and retain the most
- * recent stack trace to aid debugging of abandoned connections?
- *
- * @return <code>true</code> if usage tracking is enabled
- */
- @Override
- public boolean getAbandonedUsageTracking() {
- if (abandonedConfig != null) {
- return abandonedConfig.getUseUsageTracking();
- }
- return false;
- }
-
- /**
* If the connection pool implements {@link org.apache.tomcat.dbcp.pool2.UsageTracking UsageTracking}, configure whether
* the connection pool should record a stack trace every time a method is called on a pooled connection and retain
* the most recent stack trace to aid debugging of abandoned connections.
@@ -1908,37 +1668,83 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
}
/**
- * Adds a custom connection property to the set that will be passed to our JDBC driver. This <strong>MUST</strong>
- * be called before the first connection is retrieved (along with all the other configuration property setters).
- * Calls to this method after the connection pool has been initialized have no effect.
+ * <p>
+ * Sets the value of the accessToUnderlyingConnectionAllowed property. It controls if the PoolGuard allows access to
+ * the underlying connection. (Default: false)
+ * </p>
+ * <p>
+ * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+ * time one of the following methods is invoked: <code>getConnection, setLogwriter,
+ * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+ * </p>
*
- * @param name
- * Name of the custom connection property
- * @param value
- * Value of the custom connection property
+ * @param allow
+ * Access to the underlying connection is granted when true.
*/
- public void addConnectionProperty(final String name, final String value) {
- connectionProperties.put(name, value);
+ public synchronized void setAccessToUnderlyingConnectionAllowed(final boolean allow) {
+ this.accessToUnderlyingConnectionAllowed = allow;
}
/**
- * Removes a custom connection property.
+ * Sets the value of the flag that controls whether or not connections being returned to the pool will be checked
+ * and configured with {@link Connection#setAutoCommit(boolean) Connection.setAutoCommit(true)} if the auto commit
+ * setting is {@code false} when the connection is returned. It is <code>true</code> by default.
*
- * @param name
- * Name of the custom connection property to remove
- * @see #addConnectionProperty(String, String)
+ * @param autoCommitOnReturn
+ * Whether or not connections being returned to the pool will be checked and configured with auto-commit.
+ * @since 2.6.0
*/
- public void removeConnectionProperty(final String name) {
- connectionProperties.remove(name);
+ public void setAutoCommitOnReturn(final boolean autoCommitOnReturn) {
+ this.autoCommitOnReturn = autoCommitOnReturn;
}
/**
- * Sets the connection properties passed to driver.connect(...).
- * <p>
- * Format of the string must be [propertyName=property;]*
- * </p>
+ * Sets the state caching flag.
+ *
+ * @param cacheState
+ * The new value for the state caching flag
+ */
+ public void setCacheState(final boolean cacheState) {
+ this.cacheState = cacheState;
+ }
+
+ /**
+ * Sets the list of SQL statements to be executed when a physical connection is first created.
* <p>
- * NOTE - The "user" and "password" properties will be added explicitly, so they do not need to be included here.
+ * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+ * time one of the following methods is invoked: <code>getConnection, setLogwriter,
+ * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+ * </p>
+ *
+ * @param connectionInitSqls
+ * Collection of SQL statements to execute on connection creation
+ */
+ public void setConnectionInitSqls(final Collection<String> connectionInitSqls) {
+ if (connectionInitSqls != null && connectionInitSqls.size() > 0) {
+ ArrayList<String> newVal = null;
+ for (final String s : connectionInitSqls) {
+ if (s != null && s.trim().length() > 0) {
+ if (newVal == null) {
+ newVal = new ArrayList<>();
+ }
+ newVal.add(s);
+ }
+ }
+ this.connectionInitSqls = newVal;
+ } else {
+ this.connectionInitSqls = null;
+ }
+ }
+
+ // ----------------------------------------------------- DataSource Methods
+
+ /**
+ * Sets the connection properties passed to driver.connect(...).
+ * <p>
+ * Format of the string must be [propertyName=property;]*
+ * </p>
+ * <p>
+ * NOTE - The "user" and "password" properties will be added explicitly, so they do not need to be included here.
* </p>
*
* @param connectionProperties
@@ -1964,503 +1770,752 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
this.connectionProperties = properties;
}
- private boolean closed;
-
/**
* <p>
- * Closes and releases all idle connections that are currently stored in the connection pool associated with this
- * data source.
+ * Sets default auto-commit state of connections returned by this datasource.
* </p>
* <p>
- * Connections that are checked out to clients when this method is invoked are not affected. When client
- * applications subsequently invoke {@link Connection#close()} to return these connections to the pool, the
- * underlying JDBC connections are closed.
+ * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+ * time one of the following methods is invoked: <code>getConnection, setLogwriter,
+ * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
* </p>
+ *
+ * @param defaultAutoCommit
+ * default auto-commit value
+ */
+ public void setDefaultAutoCommit(final Boolean defaultAutoCommit) {
+ this.defaultAutoCommit = defaultAutoCommit;
+ }
+
+ /**
* <p>
- * Attempts to acquire connections using {@link #getConnection()} after this method has been invoked result in
- * SQLExceptions.
+ * Sets the default catalog.
* </p>
* <p>
- * This method is idempotent - i.e., closing an already closed BasicDataSource has no effect and does not generate
- * exceptions.
+ * 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>
*
- * @throws SQLException
- * if an error occurs closing idle connections
+ * @param defaultCatalog
+ * the default catalog
*/
- @Override
- public synchronized void close() throws SQLException {
- if (registeredJmxObjectName != null) {
- registeredJmxObjectName.unregisterMBean();
- registeredJmxObjectName = null;
- }
- closed = true;
- final GenericObjectPool<?> oldpool = connectionPool;
- connectionPool = null;
- dataSource = null;
- try {
- if (oldpool != null) {
- oldpool.close();
- }
- } catch (final RuntimeException e) {
- throw e;
- } catch (final Exception e) {
- throw new SQLException(Utils.getMessage("pool.close.fail"), e);
+ public void setDefaultCatalog(final String defaultCatalog) {
+ if (defaultCatalog != null && defaultCatalog.trim().length() > 0) {
+ this.defaultCatalog = defaultCatalog;
+ } else {
+ this.defaultCatalog = null;
}
}
/**
- * If true, this data source is closed and no more connections can be retrieved from this datasource.
+ * 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.
*
- * @return true, if the data source is closed; false otherwise
+ * @param defaultQueryTimeoutSeconds
+ * The default query timeout in seconds.
*/
- @Override
- public synchronized boolean isClosed() {
- return closed;
+ public void setDefaultQueryTimeout(final Integer defaultQueryTimeoutSeconds) {
+ this.defaultQueryTimeoutSeconds = defaultQueryTimeoutSeconds;
}
- @Override
- public boolean isWrapperFor(final Class<?> iface) throws SQLException {
- return false;
+ /**
+ * <p>
+ * Sets defaultReadonly property.
+ * </p>
+ * <p>
+ * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+ * time one of the following methods is invoked: <code>getConnection, setLogwriter,
+ * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+ * </p>
+ *
+ * @param defaultReadOnly
+ * default read-only value
+ */
+ public void setDefaultReadOnly(final Boolean defaultReadOnly) {
+ this.defaultReadOnly = defaultReadOnly;
}
- @Override
- public <T> T unwrap(final Class<T> iface) throws SQLException {
- throw new SQLException("BasicDataSource is not a wrapper.");
+ /**
+ * <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,
+ * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+ * </p>
+ *
+ * @param defaultSchema
+ * the default catalog
+ * @since 2.5.0
+ */
+ public void setDefaultSchema(final String defaultSchema) {
+ if (defaultSchema != null && defaultSchema.trim().length() > 0) {
+ this.defaultSchema = defaultSchema;
+ } else {
+ this.defaultSchema = null;
+ }
}
- @Override
- public Logger getParentLogger() throws SQLFeatureNotSupportedException {
- throw new SQLFeatureNotSupportedException();
+ /**
+ * <p>
+ * Sets the default transaction isolation state for returned connections.
+ * </p>
+ * <p>
+ * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+ * time one of the following methods is invoked: <code>getConnection, setLogwriter,
+ * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+ * </p>
+ *
+ * @param defaultTransactionIsolation
+ * the default transaction isolation state
+ * @see Connection#getTransactionIsolation
+ */
+ public void setDefaultTransactionIsolation(final int defaultTransactionIsolation) {
+ this.defaultTransactionIsolation = defaultTransactionIsolation;
}
/**
- * Manually invalidates a connection, effectively requesting the pool to try to close it, remove it from the pool
- * and reclaim pool capacity.
- *
- * @param connection
- * The Connection to invalidate.
+ * Sets the SQL_STATE codes considered to signal fatal conditions.
+ * <p>
+ * Overrides the defaults in {@link Utils#DISCONNECTION_SQL_CODES} (plus anything starting with
+ * {@link Utils#DISCONNECTION_SQL_CODE_PREFIX}). If this property is non-null and {@link #getFastFailValidation()}
+ * is {@code true}, whenever connections created by this datasource generate exceptions with SQL_STATE codes in this
+ * list, they will be marked as "fatally disconnected" and subsequent validations will fail fast (no attempt at
+ * isValid or validation query).
+ * </p>
+ * <p>
+ * If {@link #getFastFailValidation()} is {@code false} setting this property has no effect.
+ * </p>
+ * <p>
+ * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+ * time one of the following methods is invoked: {@code getConnection, setLogwriter,
+ * setLoginTimeout, getLoginTimeout, getLogWriter}.
+ * </p>
*
- * @throws IllegalStateException
- * if invalidating the connection failed.
+ * @param disconnectionSqlCodes
+ * SQL_STATE codes considered to signal fatal conditions
* @since 2.1
*/
- public void invalidateConnection(final Connection connection) throws IllegalStateException {
- if (connection == null) {
- return;
- }
- if (connectionPool == null) {
- throw new IllegalStateException("Cannot invalidate connection: ConnectionPool is null.");
- }
-
- final PoolableConnection poolableConnection;
- try {
- poolableConnection = connection.unwrap(PoolableConnection.class);
- if (poolableConnection == null) {
- throw new IllegalStateException(
- "Cannot invalidate connection: Connection is not a poolable connection.");
+ public void setDisconnectionSqlCodes(final Collection<String> disconnectionSqlCodes) {
+ if (disconnectionSqlCodes != null && disconnectionSqlCodes.size() > 0) {
+ HashSet<String> newVal = null;
+ for (final String s : disconnectionSqlCodes) {
+ if (s != null && s.trim().length() > 0) {
+ if (newVal == null) {
+ newVal = new HashSet<>();
+ }
+ newVal.add(s);
+ }
}
- } catch (final SQLException e) {
- throw new IllegalStateException("Cannot invalidate connection: Unwrapping poolable connection failed.", e);
- }
-
- try {
- connectionPool.invalidateObject(poolableConnection);
- } catch (final Exception e) {
- throw new IllegalStateException("Invalidating connection threw unexpected exception", e);
+ this.disconnectionSqlCodes = newVal;
+ } else {
+ this.disconnectionSqlCodes = null;
}
}
- // ------------------------------------------------------ Protected Methods
+ /**
+ * Sets the JDBC Driver instance to use for this pool.
+ * <p>
+ * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+ * time one of the following methods is invoked: <code>getConnection, setLogwriter,
+ * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+ * </p>
+ *
+ * @param driver
+ * The JDBC Driver instance to use for this pool.
+ */
+ public synchronized void setDriver(final Driver driver) {
+ this.driver = driver;
+ }
/**
* <p>
- * Creates (if necessary) and return the internal data source we are using to manage our connections.
+ * Sets the class loader to be used to load the JDBC driver.
+ * </p>
+ * <p>
+ * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+ * time one of the following methods is invoked: <code>getConnection, setLogwriter,
+ * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
* </p>
*
- * @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.
+ * @param driverClassLoader
+ * the class loader with which to load the JDBC driver
*/
- protected DataSource createDataSource() throws SQLException {
- if (closed) {
- throw new SQLException("Data source is closed");
- }
+ public synchronized void setDriverClassLoader(final ClassLoader driverClassLoader) {
+ this.driverClassLoader = driverClassLoader;
+ }
- // Return the pool if we have already created it
- // This is double-checked locking. This is safe since dataSource is
- // volatile and the code is targeted at Java 5 onwards.
- if (dataSource != null) {
- return dataSource;
- }
- synchronized (this) {
- if (dataSource != null) {
- return dataSource;
- }
+ /**
+ * <p>
+ * Sets the JDBC driver class name.
+ * </p>
+ * <p>
+ * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+ * time one of the following methods is invoked: <code>getConnection, setLogwriter,
+ * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+ * </p>
+ *
+ * @param driverClassName
+ * the class name of the JDBC driver
+ */
+ public synchronized void setDriverClassName(final String driverClassName) {
+ if (driverClassName != null && driverClassName.trim().length() > 0) {
+ this.driverClassName = driverClassName;
+ } else {
+ this.driverClassName = null;
+ }
+ }
- jmxRegister();
+ /**
+ * Sets the value of the flag that controls whether or not connections being returned to the pool will be checked
+ * and configured with {@link Connection#setAutoCommit(boolean) Connection.setAutoCommit(true)} if the auto commit
+ * setting is {@code false} when the connection is returned. It is <code>true</code> by default.
+ *
+ * @param autoCommitOnReturn
+ * Whether or not connections being returned to the pool will be checked and configured with auto-commit.
+ * @deprecated Use {@link #setAutoCommitOnReturn(boolean)}.
+ */
+ @Deprecated
+ public void setEnableAutoCommitOnReturn(final boolean autoCommitOnReturn) {
+ this.autoCommitOnReturn = autoCommitOnReturn;
+ }
- // create factory which returns raw physical connections
- final ConnectionFactory driverConnectionFactory = createConnectionFactory();
+ /**
+ * Sets the EvictionPolicy implementation to use with this connection pool.
+ *
+ * @param evictionPolicyClassName
+ * The fully qualified class name of the EvictionPolicy implementation
+ */
+ public synchronized void setEvictionPolicyClassName(final String evictionPolicyClassName) {
+ if (connectionPool != null) {
+ connectionPool.setEvictionPolicyClassName(evictionPolicyClassName);
+ }
+ this.evictionPolicyClassName = evictionPolicyClassName;
+ }
- // Set up the poolable connection factory
- boolean success = false;
- PoolableConnectionFactory poolableConnectionFactory;
- try {
- poolableConnectionFactory = createPoolableConnectionFactory(driverConnectionFactory);
- poolableConnectionFactory.setPoolStatements(poolPreparedStatements);
- poolableConnectionFactory.setMaxOpenPreparedStatements(maxOpenPreparedStatements);
- success = true;
- } catch (final SQLException se) {
- throw se;
- } catch (final RuntimeException rte) {
- throw rte;
- } catch (final Exception ex) {
- throw new SQLException("Error creating connection factory", ex);
- }
+ /**
+ * @see #getFastFailValidation()
+ * @param fastFailValidation
+ * true means connections created by this factory will fast fail validation
+ * @since 2.1
+ */
+ public void setFastFailValidation(final boolean fastFailValidation) {
+ this.fastFailValidation = fastFailValidation;
+ }
- if (success) {
- // create a pool for our connections
- createConnectionPool(poolableConnectionFactory);
- }
+ /**
+ * <p>
+ * Sets the initial size of the connection pool.
+ * </p>
+ * <p>
+ * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+ * time one of the following methods is invoked: <code>getConnection, setLogwriter,
+ * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+ * </p>
+ *
+ * @param initialSize
+ * the number of connections created when the pool is initialized
+ */
+ public synchronized void setInitialSize(final int initialSize) {
+ this.initialSize = initialSize;
+ }
- // Create the pooling data source to manage connections
- DataSource newDataSource;
- success = false;
- try {
- newDataSource = createDataSourceInstance();
- newDataSource.setLogWriter(logWriter);
- success = true;
- } catch (final SQLException se) {
- throw se;
- } catch (final RuntimeException rte) {
- throw rte;
- } catch (final Exception ex) {
- throw new SQLException("Error creating datasource", ex);
- } finally {
- if (!success) {
- closeConnectionPool();
- }
- }
+ /**
+ * Sets the JMX name that has been requested for this DataSource. If the requested name is not valid, an alternative
+ * may be chosen. This DataSource will attempt to register itself using this name. If another component registers
+ * this DataSource with JMX and this name is valid this name will be used in preference to any specified by the
+ * other component.
+ *
+ * @param jmxName
+ * The JMX name that has been requested for this DataSource
+ */
+ public void setJmxName(final String jmxName) {
+ this.jmxName = jmxName;
+ }
- // If initialSize > 0, preload the pool
- try {
- for (int i = 0; i < initialSize; i++) {
- connectionPool.addObject();
- }
- } catch (final Exception e) {
- closeConnectionPool();
- throw new SQLException("Error preloading the connection pool", e);
- }
+ /**
+ * Sets the LIFO property. True means the pool behaves as a LIFO queue; false means FIFO.
+ *
+ * @param lifo
+ * the new value for the LIFO property
+ */
+ public synchronized void setLifo(final boolean lifo) {
+ this.lifo = lifo;
+ if (connectionPool != null) {
+ connectionPool.setLifo(lifo);
+ }
+ }
+
+ /**
+ * @param logAbandoned
+ * new logAbandoned property value
+ */
+ public void setLogAbandoned(final boolean logAbandoned) {
+ if (abandonedConfig == null) {
+ abandonedConfig = new AbandonedConfig();
+ }
+ abandonedConfig.setLogAbandoned(logAbandoned);
+ final GenericObjectPool<?> gop = this.connectionPool;
+ if (gop != null) {
+ gop.setAbandonedConfig(abandonedConfig);
+ }
+ }
+
+ /**
+ * When {@link #getMaxConnLifetimeMillis()} is set to limit connection lifetime, this property determines whether or
+ * not log messages are generated when the pool closes connections due to maximum lifetime exceeded. Set this
+ * property to false to suppress log messages when connections expire.
+ *
+ * @param logExpiredConnections
+ * Whether or not log messages are generated when the pool closes connections due to maximum lifetime
+ * exceeded.
+ */
+ public void setLogExpiredConnections(final boolean logExpiredConnections) {
+ this.logExpiredConnections = logExpiredConnections;
+ }
+
+ /**
+ * <strong>BasicDataSource does NOT support this method. </strong>
+ *
+ * <p>
+ * Set the login timeout (in seconds) for connecting to the database.
+ * </p>
+ * <p>
+ * Calls {@link #createDataSource()}, so has the side effect of initializing the connection pool.
+ * </p>
+ *
+ * @param loginTimeout
+ * The new login timeout, or zero for no timeout
+ * @throws UnsupportedOperationException
+ * If the DataSource implementation does not support the login timeout feature.
+ * @throws SQLException
+ * if a database access error occurs
+ */
+ @Override
+ public void setLoginTimeout(final int loginTimeout) throws SQLException {
+ // This method isn't supported by the PoolingDataSource returned by the createDataSource
+ throw new UnsupportedOperationException("Not supported by BasicDataSource");
+ }
+
+ /**
+ * <p>
+ * Sets the log writer being used by this data source.
+ * </p>
+ * <p>
+ * Calls {@link #createDataSource()}, so has the side effect of initializing the connection pool.
+ * </p>
+ *
+ * @param logWriter
+ * The new log writer
+ * @throws SQLException
+ * if a database access error occurs
+ */
+ @Override
+ public void setLogWriter(final PrintWriter logWriter) throws SQLException {
+ createDataSource().setLogWriter(logWriter);
+ this.logWriter = logWriter;
+ }
+
+ /**
+ * <p>
+ * Sets the maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an
+ * infinite lifetime.
+ * </p>
+ * <p>
+ * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+ * time one of the following methods is invoked: <code>getConnection, setLogwriter,
+ * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+ * </p>
+ *
+ * @param maxConnLifetimeMillis
+ * The maximum permitted lifetime of a connection in milliseconds.
+ */
+ public void setMaxConnLifetimeMillis(final long maxConnLifetimeMillis) {
+ this.maxConnLifetimeMillis = maxConnLifetimeMillis;
+ }
+
+ /**
+ * Sets the maximum number of connections that can remain idle in the pool. Excess idle connections are destroyed on
+ * return to the pool.
+ *
+ * @see #getMaxIdle()
+ * @param maxIdle
+ * the new value for maxIdle
+ */
+ public synchronized void setMaxIdle(final int maxIdle) {
+ this.maxIdle = maxIdle;
+ if (connectionPool != null) {
+ connectionPool.setMaxIdle(maxIdle);
+ }
+ }
+
+ /**
+ * <p>
+ * Sets the value of the <code>maxOpenPreparedStatements</code> property.
+ * </p>
+ * <p>
+ * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+ * time one of the following methods is invoked: <code>getConnection, setLogwriter,
+ * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+ * </p>
+ *
+ * @param maxOpenStatements
+ * the new maximum number of prepared statements
+ */
+ public synchronized void setMaxOpenPreparedStatements(final int maxOpenStatements) {
+ this.maxOpenPreparedStatements = maxOpenStatements;
+ }
+
+ /**
+ * Sets the maximum total number of idle and borrows connections that can be active at the same time. Use a negative
+ * value for no limit.
+ *
+ * @param maxTotal
+ * the new value for maxTotal
+ * @see #getMaxTotal()
+ */
+ public synchronized void setMaxTotal(final int maxTotal) {
+ this.maxTotal = maxTotal;
+ if (connectionPool != null) {
+ connectionPool.setMaxTotal(maxTotal);
+ }
+ }
+
+ /**
+ * Sets the MaxWaitMillis property. Use -1 to make the pool wait indefinitely.
+ *
+ * @param maxWaitMillis
+ * the new value for MaxWaitMillis
+ * @see #getMaxWaitMillis()
+ */
+ public synchronized void setMaxWaitMillis(final long maxWaitMillis) {
+ this.maxWaitMillis = maxWaitMillis;
+ if (connectionPool != null) {
+ connectionPool.setMaxWaitMillis(maxWaitMillis);
+ }
+ }
- // If timeBetweenEvictionRunsMillis > 0, start the pool's evictor task
- startPoolMaintenance();
+ /**
+ * Sets the {@link #minEvictableIdleTimeMillis} property.
+ *
+ * @param minEvictableIdleTimeMillis
+ * the minimum amount of time an object may sit idle in the pool
+ * @see #minEvictableIdleTimeMillis
+ */
+ public synchronized void setMinEvictableIdleTimeMillis(final long minEvictableIdleTimeMillis) {
+ this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
+ if (connectionPool != null) {
+ connectionPool.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
+ }
+ }
- dataSource = newDataSource;
- return dataSource;
+ /**
+ * Sets the minimum number of idle connections in the pool. The pool attempts to ensure that minIdle connections are
+ * available when the idle object evictor runs. The value of this property has no effect unless
+ * {@link #timeBetweenEvictionRunsMillis} has a positive value.
+ *
+ * @param minIdle
+ * the new value for minIdle
+ * @see GenericObjectPool#setMinIdle(int)
+ */
+ public synchronized void setMinIdle(final int minIdle) {
+ this.minIdle = minIdle;
+ if (connectionPool != null) {
+ connectionPool.setMinIdle(minIdle);
}
}
/**
- * Creates a JDBC connection factory for this datasource. The JDBC driver is loaded using the following algorithm:
- * <ol>
- * <li>If a Driver instance has been specified via {@link #setDriver(Driver)} use it</li>
- * <li>If no Driver instance was specified and {@link #driverClassName} is specified that class is loaded using the
- * {@link ClassLoader} of this class or, if {@link #driverClassLoader} is set, {@link #driverClassName} is loaded
- * with the specified {@link ClassLoader}.</li>
- * <li>If {@link #driverClassName} is specified and the previous attempt fails, the class is loaded using the
- * context class loader of the current thread.</li>
- * <li>If a driver still isn't loaded one is loaded via the {@link DriverManager} using the specified {@link #url}.
- * </ol>
- * This method exists so subclasses can replace the implementation class.
+ * Sets the value of the {@link #numTestsPerEvictionRun} property.
*
- * @return A new connection factory.
+ * @param numTestsPerEvictionRun
+ * the new {@link #numTestsPerEvictionRun} value
+ * @see #numTestsPerEvictionRun
+ */
+ public synchronized void setNumTestsPerEvictionRun(final int numTestsPerEvictionRun) {
+ this.numTestsPerEvictionRun = numTestsPerEvictionRun;
+ if (connectionPool != null) {
+ connectionPool.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
+ }
+ }
+
+ // ------------------------------------------------------ Protected Methods
+
+ /**
+ * <p>
+ * Sets the {@link #password}.
+ * </p>
+ * <p>
+ * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+ * time one of the following methods is invoked: <code>getConnection, setLogwriter,
+ * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+ * </p>
*
- * @throws SQLException
- * If the connection factort cannot be created
+ * @param password
+ * new value for the password
*/
- protected ConnectionFactory createConnectionFactory() throws SQLException {
- // Load the JDBC driver class
- Driver driverToUse = this.driver;
+ public void setPassword(final String password) {
+ this.password = password;
+ }
- if (driverToUse == null) {
- Class<?> driverFromCCL = null;
- if (driverClassName != null) {
- try {
- try {
- if (driverClassLoader == null) {
- driverFromCCL = Class.forName(driverClassName);
- } else {
- driverFromCCL = Class.forName(driverClassName, true, driverClassLoader);
- }
- } catch (final ClassNotFoundException cnfe) {
- driverFromCCL = Thread.currentThread().getContextClassLoader().loadClass(driverClassName);
- }
- } catch (final Exception t) {
- final String message = "Cannot load JDBC driver class '" + driverClassName + "'";
- logWriter.println(message);
- t.printStackTrace(logWriter);
- throw new SQLException(message, t);
- }
- }
+ /**
+ * <p>
+ * Sets whether to pool statements or not.
+ * </p>
+ * <p>
+ * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+ * time one of the following methods is invoked: <code>getConnection, setLogwriter,
+ * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+ * </p>
+ *
+ * @param poolingStatements
+ * pooling on or off
+ */
+ public synchronized void setPoolPreparedStatements(final boolean poolingStatements) {
+ this.poolPreparedStatements = poolingStatements;
+ }
- try {
- if (driverFromCCL == null) {
- driverToUse = DriverManager.getDriver(url);
- } else {
- // Usage of DriverManager is not possible, as it does not
- // respect the ContextClassLoader
- // N.B. This cast may cause ClassCastException which is handled below
- driverToUse = (Driver) driverFromCCL.getConstructor().newInstance();
- if (!driverToUse.acceptsURL(url)) {
- throw new SQLException("No suitable driver", "08001");
- }
- }
- } catch (final Exception t) {
- final String message = "Cannot create JDBC driver of class '"
- + (driverClassName != null ? driverClassName : "") + "' for connect URL '" + url + "'";
- logWriter.println(message);
- t.printStackTrace(logWriter);
- throw new SQLException(message, t);
- }
+ /**
+ * @param removeAbandonedOnBorrow
+ * true means abandoned connections may be removed when connections are borrowed from the pool.
+ * @see #getRemoveAbandonedOnBorrow()
+ */
+ public void setRemoveAbandonedOnBorrow(final boolean removeAbandonedOnBorrow) {
+ if (abandonedConfig == null) {
+ abandonedConfig = new AbandonedConfig();
}
-
- // Set up the driver connection factory we will use
- final String user = userName;
- if (user != null) {
- connectionProperties.put("user", user);
- } else {
- log("DBCP DataSource configured without a 'username'");
+ abandonedConfig.setRemoveAbandonedOnBorrow(removeAbandonedOnBorrow);
+ final GenericObjectPool<?> gop = this.connectionPool;
+ if (gop != null) {
+ gop.setAbandonedConfig(abandonedConfig);
}
+ }
- final String pwd = password;
- if (pwd != null) {
- connectionProperties.put("password", pwd);
- } else {
- log("DBCP DataSource configured without a 'password'");
+ /**
+ * @param removeAbandonedOnMaintenance
+ * true means abandoned connections may be removed on pool maintenance.
+ * @see #getRemoveAbandonedOnMaintenance()
+ */
+ public void setRemoveAbandonedOnMaintenance(final boolean removeAbandonedOnMaintenance) {
+ if (abandonedConfig == null) {
+ abandonedConfig = new AbandonedConfig();
+ }
+ abandonedConfig.setRemoveAbandonedOnMaintenance(removeAbandonedOnMaintenance);
+ final GenericObjectPool<?> gop = this.connectionPool;
+ if (gop != null) {
+ gop.setAbandonedConfig(abandonedConfig);
}
-
- final ConnectionFactory driverConnectionFactory = new DriverConnectionFactory(driverToUse, url,
- connectionProperties);
- return driverConnectionFactory;
}
/**
- * Creates a connection pool for this datasource. This method only exists so subclasses can replace the
- * implementation class.
* <p>
- * This implementation configures all pool properties other than timeBetweenEvictionRunsMillis. Setting that
- * property is deferred to {@link #startPoolMaintenance()}, since setting timeBetweenEvictionRunsMillis to a
- * positive value causes {@link GenericObjectPool}'s eviction timer to be started.
+ * Sets the timeout in seconds before an abandoned connection can be removed.
* </p>
*
- * @param factory
- * The factory to use to create new connections for this pool.
+ * <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 #getRemoveAbandonedOnBorrow()
+ * @see #getRemoveAbandonedOnMaintenance()
*/
- protected void createConnectionPool(final PoolableConnectionFactory factory) {
- // Create an object pool to contain our active connections
- final GenericObjectPoolConfig<PoolableConnection> config = new GenericObjectPoolConfig<>();
- updateJmxName(config);
- // Disable JMX on the underlying pool if the DS is not registered:
- config.setJmxEnabled(registeredJmxObjectName != null);
- final GenericObjectPool<PoolableConnection> gop = createObjectPool(factory, config, abandonedConfig);
- gop.setMaxTotal(maxTotal);
- gop.setMaxIdle(maxIdle);
- gop.setMinIdle(minIdle);
- gop.setMaxWaitMillis(maxWaitMillis);
- gop.setTestOnCreate(testOnCreate);
- gop.setTestOnBorrow(testOnBorrow);
- gop.setTestOnReturn(testOnReturn);
- gop.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
- gop.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
- gop.setSoftMinEvictableIdleTimeMillis(softMinEvictableIdleTimeMillis);
- gop.setTestWhileIdle(testWhileIdle);
- gop.setLifo(lifo);
- gop.setSwallowedExceptionListener(new SwallowedExceptionLogger(log, logExpiredConnections));
- gop.setEvictionPolicyClassName(evictionPolicyClassName);
- factory.setPool(gop);
- connectionPool = gop;
+ public void setRemoveAbandonedTimeout(final int removeAbandonedTimeout) {
+ if (abandonedConfig == null) {
+ abandonedConfig = new AbandonedConfig();
+ }
+ abandonedConfig.setRemoveAbandonedTimeout(removeAbandonedTimeout);
+ final GenericObjectPool<?> gop = this.connectionPool;
+ if (gop != null) {
+ gop.setAbandonedConfig(abandonedConfig);
+ }
}
/**
- * Creates an object pool used to provide pooling support for {@link Connection JDBC connections}.
+ * Sets the flag that controls if a connection will be rolled back when it is returned to the pool if auto commit is
+ * not enabled and the connection is not read only.
*
- * @param factory
- * the object factory
- * @param poolConfig
- * the object pool configuration
- * @param abandonedConfig
- * the abandoned objects configuration
- * @return a non-null instance
+ * @param rollbackOnReturn
+ * whether a connection will be rolled back when it is returned to the pool.
*/
- protected GenericObjectPool<PoolableConnection> createObjectPool(final PoolableConnectionFactory factory,
- final GenericObjectPoolConfig<PoolableConnection> poolConfig, final AbandonedConfig abandonedConfig) {
- GenericObjectPool<PoolableConnection> gop;
- if (abandonedConfig != null && (abandonedConfig.getRemoveAbandonedOnBorrow()
- || abandonedConfig.getRemoveAbandonedOnMaintenance())) {
- gop = new GenericObjectPool<>(factory, poolConfig, abandonedConfig);
- } else {
- gop = new GenericObjectPool<>(factory, poolConfig);
+ public void setRollbackOnReturn(final boolean rollbackOnReturn) {
+ this.rollbackOnReturn = rollbackOnReturn;
+ }
+
+ /**
+ * 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
+ */
+ public synchronized void setSoftMinEvictableIdleTimeMillis(final long softMinEvictableIdleTimeMillis) {
+ this.softMinEvictableIdleTimeMillis = softMinEvictableIdleTimeMillis;
+ if (connectionPool != null) {
+ connectionPool.setSoftMinEvictableIdleTimeMillis(softMinEvictableIdleTimeMillis);
}
- return gop;
}
/**
- * Closes the connection pool, silently swallowing any exception that occurs.
+ * Sets the {@link #testOnBorrow} property. This property determines whether or not the pool will validate objects
+ * before they are borrowed from the pool.
+ *
+ * @param testOnBorrow
+ * new value for testOnBorrow property
*/
- private void closeConnectionPool() {
- final GenericObjectPool<?> oldPool = connectionPool;
- connectionPool = null;
- try {
- if (oldPool != null) {
- oldPool.close();
- }
- } catch (final Exception e) {
- /* Ignore */
+ public synchronized void setTestOnBorrow(final boolean testOnBorrow) {
+ this.testOnBorrow = testOnBorrow;
+ if (connectionPool != null) {
+ connectionPool.setTestOnBorrow(testOnBorrow);
}
}
/**
- * Starts the connection pool maintenance task, if configured.
+ * Sets the {@link #testOnCreate} property. This property determines whether or not the pool will validate objects
+ * immediately after they are created by the pool
+ *
+ * @param testOnCreate
+ * new value for testOnCreate property
*/
- protected void startPoolMaintenance() {
- if (connectionPool != null && timeBetweenEvictionRunsMillis > 0) {
- connectionPool.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
+ public synchronized void setTestOnCreate(final boolean testOnCreate) {
+ this.testOnCreate = testOnCreate;
+ if (connectionPool != null) {
+ connectionPool.setTestOnCreate(testOnCreate);
}
}
/**
- * Creates the actual data source instance. This method only exists so that subclasses can replace the
- * implementation class.
- *
- * @throws SQLException
- * if unable to create a datasource instance
+ * Sets the <code>testOnReturn</code> property. This property determines whether or not the pool will validate
+ * objects before they are returned to the pool.
*
- * @return A new DataSource instance
+ * @param testOnReturn
+ * new value for testOnReturn property
*/
- protected DataSource createDataSourceInstance() throws SQLException {
- final PoolingDataSource<PoolableConnection> pds = new PoolingDataSource<>(connectionPool);
- pds.setAccessToUnderlyingConnectionAllowed(isAccessToUnderlyingConnectionAllowed());
- return pds;
+ public synchronized void setTestOnReturn(final boolean testOnReturn) {
+ this.testOnReturn = testOnReturn;
+ if (connectionPool != null) {
+ connectionPool.setTestOnReturn(testOnReturn);
+ }
}
/**
- * Creates the PoolableConnectionFactory and attaches it to the connection pool. This method only exists so
- * subclasses can replace the default implementation.
- *
- * @param driverConnectionFactory
- * JDBC connection factory
- * @throws SQLException
- * if an error occurs creating the PoolableConnectionFactory
+ * Sets the <code>testWhileIdle</code> property. This property determines whether or not the idle object evictor
+ * will validate connections.
*
- * @return A new PoolableConnectionFactory configured with the current configuration of this BasicDataSource
+ * @param testWhileIdle
+ * new value for testWhileIdle property
*/
- protected PoolableConnectionFactory createPoolableConnectionFactory(final ConnectionFactory driverConnectionFactory)
- throws SQLException {
- PoolableConnectionFactory connectionFactory = null;
- try {
- connectionFactory = new PoolableConnectionFactory(driverConnectionFactory,
- ObjectNameWrapper.unwrap(registeredJmxObjectName));
- connectionFactory.setValidationQuery(validationQuery);
- connectionFactory.setValidationQueryTimeout(validationQueryTimeoutSeconds);
- connectionFactory.setConnectionInitSql(connectionInitSqls);
- connectionFactory.setDefaultReadOnly(defaultReadOnly);
- connectionFactory.setDefaultAutoCommit(defaultAutoCommit);
- connectionFactory.setDefaultTransactionIsolation(defaultTransactionIsolation);
- connectionFactory.setDefaultCatalog(defaultCatalog);
- connectionFactory.setDefaultSchema(defaultSchema);
- connectionFactory.setCacheState(cacheState);
- connectionFactory.setPoolStatements(poolPreparedStatements);
- connectionFactory.setMaxOpenPreparedStatements(maxOpenPreparedStatements);
- connectionFactory.setMaxConnLifetimeMillis(maxConnLifetimeMillis);
- connectionFactory.setRollbackOnReturn(getRollbackOnReturn());
- connectionFactory.setEnableAutoCommitOnReturn(getEnableAutoCommitOnReturn());
- connectionFactory.setDefaultQueryTimeout(getDefaultQueryTimeout());
- connectionFactory.setFastFailValidation(fastFailValidation);
- connectionFactory.setDisconnectionSqlCodes(disconnectionSqlCodes);
- validateConnectionFactory(connectionFactory);
- } catch (final RuntimeException e) {
- throw e;
- } catch (final Exception e) {
- throw new SQLException("Cannot create PoolableConnectionFactory (" + e.getMessage() + ")", e);
+ public synchronized void setTestWhileIdle(final boolean testWhileIdle) {
+ this.testWhileIdle = testWhileIdle;
+ if (connectionPool != null) {
+ connectionPool.setTestWhileIdle(testWhileIdle);
}
- return connectionFactory;
}
- protected static void validateConnectionFactory(final PoolableConnectionFactory connectionFactory)
- throws Exception {
- PoolableConnection conn = null;
- PooledObject<PoolableConnection> p = null;
- try {
- p = connectionFactory.makeObject();
- conn = p.getObject();
- connectionFactory.activateObject(p);
- connectionFactory.validateConnection(conn);
- connectionFactory.passivateObject(p);
- } finally {
- if (p != null) {
- connectionFactory.destroyObject(p);
- }
+ /**
+ * Sets the {@link #timeBetweenEvictionRunsMillis} property.
+ *
+ * @param timeBetweenEvictionRunsMillis
+ * the new time between evictor runs
+ * @see #timeBetweenEvictionRunsMillis
+ */
+ public synchronized void setTimeBetweenEvictionRunsMillis(final long timeBetweenEvictionRunsMillis) {
+ this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
+ if (connectionPool != null) {
+ connectionPool.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
}
}
- protected void log(final String message) {
- if (logWriter != null) {
- logWriter.println(message);
- }
+ /**
+ * <p>
+ * Sets the {@link #url}.
+ * </p>
+ * <p>
+ * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+ * time one of the following methods is invoked: <code>getConnection, setLogwriter,
+ * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+ * </p>
+ *
+ * @param url
+ * the new value for the JDBC connection url
+ */
+ public synchronized void setUrl(final String url) {
+ this.url = url;
}
/**
- * Actual name under which this component has been registered.
+ * <p>
+ * Sets the {@link #userName}.
+ * </p>
+ * <p>
+ * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+ * time one of the following methods is invoked: <code>getConnection, setLogwriter,
+ * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+ * </p>
+ *
+ * @param userName
+ * the new value for the JDBC connection user name
*/
- private ObjectNameWrapper registeredJmxObjectName;
-
- private void jmxRegister() {
- // Return immediately if this DataSource has already been registered
- if (registeredJmxObjectName != null) {
- return;
- }
- // Return immediately if no JMX name has been specified
- final String requestedName = getJmxName();
- if (requestedName == null) {
- return;
- }
- try {
- ObjectNameWrapper.wrap(requestedName).registerMBean(this);
- } catch (final MalformedObjectNameException e) {
- log.warn("The requested JMX name [" + requestedName + "] was not valid and will be ignored.");
- }
+ public void setUsername(final String userName) {
+ this.userName = userName;
}
- @Override
- public ObjectName preRegister(final MBeanServer server, final ObjectName objectName) {
- final String requestedName = getJmxName();
- if (requestedName != null) {
- try {
- registeredJmxObjectName = ObjectNameWrapper.wrap(requestedName);
- } catch (final MalformedObjectNameException e) {
- log.warn("The requested JMX name [" + requestedName + "] was not valid and will be ignored.");
- }
- }
- if (registeredJmxObjectName == null) {
- registeredJmxObjectName = ObjectNameWrapper.wrap(objectName);
+ /**
+ * <p>
+ * Sets the {@link #validationQuery}.
+ * </p>
+ * <p>
+ * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
+ * time one of the following methods is invoked: <code>getConnection, setLogwriter,
+ * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
+ * </p>
+ *
+ * @param validationQuery
+ * the new value for the validation query
+ */
+ public void setValidationQuery(final String validationQuery) {
+ if (validationQuery != null && validationQuery.trim().length() > 0) {
+ this.validationQuery = validationQuery;
+ } else {
+ this.validationQuery = null;
}
- return ObjectNameWrapper.unwrap(registeredJmxObjectName);
}
- @Override
- public void postRegister(final Boolean registrationDone) {
- // NO-OP
+ /**
+ * 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
+ */
+ public void setValidationQueryTimeout(final int validationQueryTimeoutSeconds) {
+ this.validationQueryTimeoutSeconds = validationQueryTimeoutSeconds;
}
- @Override
- public void preDeregister() throws Exception {
- // NO-OP
+ /**
+ * Starts the connection pool maintenance task, if configured.
+ */
+ protected void startPoolMaintenance() {
+ if (connectionPool != null && timeBetweenEvictionRunsMillis > 0) {
+ connectionPool.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
+ }
}
@Override
- public void postDeregister() {
- // NO-OP
+ public <T> T unwrap(final Class<T> iface) throws SQLException {
+ throw new SQLException("BasicDataSource is not a wrapper.");
}
private void updateJmxName(final GenericObjectPoolConfig<?> config) {
@@ -2472,19 +2527,4 @@ public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBean
config.setJmxNameBase(base.toString());
config.setJmxNamePrefix(Constants.JMX_CONNECTION_POOL_PREFIX);
}
-
- protected ObjectName getRegisteredJmxName() {
- return ObjectNameWrapper.unwrap(registeredJmxObjectName);
- }
-
- /**
- * @since 2.0
- */
- private class PaGetConnection implements PrivilegedExceptionAction<Connection> {
-
- @Override
- public Connection run() throws SQLException {
- return createDataSource().getConnection();
- }
- }
}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceFactory.java b/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceFactory.java
index 200a8fe..eff9a7c 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceFactory.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/BasicDataSourceFactory.java
@@ -59,54 +59,54 @@ public class BasicDataSourceFactory implements ObjectFactory {
private static final Log log = LogFactory.getLog(BasicDataSourceFactory.class);
- private static final String PROP_DEFAULTAUTOCOMMIT = "defaultAutoCommit";
- private static final String PROP_DEFAULTREADONLY = "defaultReadOnly";
- private static final String PROP_DEFAULTTRANSACTIONISOLATION = "defaultTransactionIsolation";
- private static final String PROP_DEFAULTCATALOG = "defaultCatalog";
- private static final String PROP_DEFAULTSCHEMA = "defaultSchema";
- private static final String PROP_CACHESTATE = "cacheState";
- private static final String PROP_DRIVERCLASSNAME = "driverClassName";
+ private static final String PROP_DEFAULT_AUTO_COMMIT = "defaultAutoCommit";
+ private static final String PROP_DEFAULT_READ_ONLY = "defaultReadOnly";
+ private static final String PROP_DEFAULT_TRANSACTION_ISOLATION = "defaultTransactionIsolation";
+ private static final String PROP_DEFAULT_CATALOG = "defaultCatalog";
+ private static final String PROP_DEFAULT_SCHEMA = "defaultSchema";
+ private static final String PROP_CACHE_STATE = "cacheState";
+ private static final String PROP_DRIVER_CLASS_NAME = "driverClassName";
private static final String PROP_LIFO = "lifo";
- private static final String PROP_MAXTOTAL = "maxTotal";
- private static final String PROP_MAXIDLE = "maxIdle";
- private static final String PROP_MINIDLE = "minIdle";
- private static final String PROP_INITIALSIZE = "initialSize";
- private static final String PROP_MAXWAITMILLIS = "maxWaitMillis";
- private static final String PROP_TESTONCREATE = "testOnCreate";
- private static final String PROP_TESTONBORROW = "testOnBorrow";
- private static final String PROP_TESTONRETURN = "testOnReturn";
- private static final String PROP_TIMEBETWEENEVICTIONRUNSMILLIS = "timeBetweenEvictionRunsMillis";
- private static final String PROP_NUMTESTSPEREVICTIONRUN = "numTestsPerEvictionRun";
- private static final String PROP_MINEVICTABLEIDLETIMEMILLIS = "minEvictableIdleTimeMillis";
- private static final String PROP_SOFTMINEVICTABLEIDLETIMEMILLIS = "softMinEvictableIdleTimeMillis";
- private static final String PROP_EVICTIONPOLICYCLASSNAME = "evictionPolicyClassName";
- private static final String PROP_TESTWHILEIDLE = "testWhileIdle";
+ private static final String PROP_MAX_TOTAL = "maxTotal";
+ private static final String PROP_MAX_IDLE = "maxIdle";
+ private static final String PROP_MIN_IDLE = "minIdle";
+ private static final String PROP_INITIAL_SIZE = "initialSize";
+ private static final String PROP_MAX_WAIT_MILLIS = "maxWaitMillis";
+ private static final String PROP_TEST_ON_CREATE = "testOnCreate";
+ private static final String PROP_TEST_ON_BORROW = "testOnBorrow";
+ private static final String PROP_TEST_ON_RETURN = "testOnReturn";
+ private static final String PROP_TIME_BETWEEN_EVICTION_RUNS_MILLIS = "timeBetweenEvictionRunsMillis";
+ private static final String PROP_NUM_TESTS_PER_EVICTION_RUN = "numTestsPerEvictionRun";
+ private static final String PROP_MIN_EVICTABLE_IDLE_TIME_MILLIS = "minEvictableIdleTimeMillis";
+ private static final String PROP_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS = "softMinEvictableIdleTimeMillis";
+ private static final String PROP_EVICTION_POLICY_CLASS_NAME = "evictionPolicyClassName";
+ private static final String PROP_TEST_WHILE_IDLE = "testWhileIdle";
private static final String PROP_PASSWORD = "password";
private static final String PROP_URL = "url";
- private static final String PROP_USERNAME = "username";
- private static final String PROP_VALIDATIONQUERY = "validationQuery";
- private static final String PROP_VALIDATIONQUERY_TIMEOUT = "validationQueryTimeout";
+ private static final String PROP_USER_NAME = "username";
+ private static final String PROP_VALIDATION_QUERY = "validationQuery";
+ private static final String PROP_VALIDATION_QUERY_TIMEOUT = "validationQueryTimeout";
private static final String PROP_JMX_NAME = "jmxName";
/**
* The property name for connectionInitSqls. The associated value String must be of the form [query;]*
*/
- private static final String PROP_CONNECTIONINITSQLS = "connectionInitSqls";
- private static final String PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED = "accessToUnderlyingConnectionAllowed";
- private static final String PROP_REMOVEABANDONEDONBORROW = "removeAbandonedOnBorrow";
- private static final String PROP_REMOVEABANDONEDONMAINTENANCE = "removeAbandonedOnMaintenance";
- private static final String PROP_REMOVEABANDONEDTIMEOUT = "removeAbandonedTimeout";
- private static final String PROP_LOGABANDONED = "logAbandoned";
- private static final String PROP_ABANDONEDUSAGETRACKING = "abandonedUsageTracking";
- private static final String PROP_POOLPREPAREDSTATEMENTS = "poolPreparedStatements";
- private static final String PROP_MAXOPENPREPAREDSTATEMENTS = "maxOpenPreparedStatements";
- private static final String PROP_CONNECTIONPROPERTIES = "connectionProperties";
- private static final String PROP_MAXCONNLIFETIMEMILLIS = "maxConnLifetimeMillis";
- private static final String PROP_LOGEXPIREDCONNECTIONS = "logExpiredConnections";
+ private static final String PROP_CONNECTION_INIT_SQLS = "connectionInitSqls";
+ private static final String PROP_ACCESS_TO_UNDERLYING_CONNECTION_ALLOWED = "accessToUnderlyingConnectionAllowed";
+ private static final String PROP_REMOVE_ABANDONED_ON_BORROW = "removeAbandonedOnBorrow";
+ private static final String PROP_REMOVE_ABANDONED_ON_MAINTENANCE = "removeAbandonedOnMaintenance";
+ private static final String PROP_REMOVE_ABANDONED_TIMEOUT = "removeAbandonedTimeout";
+ private static final String PROP_LOG_ABANDONED = "logAbandoned";
+ private static final String PROP_ABANDONED_USAGE_TRACKING = "abandonedUsageTracking";
+ private static final String PROP_POOL_PREPARED_STATEMENTS = "poolPreparedStatements";
+ private static final String PROP_MAX_OPEN_PREPARED_STATEMENTS = "maxOpenPreparedStatements";
+ private static final String PROP_CONNECTION_PROPERTIES = "connectionProperties";
+ private static final String PROP_MAX_CONN_LIFETIME_MILLIS = "maxConnLifetimeMillis";
+ private static final String PROP_LOG_EXPIRED_CONNECTIONS = "logExpiredConnections";
private static final String PROP_ROLLBACK_ON_RETURN = "rollbackOnReturn";
- private static final String PROP_ENABLE_AUTOCOMMIT_ON_RETURN = "enableAutoCommitOnReturn";
- private static final String PROP_DEFAULT_QUERYTIMEOUT = "defaultQueryTimeout";
- private static final String PROP_FASTFAIL_VALIDATION = "fastFailValidation";
+ private static final String PROP_ENABLE_AUTO_COMMIT_ON_RETURN = "enableAutoCommitOnReturn";
+ private static final String PROP_DEFAULT_QUERY_TIMEOUT = "defaultQueryTimeout";
+ private static final String PROP_FAST_FAIL_VALIDATION = "fastFailValidation";
/**
* Value string must be of the form [STATE_CODE,]*
@@ -117,31 +117,31 @@ public class BasicDataSourceFactory implements ObjectFactory {
* Block with obsolete properties from DBCP 1.x. Warn users that these are ignored and they should use the 2.x
* properties.
*/
- private static final String NUPROP_MAXACTIVE = "maxActive";
- private static final String NUPROP_REMOVEABANDONED = "removeAbandoned";
+ private static final String NUPROP_MAX_ACTIVE = "maxActive";
+ private static final String NUPROP_REMOVE_ABANDONED = "removeAbandoned";
private static final String NUPROP_MAXWAIT = "maxWait";
/*
* Block with properties expected in a DataSource This props will not be listed as ignored - we know that they may
* appear in Resource, and not listing them as ignored.
*/
- private static final String SILENTPROP_FACTORY = "factory";
- private static final String SILENTPROP_SCOPE = "scope";
- private static final String SILENTPROP_SINGLETON = "singleton";
- private static final String SILENTPROP_AUTH = "auth";
-
- private static final String[] ALL_PROPERTIES = {PROP_DEFAULTAUTOCOMMIT, PROP_DEFAULTREADONLY,
- PROP_DEFAULTTRANSACTIONISOLATION, PROP_DEFAULTCATALOG, PROP_DEFAULTSCHEMA, PROP_CACHESTATE,
- PROP_DRIVERCLASSNAME, PROP_LIFO, PROP_MAXTOTAL, PROP_MAXIDLE, PROP_MINIDLE, PROP_INITIALSIZE,
- PROP_MAXWAITMILLIS, PROP_TESTONCREATE, PROP_TESTONBORROW, PROP_TESTONRETURN,
- PROP_TIMEBETWEENEVICTIONRUNSMILLIS, PROP_NUMTESTSPEREVICTIONRUN, PROP_MINEVICTABLEIDLETIMEMILLIS,
- PROP_SOFTMINEVICTABLEIDLETIMEMILLIS, PROP_EVICTIONPOLICYCLASSNAME, PROP_TESTWHILEIDLE, PROP_PASSWORD,
- PROP_URL, PROP_USERNAME, PROP_VALIDATIONQUERY, PROP_VALIDATIONQUERY_TIMEOUT, PROP_CONNECTIONINITSQLS,
- PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED, PROP_REMOVEABANDONEDONBORROW, PROP_REMOVEABANDONEDONMAINTENANCE,
- PROP_REMOVEABANDONEDTIMEOUT, PROP_LOGABANDONED, PROP_ABANDONEDUSAGETRACKING, PROP_POOLPREPAREDSTATEMENTS,
- PROP_MAXOPENPREPAREDSTATEMENTS, PROP_CONNECTIONPROPERTIES, PROP_MAXCONNLIFETIMEMILLIS,
- PROP_LOGEXPIREDCONNECTIONS, PROP_ROLLBACK_ON_RETURN, PROP_ENABLE_AUTOCOMMIT_ON_RETURN,
- PROP_DEFAULT_QUERYTIMEOUT, PROP_FASTFAIL_VALIDATION, PROP_DISCONNECTION_SQL_CODES, PROP_JMX_NAME };
+ private static final String SILENT_PROP_FACTORY = "factory";
+ private static final String SILENT_PROP_SCOPE = "scope";
+ private static final String SILENT_PROP_SINGLETON = "singleton";
+ private static final String SILENT_PROP_AUTH = "auth";
+
+ private static final String[] ALL_PROPERTIES = {PROP_DEFAULT_AUTO_COMMIT, PROP_DEFAULT_READ_ONLY,
+ PROP_DEFAULT_TRANSACTION_ISOLATION, PROP_DEFAULT_CATALOG, PROP_DEFAULT_SCHEMA, PROP_CACHE_STATE,
+ PROP_DRIVER_CLASS_NAME, PROP_LIFO, PROP_MAX_TOTAL, PROP_MAX_IDLE, PROP_MIN_IDLE, PROP_INITIAL_SIZE,
+ PROP_MAX_WAIT_MILLIS, PROP_TEST_ON_CREATE, PROP_TEST_ON_BORROW, PROP_TEST_ON_RETURN,
+ PROP_TIME_BETWEEN_EVICTION_RUNS_MILLIS, PROP_NUM_TESTS_PER_EVICTION_RUN, PROP_MIN_EVICTABLE_IDLE_TIME_MILLIS,
+ PROP_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS, PROP_EVICTION_POLICY_CLASS_NAME, PROP_TEST_WHILE_IDLE, PROP_PASSWORD,
+ PROP_URL, PROP_USER_NAME, PROP_VALIDATION_QUERY, PROP_VALIDATION_QUERY_TIMEOUT, PROP_CONNECTION_INIT_SQLS,
+ PROP_ACCESS_TO_UNDERLYING_CONNECTION_ALLOWED, PROP_REMOVE_ABANDONED_ON_BORROW, PROP_REMOVE_ABANDONED_ON_MAINTENANCE,
+ PROP_REMOVE_ABANDONED_TIMEOUT, PROP_LOG_ABANDONED, PROP_ABANDONED_USAGE_TRACKING, PROP_POOL_PREPARED_STATEMENTS,
+ PROP_MAX_OPEN_PREPARED_STATEMENTS, PROP_CONNECTION_PROPERTIES, PROP_MAX_CONN_LIFETIME_MILLIS,
+ PROP_LOG_EXPIRED_CONNECTIONS, PROP_ROLLBACK_ON_RETURN, PROP_ENABLE_AUTO_COMMIT_ON_RETURN,
+ PROP_DEFAULT_QUERY_TIMEOUT, PROP_FAST_FAIL_VALIDATION, PROP_DISCONNECTION_SQL_CODES, PROP_JMX_NAME };
/**
* Obsolete properties from DBCP 1.x. with warning strings suggesting new properties. LinkedHashMap will guarantee
@@ -150,16 +150,16 @@ public class BasicDataSourceFactory implements ObjectFactory {
private static final Map<String, String> NUPROP_WARNTEXT = new LinkedHashMap<>();
static {
- NUPROP_WARNTEXT.put(NUPROP_MAXACTIVE,
- "Property " + NUPROP_MAXACTIVE + " is not used in DBCP2, use " + PROP_MAXTOTAL + " instead. "
- + PROP_MAXTOTAL + " default value is " + GenericObjectPoolConfig.DEFAULT_MAX_TOTAL + ".");
- NUPROP_WARNTEXT.put(NUPROP_REMOVEABANDONED,
- "Property " + NUPROP_REMOVEABANDONED + " is not used in DBCP2," + " use one or both of "
- + PROP_REMOVEABANDONEDONBORROW + " or " + PROP_REMOVEABANDONEDONMAINTENANCE + " instead. "
+ NUPROP_WARNTEXT.put(NUPROP_MAX_ACTIVE,
+ "Property " + NUPROP_MAX_ACTIVE + " is not used in DBCP2, use " + PROP_MAX_TOTAL + " instead. "
+ + PROP_MAX_TOTAL + " default value is " + GenericObjectPoolConfig.DEFAULT_MAX_TOTAL + ".");
+ NUPROP_WARNTEXT.put(NUPROP_REMOVE_ABANDONED,
+ "Property " + NUPROP_REMOVE_ABANDONED + " is not used in DBCP2," + " use one or both of "
+ + PROP_REMOVE_ABANDONED_ON_BORROW + " or " + PROP_REMOVE_ABANDONED_ON_MAINTENANCE + " instead. "
+ "Both have default value set to false.");
NUPROP_WARNTEXT.put(NUPROP_MAXWAIT,
- "Property " + NUPROP_MAXWAIT + " is not used in DBCP2" + " , use " + PROP_MAXWAITMILLIS + " instead. "
- + PROP_MAXWAITMILLIS + " default value is " + BaseObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS
+ "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
+ ".");
}
@@ -170,10 +170,10 @@ public class BasicDataSourceFactory implements ObjectFactory {
private static final List<String> SILENT_PROPERTIES = new ArrayList<>();
static {
- SILENT_PROPERTIES.add(SILENTPROP_FACTORY);
- SILENT_PROPERTIES.add(SILENTPROP_SCOPE);
- SILENT_PROPERTIES.add(SILENTPROP_SINGLETON);
- SILENT_PROPERTIES.add(SILENTPROP_AUTH);
+ SILENT_PROPERTIES.add(SILENT_PROP_FACTORY);
+ SILENT_PROPERTIES.add(SILENT_PROP_SCOPE);
+ SILENT_PROPERTIES.add(SILENT_PROP_SINGLETON);
+ SILENT_PROPERTIES.add(SILENT_PROP_AUTH);
}
@@ -297,19 +297,19 @@ public class BasicDataSourceFactory implements ObjectFactory {
final BasicDataSource dataSource = new BasicDataSource();
String value = null;
- value = properties.getProperty(PROP_DEFAULTAUTOCOMMIT);
+ value = properties.getProperty(PROP_DEFAULT_AUTO_COMMIT);
if (value != null) {
dataSource.setDefaultAutoCommit(Boolean.valueOf(value));
}
- value = properties.getProperty(PROP_DEFAULTREADONLY);
+ value = properties.getProperty(PROP_DEFAULT_READ_ONLY);
if (value != null) {
dataSource.setDefaultReadOnly(Boolean.valueOf(value));
}
- value = properties.getProperty(PROP_DEFAULTTRANSACTIONISOLATION);
+ value = properties.getProperty(PROP_DEFAULT_TRANSACTION_ISOLATION);
if (value != null) {
- int level = PoolableConnectionFactory.UNKNOWN_TRANSACTIONISOLATION;
+ int level = PoolableConnectionFactory.UNKNOWN_TRANSACTION_ISOLATION;
if ("NONE".equalsIgnoreCase(value)) {
level = Connection.TRANSACTION_NONE;
} else if ("READ_COMMITTED".equalsIgnoreCase(value)) {
@@ -327,28 +327,28 @@ public class BasicDataSourceFactory implements ObjectFactory {
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_TRANSACTIONISOLATION;
+ level = PoolableConnectionFactory.UNKNOWN_TRANSACTION_ISOLATION;
}
}
dataSource.setDefaultTransactionIsolation(level);
}
- value = properties.getProperty(PROP_DEFAULTCATALOG);
+ value = properties.getProperty(PROP_DEFAULT_CATALOG);
if (value != null) {
dataSource.setDefaultCatalog(value);
}
- value = properties.getProperty(PROP_DEFAULTSCHEMA);
+ value = properties.getProperty(PROP_DEFAULT_SCHEMA);
if (value != null) {
dataSource.setDefaultSchema(value);
}
- value = properties.getProperty(PROP_CACHESTATE);
+ value = properties.getProperty(PROP_CACHE_STATE);
if (value != null) {
dataSource.setCacheState(Boolean.valueOf(value).booleanValue());
}
- value = properties.getProperty(PROP_DRIVERCLASSNAME);
+ value = properties.getProperty(PROP_DRIVER_CLASS_NAME);
if (value != null) {
dataSource.setDriverClassName(value);
}
@@ -358,72 +358,72 @@ public class BasicDataSourceFactory implements ObjectFactory {
dataSource.setLifo(Boolean.valueOf(value).booleanValue());
}
- value = properties.getProperty(PROP_MAXTOTAL);
+ value = properties.getProperty(PROP_MAX_TOTAL);
if (value != null) {
dataSource.setMaxTotal(Integer.parseInt(value));
}
- value = properties.getProperty(PROP_MAXIDLE);
+ value = properties.getProperty(PROP_MAX_IDLE);
if (value != null) {
dataSource.setMaxIdle(Integer.parseInt(value));
}
- value = properties.getProperty(PROP_MINIDLE);
+ value = properties.getProperty(PROP_MIN_IDLE);
if (value != null) {
dataSource.setMinIdle(Integer.parseInt(value));
}
- value = properties.getProperty(PROP_INITIALSIZE);
+ value = properties.getProperty(PROP_INITIAL_SIZE);
if (value != null) {
dataSource.setInitialSize(Integer.parseInt(value));
}
- value = properties.getProperty(PROP_MAXWAITMILLIS);
+ value = properties.getProperty(PROP_MAX_WAIT_MILLIS);
if (value != null) {
dataSource.setMaxWaitMillis(Long.parseLong(value));
}
- value = properties.getProperty(PROP_TESTONCREATE);
+ value = properties.getProperty(PROP_TEST_ON_CREATE);
if (value != null) {
dataSource.setTestOnCreate(Boolean.valueOf(value).booleanValue());
}
- value = properties.getProperty(PROP_TESTONBORROW);
+ value = properties.getProperty(PROP_TEST_ON_BORROW);
if (value != null) {
dataSource.setTestOnBorrow(Boolean.valueOf(value).booleanValue());
}
- value = properties.getProperty(PROP_TESTONRETURN);
+ value = properties.getProperty(PROP_TEST_ON_RETURN);
if (value != null) {
dataSource.setTestOnReturn(Boolean.valueOf(value).booleanValue());
}
- value = properties.getProperty(PROP_TIMEBETWEENEVICTIONRUNSMILLIS);
+ value = properties.getProperty(PROP_TIME_BETWEEN_EVICTION_RUNS_MILLIS);
if (value != null) {
dataSource.setTimeBetweenEvictionRunsMillis(Long.parseLong(value));
}
- value = properties.getProperty(PROP_NUMTESTSPEREVICTIONRUN);
+ value = properties.getProperty(PROP_NUM_TESTS_PER_EVICTION_RUN);
if (value != null) {
dataSource.setNumTestsPerEvictionRun(Integer.parseInt(value));
}
- value = properties.getProperty(PROP_MINEVICTABLEIDLETIMEMILLIS);
+ value = properties.getProperty(PROP_MIN_EVICTABLE_IDLE_TIME_MILLIS);
if (value != null) {
dataSource.setMinEvictableIdleTimeMillis(Long.parseLong(value));
}
- value = properties.getProperty(PROP_SOFTMINEVICTABLEIDLETIMEMILLIS);
+ value = properties.getProperty(PROP_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS);
if (value != null) {
dataSource.setSoftMinEvictableIdleTimeMillis(Long.parseLong(value));
}
- value = properties.getProperty(PROP_EVICTIONPOLICYCLASSNAME);
+ value = properties.getProperty(PROP_EVICTION_POLICY_CLASS_NAME);
if (value != null) {
dataSource.setEvictionPolicyClassName(value);
}
- value = properties.getProperty(PROP_TESTWHILEIDLE);
+ value = properties.getProperty(PROP_TEST_WHILE_IDLE);
if (value != null) {
dataSource.setTestWhileIdle(Boolean.valueOf(value).booleanValue());
}
@@ -438,67 +438,67 @@ public class BasicDataSourceFactory implements ObjectFactory {
dataSource.setUrl(value);
}
- value = properties.getProperty(PROP_USERNAME);
+ value = properties.getProperty(PROP_USER_NAME);
if (value != null) {
dataSource.setUsername(value);
}
- value = properties.getProperty(PROP_VALIDATIONQUERY);
+ value = properties.getProperty(PROP_VALIDATION_QUERY);
if (value != null) {
dataSource.setValidationQuery(value);
}
- value = properties.getProperty(PROP_VALIDATIONQUERY_TIMEOUT);
+ value = properties.getProperty(PROP_VALIDATION_QUERY_TIMEOUT);
if (value != null) {
dataSource.setValidationQueryTimeout(Integer.parseInt(value));
}
- value = properties.getProperty(PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED);
+ value = properties.getProperty(PROP_ACCESS_TO_UNDERLYING_CONNECTION_ALLOWED);
if (value != null) {
dataSource.setAccessToUnderlyingConnectionAllowed(Boolean.valueOf(value).booleanValue());
}
- value = properties.getProperty(PROP_REMOVEABANDONEDONBORROW);
+ value = properties.getProperty(PROP_REMOVE_ABANDONED_ON_BORROW);
if (value != null) {
dataSource.setRemoveAbandonedOnBorrow(Boolean.valueOf(value).booleanValue());
}
- value = properties.getProperty(PROP_REMOVEABANDONEDONMAINTENANCE);
+ value = properties.getProperty(PROP_REMOVE_ABANDONED_ON_MAINTENANCE);
if (value != null) {
dataSource.setRemoveAbandonedOnMaintenance(Boolean.valueOf(value).booleanValue());
}
- value = properties.getProperty(PROP_REMOVEABANDONEDTIMEOUT);
+ value = properties.getProperty(PROP_REMOVE_ABANDONED_TIMEOUT);
if (value != null) {
dataSource.setRemoveAbandonedTimeout(Integer.parseInt(value));
}
- value = properties.getProperty(PROP_LOGABANDONED);
+ value = properties.getProperty(PROP_LOG_ABANDONED);
if (value != null) {
dataSource.setLogAbandoned(Boolean.valueOf(value).booleanValue());
}
- value = properties.getProperty(PROP_ABANDONEDUSAGETRACKING);
+ value = properties.getProperty(PROP_ABANDONED_USAGE_TRACKING);
if (value != null) {
dataSource.setAbandonedUsageTracking(Boolean.valueOf(value).booleanValue());
}
- value = properties.getProperty(PROP_POOLPREPAREDSTATEMENTS);
+ value = properties.getProperty(PROP_POOL_PREPARED_STATEMENTS);
if (value != null) {
dataSource.setPoolPreparedStatements(Boolean.valueOf(value).booleanValue());
}
- value = properties.getProperty(PROP_MAXOPENPREPAREDSTATEMENTS);
+ value = properties.getProperty(PROP_MAX_OPEN_PREPARED_STATEMENTS);
if (value != null) {
dataSource.setMaxOpenPreparedStatements(Integer.parseInt(value));
}
- value = properties.getProperty(PROP_CONNECTIONINITSQLS);
+ value = properties.getProperty(PROP_CONNECTION_INIT_SQLS);
if (value != null) {
dataSource.setConnectionInitSqls(parseList(value, ';'));
}
- value = properties.getProperty(PROP_CONNECTIONPROPERTIES);
+ value = properties.getProperty(PROP_CONNECTION_PROPERTIES);
if (value != null) {
final Properties p = getProperties(value);
final Enumeration<?> e = p.propertyNames();
@@ -508,12 +508,12 @@ public class BasicDataSourceFactory implements ObjectFactory {
}
}
- value = properties.getProperty(PROP_MAXCONNLIFETIMEMILLIS);
+ value = properties.getProperty(PROP_MAX_CONN_LIFETIME_MILLIS);
if (value != null) {
dataSource.setMaxConnLifetimeMillis(Long.parseLong(value));
}
- value = properties.getProperty(PROP_LOGEXPIREDCONNECTIONS);
+ value = properties.getProperty(PROP_LOG_EXPIRED_CONNECTIONS);
if (value != null) {
dataSource.setLogExpiredConnections(Boolean.valueOf(value).booleanValue());
}
@@ -523,9 +523,9 @@ public class BasicDataSourceFactory implements ObjectFactory {
dataSource.setJmxName(value);
}
- value = properties.getProperty(PROP_ENABLE_AUTOCOMMIT_ON_RETURN);
+ value = properties.getProperty(PROP_ENABLE_AUTO_COMMIT_ON_RETURN);
if (value != null) {
- dataSource.setEnableAutoCommitOnReturn(Boolean.valueOf(value).booleanValue());
+ dataSource.setAutoCommitOnReturn(Boolean.valueOf(value).booleanValue());
}
value = properties.getProperty(PROP_ROLLBACK_ON_RETURN);
@@ -533,12 +533,12 @@ public class BasicDataSourceFactory implements ObjectFactory {
dataSource.setRollbackOnReturn(Boolean.valueOf(value).booleanValue());
}
- value = properties.getProperty(PROP_DEFAULT_QUERYTIMEOUT);
+ value = properties.getProperty(PROP_DEFAULT_QUERY_TIMEOUT);
if (value != null) {
dataSource.setDefaultQueryTimeout(Integer.valueOf(value));
}
- value = properties.getProperty(PROP_FASTFAIL_VALIDATION);
+ value = properties.getProperty(PROP_FAST_FAIL_VALIDATION);
if (value != null) {
dataSource.setFastFailValidation(Boolean.valueOf(value).booleanValue());
}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/DataSourceConnectionFactory.java b/java/org/apache/tomcat/dbcp/dbcp2/DataSourceConnectionFactory.java
index c56b500..5fdceab 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/DataSourceConnectionFactory.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/DataSourceConnectionFactory.java
@@ -58,7 +58,7 @@ public class DataSourceConnectionFactory implements ConnectionFactory {
public DataSourceConnectionFactory(final DataSource dataSource, final String userName, final char[] userPassword) {
this.dataSource = dataSource;
this.userName = userName;
- this.userPassword = userPassword;
+ this.userPassword = Utils.clone(userPassword);
}
/**
@@ -84,4 +84,28 @@ public class DataSourceConnectionFactory implements ConnectionFactory {
}
return dataSource.getConnection(userName, Utils.toString(userPassword));
}
+
+ /**
+ * @return The data source.
+ * @since 2.6.0
+ */
+ public DataSource getDataSource() {
+ return dataSource;
+ }
+
+ /**
+ * @return The user name.
+ * @since 2.6.0
+ */
+ public String getUserName() {
+ return userName;
+ }
+
+ /**
+ * @return The user password.
+ * @since 2.6.0
+ */
+ public char[] getUserPassword() {
+ return userPassword;
+ }
}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingConnection.java b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingConnection.java
index 3be956c..5869a36 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingConnection.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingConnection.java
@@ -88,7 +88,7 @@ public class DelegatingConnection<C extends Connection> extends AbandonedTrace i
* Returns a string representation of the metadata associated with the innermost delegate connection.
*/
@Override
- public String toString() {
+ public synchronized String toString() {
String s = null;
final Connection c = this.getInnermostDelegateInternal();
@@ -928,7 +928,7 @@ public class DelegatingConnection<C extends Connection> extends AbandonedTrace i
public void setSchema(final String schema) throws SQLException {
checkOpen();
try {
- connection.setSchema(schema);
+ Jdbc41Bridge.setSchema(connection, schema);
} catch (final SQLException e) {
handleException(e);
}
@@ -938,7 +938,7 @@ public class DelegatingConnection<C extends Connection> extends AbandonedTrace i
public String getSchema() throws SQLException {
checkOpen();
try {
- return connection.getSchema();
+ return Jdbc41Bridge.getSchema(connection);
} catch (final SQLException e) {
handleException(e);
return null;
@@ -949,7 +949,7 @@ public class DelegatingConnection<C extends Connection> extends AbandonedTrace i
public void abort(final Executor executor) throws SQLException {
checkOpen();
try {
- connection.abort(executor);
+ Jdbc41Bridge.abort(connection, executor);
} catch (final SQLException e) {
handleException(e);
}
@@ -959,7 +959,7 @@ public class DelegatingConnection<C extends Connection> extends AbandonedTrace i
public void setNetworkTimeout(final Executor executor, final int milliseconds) throws SQLException {
checkOpen();
try {
- connection.setNetworkTimeout(executor, milliseconds);
+ Jdbc41Bridge.setNetworkTimeout(connection, executor, milliseconds);
} catch (final SQLException e) {
handleException(e);
}
@@ -969,7 +969,7 @@ public class DelegatingConnection<C extends Connection> extends AbandonedTrace i
public int getNetworkTimeout() throws SQLException {
checkOpen();
try {
- return connection.getNetworkTimeout();
+ return Jdbc41Bridge.getNetworkTimeout(connection);
} catch (final SQLException e) {
handleException(e);
return 0;
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingDatabaseMetaData.java b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingDatabaseMetaData.java
index 8084b2d..a3f9bc1 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingDatabaseMetaData.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingDatabaseMetaData.java
@@ -130,7 +130,7 @@ public class DelegatingDatabaseMetaData implements DatabaseMetaData {
public boolean generatedKeyAlwaysReturned() throws SQLException {
connection.checkOpen();
try {
- return databaseMetaData.generatedKeyAlwaysReturned();
+ return Jdbc41Bridge.generatedKeyAlwaysReturned(databaseMetaData);
} catch (final SQLException e) {
handleException(e);
return false;
@@ -731,8 +731,8 @@ public class DelegatingDatabaseMetaData implements DatabaseMetaData {
final String columnNamePattern) throws SQLException {
connection.checkOpen();
try {
- return DelegatingResultSet.wrapResultSet(connection,
- databaseMetaData.getPseudoColumns(catalog, schemaPattern, tableNamePattern, columnNamePattern));
+ return DelegatingResultSet.wrapResultSet(connection, Jdbc41Bridge.getPseudoColumns(databaseMetaData,
+ catalog, schemaPattern, tableNamePattern, columnNamePattern));
} catch (final SQLException e) {
handleException(e);
throw new AssertionError();
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingPreparedStatement.java b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingPreparedStatement.java
index 35049d9..6719ead 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingPreparedStatement.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingPreparedStatement.java
@@ -647,7 +647,7 @@ public class DelegatingPreparedStatement extends DelegatingStatement implements
*/
@SuppressWarnings("resource")
@Override
- public String toString() {
+ public synchronized String toString() {
final Statement statement = getDelegate();
return statement == null ? "NULL" : statement.toString();
}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingResultSet.java b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingResultSet.java
index 1739c14..e26d13c 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingResultSet.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingResultSet.java
@@ -739,7 +739,7 @@ public final class DelegatingResultSet extends AbandonedTrace implements ResultS
@Override
public <T> T getObject(final int columnIndex, final Class<T> type) throws SQLException {
try {
- return resultSet.getObject(columnIndex, type);
+ return Jdbc41Bridge.getObject(resultSet, columnIndex, type);
} catch (final SQLException e) {
handleException(e);
return null;
@@ -769,7 +769,7 @@ public final class DelegatingResultSet extends AbandonedTrace implements ResultS
@Override
public <T> T getObject(final String columnLabel, final Class<T> type) throws SQLException {
try {
- return resultSet.getObject(columnLabel, type);
+ return Jdbc41Bridge.getObject(resultSet, columnLabel, type);
} catch (final SQLException e) {
handleException(e);
return null;
@@ -1241,8 +1241,8 @@ public final class DelegatingResultSet extends AbandonedTrace implements ResultS
}
@Override
- public String toString() {
- return super.toString() + "[_res=" + resultSet + ", _stmt=" + statement + ", _conn=" + connection + "]";
+ public synchronized String toString() {
+ return super.toString() + "[resultSet=" + resultSet + ", statement=" + statement + ", connection=" + connection + "]";
}
@Override
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingStatement.java b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingStatement.java
index 3bbdcd5..966d9b8 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/DelegatingStatement.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/DelegatingStatement.java
@@ -161,7 +161,7 @@ public class DelegatingStatement extends AbandonedTrace implements Statement {
public void closeOnCompletion() throws SQLException {
checkOpen();
try {
- statement.closeOnCompletion();
+ Jdbc41Bridge.closeOnCompletion(statement);
} catch (final SQLException e) {
handleException(e);
}
@@ -527,7 +527,7 @@ public class DelegatingStatement extends AbandonedTrace implements Statement {
public boolean isCloseOnCompletion() throws SQLException {
checkOpen();
try {
- return statement.isCloseOnCompletion();
+ return Jdbc41Bridge.isCloseOnCompletion(statement);
} catch (final SQLException e) {
handleException(e);
return false;
@@ -674,7 +674,7 @@ public class DelegatingStatement extends AbandonedTrace implements Statement {
* @return String
*/
@Override
- public String toString() {
+ public synchronized String toString() {
return statement == null ? "NULL" : statement.toString();
}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/DriverConnectionFactory.java b/java/org/apache/tomcat/dbcp/dbcp2/DriverConnectionFactory.java
index eebe56f..7e26052 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/DriverConnectionFactory.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/DriverConnectionFactory.java
@@ -53,6 +53,30 @@ public class DriverConnectionFactory implements ConnectionFactory {
return driver.connect(connectionString, properties);
}
+ /**
+ * @return The connection String.
+ * @since 2.6.0
+ */
+ public String getConnectionString() {
+ return connectionString;
+ }
+
+ /**
+ * @return The Driver.
+ * @since 2.6.0
+ */
+ public Driver getDriver() {
+ return driver;
+ }
+
+ /**
+ * @return The Properties.
+ * @since 2.6.0
+ */
+ public Properties getProperties() {
+ return properties;
+ }
+
@Override
public String toString() {
return this.getClass().getName() + " [" + String.valueOf(driver) + ";" + String.valueOf(connectionString) + ";"
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/DriverManagerConnectionFactory.java b/java/org/apache/tomcat/dbcp/dbcp2/DriverManagerConnectionFactory.java
index c8f462d..b9b49a1 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/DriverManagerConnectionFactory.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/DriverManagerConnectionFactory.java
@@ -38,6 +38,14 @@ public class DriverManagerConnectionFactory implements ConnectionFactory {
DriverManager.getDrivers();
}
+ private final String connectionUri;
+
+ private final String userName;
+
+ private final char[] userPassword;
+
+ private final Properties properties;
+
/**
* Constructor for DriverManagerConnectionFactory.
*
@@ -48,6 +56,8 @@ public class DriverManagerConnectionFactory implements ConnectionFactory {
public DriverManagerConnectionFactory(final String connectionUri) {
this.connectionUri = connectionUri;
this.properties = new Properties();
+ this.userName = null;
+ this.userPassword = null;
}
/**
@@ -62,6 +72,26 @@ public class DriverManagerConnectionFactory implements ConnectionFactory {
public DriverManagerConnectionFactory(final String connectionUri, final Properties properties) {
this.connectionUri = connectionUri;
this.properties = properties;
+ this.userName = null;
+ this.userPassword = null;
+ }
+
+ /**
+ * Constructor for DriverManagerConnectionFactory.
+ *
+ * @param connectionUri
+ * a database url of the form <code>jdbc:<em>subprotocol</em>:<em>subname</em></code>
+ * @param userName
+ * the database user
+ * @param userPassword
+ * the user's password
+ */
+ public DriverManagerConnectionFactory(final String connectionUri, final String userName,
+ final char[] userPassword) {
+ this.connectionUri = connectionUri;
+ this.userName = userName;
+ this.userPassword = Utils.clone(userPassword);
+ this.properties = null;
}
/**
@@ -78,7 +108,8 @@ public class DriverManagerConnectionFactory implements ConnectionFactory {
final String userPassword) {
this.connectionUri = connectionUri;
this.userName = userName;
- this.userPassword = userPassword;
+ this.userPassword = Utils.toCharArray(userPassword);
+ this.properties = null;
}
@Override
@@ -87,13 +118,32 @@ public class DriverManagerConnectionFactory implements ConnectionFactory {
if (userName == null && userPassword == null) {
return DriverManager.getConnection(connectionUri);
}
- return DriverManager.getConnection(connectionUri, userName, userPassword);
+ return DriverManager.getConnection(connectionUri, userName, Utils.toString(userPassword));
}
return DriverManager.getConnection(connectionUri, properties);
}
- private final String connectionUri;
- private String userName;
- private String userPassword;
- private Properties properties;
+ /**
+ * @return The connection URI.
+ * @since 2.6.0
+ */
+ public String getConnectionUri() {
+ return connectionUri;
+ }
+
+ /**
+ * @return The Properties.
+ * @since 2.6.0
+ */
+ public Properties getProperties() {
+ return properties;
+ }
+
+ /**
+ * @return The user name.
+ * @since 2.6.0
+ */
+ public String getUserName() {
+ return userName;
+ }
}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/Jdbc41Bridge.java b/java/org/apache/tomcat/dbcp/dbcp2/Jdbc41Bridge.java
new file mode 100644
index 0000000..b4ee5b9
--- /dev/null
+++ b/java/org/apache/tomcat/dbcp/dbcp2/Jdbc41Bridge.java
@@ -0,0 +1,482 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.dbcp.dbcp2;
+
+import java.io.InputStream;
+import java.io.Reader;
+import java.math.BigDecimal;
+import java.net.URL;
+import java.sql.Array;
+import java.sql.Blob;
+import java.sql.Clob;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.Date;
+import java.sql.Ref;
+import java.sql.ResultSet;
+import java.sql.RowId;
+import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
+import java.sql.SQLXML;
+import java.sql.Statement;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.util.concurrent.Executor;
+import java.util.logging.Logger;
+
+import javax.sql.CommonDataSource;
+
+/**
+ * Defines bridge methods to JDBC 4.1 (Java 7) methods to allow call sites to operate safely (without
+ * {@link AbstractMethodError}) when using a JDBC driver written for JDBC 4.0 (Java 6).
+ *
+ * @since 2.6.0
+ */
+public class Jdbc41Bridge {
+
+ /**
+ * Delegates to {@link Connection#abort(Executor)} without throwing a {@link AbstractMethodError}.
+ * <p>
+ * If the JDBC driver does not implement {@link Connection#abort(Executor)}, then call {@link Connection#close()}.
+ * </p>
+ *
+ * @param connection
+ * the receiver
+ * @param executor
+ * See {@link Connection#abort(Executor)}.
+ * @throws SQLException
+ * See {@link Connection#abort(Executor)}.
+ * @see Connection#abort(Executor)
+ */
+ public static void abort(final Connection connection, final Executor executor) throws SQLException {
+ try {
+ connection.abort(executor);
+ } catch (final AbstractMethodError e) {
+ connection.close();
+ }
+ }
+
+ /**
+ * Delegates to {@link DatabaseMetaData#generatedKeyAlwaysReturned()} without throwing a
+ * {@link AbstractMethodError}.
+ * <p>
+ * If the JDBC driver does not implement {@link DatabaseMetaData#generatedKeyAlwaysReturned()}, then return false.
+ * </p>
+ *
+ * @param databaseMetaData
+ * See {@link DatabaseMetaData#generatedKeyAlwaysReturned()}
+ * @return See {@link DatabaseMetaData#generatedKeyAlwaysReturned()}
+ * @throws SQLException
+ * See {@link DatabaseMetaData#generatedKeyAlwaysReturned()}
+ * @see DatabaseMetaData#generatedKeyAlwaysReturned()
+ */
+ public static boolean generatedKeyAlwaysReturned(final DatabaseMetaData databaseMetaData) throws SQLException {
+ try {
+ return databaseMetaData.generatedKeyAlwaysReturned();
+ } catch (final AbstractMethodError e) {
+ // do nothing
+ return false;
+ }
+ }
+
+ /**
+ * Delegates to {@link Connection#getNetworkTimeout()} without throwing a {@link AbstractMethodError}.
+ * <p>
+ * If the JDBC driver does not implement {@link Connection#getNetworkTimeout()}, then return 0.
+ * </p>
+ *
+ * @param connection
+ * the receiver
+ * @return See {@link Connection#getNetworkTimeout()}
+ * @throws SQLException
+ * See {@link Connection#getNetworkTimeout()}
+ * @see Connection#getNetworkTimeout()
+ */
+ public static int getNetworkTimeout(final Connection connection) throws SQLException {
+ try {
+ return connection.getNetworkTimeout();
+ } catch (final AbstractMethodError e) {
+ return 0;
+ }
+ }
+
+ /**
+ * Delegates to {@link ResultSet#getObject(int, Class)} without throwing a {@link AbstractMethodError}.
+ * <p>
+ * If the JDBC driver does not implement {@link ResultSet#getObject(int, Class)}, then return 0.
+ * </p>
+ *
+ * @param <T>
+ * See {@link ResultSet#getObject(int, Class)}
+ * @param resultSet
+ * See {@link ResultSet#getObject(int, Class)}
+ * @param columnIndex
+ * See {@link ResultSet#getObject(int, Class)}
+ * @param type
+ * See {@link ResultSet#getObject(int, Class)}
+ * @return See {@link ResultSet#getObject(int, Class)}
+ * @throws SQLException
+ * See {@link ResultSet#getObject(int, Class)}
+ * @see ResultSet#getObject(int, Class)
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> T getObject(final ResultSet resultSet, final int columnIndex, final Class<T> type)
+ throws SQLException {
+ try {
+ return resultSet.getObject(columnIndex, type);
+ } catch (final AbstractMethodError e) {
+ if (type == String.class) {
+ return (T) resultSet.getString(columnIndex);
+ }
+ // Numbers
+ if (type == Integer.class) {
+ return (T) Integer.valueOf(resultSet.getInt(columnIndex));
+ }
+ if (type == Long.class) {
+ return (T) Long.valueOf(resultSet.getLong(columnIndex));
+ }
+ if (type == Double.class) {
+ return (T) Double.valueOf(resultSet.getDouble(columnIndex));
+ }
+ if (type == Float.class) {
+ return (T) Float.valueOf(resultSet.getFloat(columnIndex));
+ }
+ if (type == Short.class) {
+ return (T) Short.valueOf(resultSet.getShort(columnIndex));
+ }
+ if (type == BigDecimal.class) {
+ return (T) resultSet.getBigDecimal(columnIndex);
+ }
+ if (type == Byte.class) {
+ return (T) Byte.valueOf(resultSet.getByte(columnIndex));
+ }
+ // Dates
+ if (type == Date.class) {
+ return (T) resultSet.getDate(columnIndex);
+ }
+ if (type == Time.class) {
+ return (T) resultSet.getTime(columnIndex);
+ }
+ if (type == Timestamp.class) {
+ return (T) resultSet.getTimestamp(columnIndex);
+ }
+ // Streams
+ if (type == InputStream.class) {
+ return (T) resultSet.getBinaryStream(columnIndex);
+ }
+ if (type == Reader.class) {
+ return (T) resultSet.getCharacterStream(columnIndex);
+ }
+ // Other
+ if (type == Object.class) {
+ return (T) resultSet.getObject(columnIndex);
+ }
+ if (type == Boolean.class) {
+ return (T) Boolean.valueOf(resultSet.getBoolean(columnIndex));
+ }
+ if (type == Array.class) {
+ return (T) resultSet.getArray(columnIndex);
+ }
+ if (type == Blob.class) {
+ return (T) resultSet.getBlob(columnIndex);
+ }
+ if (type == Clob.class) {
+ return (T) resultSet.getClob(columnIndex);
+ }
+ if (type == Ref.class) {
+ return (T) resultSet.getRef(columnIndex);
+ }
+ if (type == RowId.class) {
+ return (T) resultSet.getRowId(columnIndex);
+ }
+ if (type == SQLXML.class) {
+ return (T) resultSet.getSQLXML(columnIndex);
+ }
+ if (type == URL.class) {
+ return (T) resultSet.getURL(columnIndex);
+ }
+ throw new SQLFeatureNotSupportedException(
+ String.format("resultSet=%s, columnIndex=%,d, type=%s", resultSet, Integer.valueOf(columnIndex), type));
+ }
+ }
+
+ /**
+ * Delegates to {@link ResultSet#getObject(String, Class)} without throwing a {@link AbstractMethodError}.
+ *
+ * @param <T>
+ * See {@link ResultSet#getObject(String, Class)}
+ * @param resultSet
+ * See {@link ResultSet#getObject(String, Class)}
+ * @param columnLabel
+ * See {@link ResultSet#getObject(String, Class)}
+ * @param type
+ * See {@link ResultSet#getObject(String, Class)}
+ * @return See {@link ResultSet#getObject(String, Class)}
+ * @throws SQLException
+ * See {@link ResultSet#getObject(String, Class)}
+ * @see ResultSet#getObject(int, Class)
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> T getObject(final ResultSet resultSet, final String columnLabel, final Class<T> type)
+ throws SQLException {
+ try {
+ return resultSet.getObject(columnLabel, type);
+ } catch (final AbstractMethodError e) {
+ // Numbers
+ if (type == Integer.class) {
+ return (T) Integer.valueOf(resultSet.getInt(columnLabel));
+ }
+ if (type == Long.class) {
+ return (T) Long.valueOf(resultSet.getLong(columnLabel));
+ }
+ if (type == Double.class) {
+ return (T) Double.valueOf(resultSet.getDouble(columnLabel));
+ }
+ if (type == Float.class) {
+ return (T) Float.valueOf(resultSet.getFloat(columnLabel));
+ }
+ if (type == Short.class) {
+ return (T) Short.valueOf(resultSet.getShort(columnLabel));
+ }
+ if (type == BigDecimal.class) {
+ return (T) resultSet.getBigDecimal(columnLabel);
+ }
+ if (type == Byte.class) {
+ return (T) Byte.valueOf(resultSet.getByte(columnLabel));
+ }
+ // Dates
+ if (type == Date.class) {
+ return (T) resultSet.getDate(columnLabel);
+ }
+ if (type == Time.class) {
+ return (T) resultSet.getTime(columnLabel);
+ }
+ if (type == Timestamp.class) {
+ return (T) resultSet.getTimestamp(columnLabel);
+ }
+ // Streams
+ if (type == InputStream.class) {
+ return (T) resultSet.getBinaryStream(columnLabel);
+ }
+ if (type == Reader.class) {
+ return (T) resultSet.getCharacterStream(columnLabel);
+ }
+ // Other
+ if (type == Object.class) {
+ return (T) resultSet.getObject(columnLabel);
+ }
+ if (type == Boolean.class) {
+ return (T) Boolean.valueOf(resultSet.getBoolean(columnLabel));
+ }
+ if (type == Array.class) {
+ return (T) resultSet.getArray(columnLabel);
+ }
+ if (type == Blob.class) {
+ return (T) resultSet.getBlob(columnLabel);
+ }
+ if (type == Clob.class) {
+ return (T) resultSet.getClob(columnLabel);
+ }
+ if (type == Ref.class) {
+ return (T) resultSet.getRef(columnLabel);
+ }
+ if (type == RowId.class) {
+ return (T) resultSet.getRowId(columnLabel);
+ }
+ if (type == SQLXML.class) {
+ return (T) resultSet.getSQLXML(columnLabel);
+ }
+ if (type == URL.class) {
+ return (T) resultSet.getURL(columnLabel);
+ }
+ throw new SQLFeatureNotSupportedException(
+ String.format("resultSet=%s, columnLabel=%,d, type=%s", resultSet, columnLabel, type));
+ }
+ }
+
+ /**
+ * Delegates to {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)} without throwing a
+ * {@link AbstractMethodError}.
+ * <p>
+ * If the JDBC driver does not implement {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)},
+ * then return null.
+ * </p>
+ *
+ * @param databaseMetaData
+ * the receiver
+ * @param catalog
+ * See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)}
+ * @param schemaPattern
+ * See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)}
+ * @param tableNamePattern
+ * See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)}
+ * @param columnNamePattern
+ * See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)}
+ * @return See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)}
+ * @throws SQLException
+ * See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)}
+ * @see DatabaseMetaData#getPseudoColumns(String, String, String, String)
+ */
+ public static ResultSet getPseudoColumns(final DatabaseMetaData databaseMetaData, final String catalog,
+ final String schemaPattern, final String tableNamePattern, final String columnNamePattern)
+ throws SQLException {
+ try {
+ return databaseMetaData.getPseudoColumns(catalog, schemaPattern, tableNamePattern, columnNamePattern);
+ } catch (final AbstractMethodError e) {
+ // do nothing
+ return null;
+ }
+ }
+
+ /**
+ * Delegates to {@link Connection#getSchema()} without throwing a {@link AbstractMethodError}.
+ * <p>
+ * If the JDBC driver does not implement {@link Connection#getSchema()}, then return null.
+ * </p>
+ *
+ * @param connection
+ * the receiver
+ * @return null for a JDBC 4 driver or a value per {@link Connection#getSchema()}.
+ * @throws SQLException
+ * See {@link Connection#getSchema()}.
+ * @see Connection#getSchema()
+ */
+ public static String getSchema(final Connection connection) throws SQLException {
+ try {
+ return connection.getSchema();
+ } catch (final AbstractMethodError e) {
+ // do nothing
+ return null;
+ }
+ }
+
+ /**
+ * Delegates to {@link Connection#setNetworkTimeout(Executor, int)} without throwing a {@link AbstractMethodError}.
+ * <p>
+ * If the JDBC driver does not implement {@link Connection#setNetworkTimeout(Executor, int)}, then do nothing.
+ * </p>
+ *
+ * @param connection
+ * the receiver
+ * @param executor
+ * See {@link Connection#setNetworkTimeout(Executor, int)}
+ * @param milliseconds
+ * {@link Connection#setNetworkTimeout(Executor, int)}
+ * @throws SQLException
+ * {@link Connection#setNetworkTimeout(Executor, int)}
+ * @see Connection#setNetworkTimeout(Executor, int)
+ */
+ public static void setNetworkTimeout(final Connection connection, final Executor executor, final int milliseconds)
+ throws SQLException {
+ try {
+ connection.setNetworkTimeout(executor, milliseconds);
+ } catch (final AbstractMethodError e) {
+ // do nothing
+ }
+ }
+
+ /**
+ * Delegates to {@link Connection#setSchema(String)} without throwing a {@link AbstractMethodError}.
+ * <p>
+ * If the JDBC driver does not implement {@link Connection#setSchema(String)}, then do nothing.
+ * </p>
+ *
+ * @param connection
+ * the receiver
+ * @param schema
+ * See {@link Connection#setSchema(String)}.
+ * @throws SQLException
+ * See {@link Connection#setSchema(String)}.
+ * @see Connection#setSchema(String)
+ */
+ public static void setSchema(final Connection connection, final String schema) throws SQLException {
+ try {
+ connection.setSchema(schema);
+ } catch (final AbstractMethodError e) {
+ // do nothing
+ }
+ }
+
+ /**
+ * Delegates to {@link Statement#closeOnCompletion()} without throwing a {@link AbstractMethodError}.
+ * <p>
+ * If the JDBC driver does not implement {@link Statement#closeOnCompletion()}, then just check that the connection
+ * is closed to then throw a 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 a {@link AbstractMethodError}.
+ * <p>
+ * If the JDBC driver does not implement {@link Statement#isCloseOnCompletion()}, then just check that the
+ * connection is closed to then throw a 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 a {@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/LocalStrings.properties b/java/org/apache/tomcat/dbcp/dbcp2/LocalStrings.properties
index 2e0ada2..3aaa50b 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/LocalStrings.properties
+++ b/java/org/apache/tomcat/dbcp/dbcp2/LocalStrings.properties
@@ -15,12 +15,12 @@
connectionFactory.lifetimeExceeded=The lifetime of the connection [{0}] milliseconds exceeds the maximum permitted value of [{1}] milliseconds
-poolableConnectionFactory.validateObject.fail=Failed to validate a poolable connection.
+pool.close.fail=Cannot close connection pool.
poolableConnection.validate.fastFail=Fatal SQLException was thrown previously on this connection.
-swallowedExceptionLogger.onSwallowedException=An internal object pool swallowed an Exception.
+poolableConnectionFactory.validateObject.fail=Failed to validate a poolable connection.
poolingDataSource.factoryConfig=PoolableConnectionFactory not linked to pool. Calling setPool() to fix the configuration.
-pool.close.fail=Cannot close connection pool.
+swallowedExceptionLogger.onSwallowedException=An internal object pool swallowed an Exception.
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/ObjectNameWrapper.java b/java/org/apache/tomcat/dbcp/dbcp2/ObjectNameWrapper.java
index f036989..9c78936 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/ObjectNameWrapper.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/ObjectNameWrapper.java
@@ -18,6 +18,7 @@
package org.apache.tomcat.dbcp.dbcp2;
import java.lang.management.ManagementFactory;
+import java.util.Objects;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
@@ -76,6 +77,14 @@ class ObjectNameWrapper {
}
}
+ /**
+ * @since 2.7.0
+ */
+ @Override
+ public String toString() {
+ return Objects.toString(objectName);
+ }
+
public void unregisterMBean() {
if (MBEAN_SERVER == null || objectName == null) {
return;
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnection.java b/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnection.java
index 8b0a0f1..9c15c7e 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnection.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnection.java
@@ -329,4 +329,20 @@ public class PoolableConnection extends DelegatingConnection<Connection> impleme
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 2720757..4123d16 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnectionFactory.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/PoolableConnectionFactory.java
@@ -46,6 +46,53 @@ public class PoolableConnectionFactory implements PooledObjectFactory<PoolableCo
private static final Log log = LogFactory.getLog(PoolableConnectionFactory.class);
/**
+ * Internal constant to indicate the level is not set.
+ */
+ static final int UNKNOWN_TRANSACTION_ISOLATION = -1;
+
+ private final ConnectionFactory connectionFactory;
+
+ private final ObjectName dataSourceJmxObjectName;
+
+ private volatile String validationQuery;
+
+ private volatile int validationQueryTimeoutSeconds = -1;
+
+ private Collection<String> connectionInitSqls;
+
+ private Collection<String> disconnectionSqlCodes;
+
+ private boolean fastFailValidation = true;
+
+ private volatile ObjectPool<PoolableConnection> pool;
+
+ private Boolean defaultReadOnly;
+
+ private Boolean defaultAutoCommit;
+
+ private boolean autoCommitOnReturn = true;
+
+ private boolean rollbackOnReturn = true;
+
+ private int defaultTransactionIsolation = UNKNOWN_TRANSACTION_ISOLATION;
+
+ private String defaultCatalog;
+
+ private String defaultSchema;
+
+ private boolean cacheState;
+
+ private boolean poolStatements;
+
+ private int maxOpenPreparedStatements = GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL_PER_KEY;
+
+ private long maxConnLifetimeMillis = -1;
+
+ private final AtomicLong connectionIndex = new AtomicLong(0);
+
+ private Integer defaultQueryTimeoutSeconds;
+
+ /**
* Creates a new {@code PoolableConnectionFactory}.
*
* @param connFactory
@@ -58,179 +105,135 @@ public class PoolableConnectionFactory implements PooledObjectFactory<PoolableCo
this.dataSourceJmxObjectName = dataSourceJmxObjectName;
}
- /**
- * Sets the query I use to {@link #validateObject validate} {@link Connection}s. Should return at least one row. If
- * not specified, {@link Connection#isValid(int)} will be used to validate connections.
- *
- * @param validationQuery
- * a query to use to {@link #validateObject validate} {@link Connection}s.
- */
- public void setValidationQuery(final String validationQuery) {
- this.validationQuery = validationQuery;
+ @Override
+ public void activateObject(final PooledObject<PoolableConnection> p) throws Exception {
+
+ validateLifetime(p);
+
+ final PoolableConnection conn = p.getObject();
+ conn.activate();
+
+ if (defaultAutoCommit != null && conn.getAutoCommit() != defaultAutoCommit.booleanValue()) {
+ conn.setAutoCommit(defaultAutoCommit.booleanValue());
+ }
+ if (defaultTransactionIsolation != UNKNOWN_TRANSACTION_ISOLATION
+ && conn.getTransactionIsolation() != defaultTransactionIsolation) {
+ conn.setTransactionIsolation(defaultTransactionIsolation);
+ }
+ if (defaultReadOnly != null && conn.isReadOnly() != defaultReadOnly.booleanValue()) {
+ conn.setReadOnly(defaultReadOnly.booleanValue());
+ }
+ if (defaultCatalog != null && !defaultCatalog.equals(conn.getCatalog())) {
+ conn.setCatalog(defaultCatalog);
+ }
+ if (defaultSchema != null && !defaultSchema.equals(Jdbc41Bridge.getSchema(conn))) {
+ Jdbc41Bridge.setSchema(conn, defaultSchema);
+ }
+ conn.setDefaultQueryTimeout(defaultQueryTimeoutSeconds);
}
- /**
- * 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
- */
- public void setValidationQueryTimeout(final int validationQueryTimeoutSeconds) {
- this.validationQueryTimeoutSeconds = validationQueryTimeoutSeconds;
+ @Override
+ public void destroyObject(final PooledObject<PoolableConnection> p) throws Exception {
+ p.getObject().reallyClose();
}
/**
- * Sets the SQL statements I use to initialize newly created {@link Connection}s. Using {@code null} turns off
- * connection initialization.
- *
- * @param connectionInitSqls
- * SQL statement to initialize {@link Connection}s.
+ * @return The cache state.
+ * @since Made public in 2.6.0.
*/
- public void setConnectionInitSql(final Collection<String> connectionInitSqls) {
- this.connectionInitSqls = connectionInitSqls;
+ public boolean getCacheState() {
+ return cacheState;
}
/**
- * Sets the {@link ObjectPool} in which to pool {@link Connection}s.
- *
- * @param pool
- * the {@link ObjectPool} in which to pool those {@link Connection}s
+ * @return The connection factory.
+ * @since Made public in 2.6.0.
*/
- public synchronized void setPool(final ObjectPool<PoolableConnection> pool) {
- if (null != this.pool && pool != this.pool) {
- try {
- this.pool.close();
- } catch (final Exception e) {
- // ignored !?!
- }
- }
- this.pool = pool;
+ public ConnectionFactory getConnectionFactory() {
+ return connectionFactory;
}
- /**
- * Returns the {@link ObjectPool} in which {@link Connection}s are pooled.
- *
- * @return the connection pool
- */
- public synchronized ObjectPool<PoolableConnection> getPool() {
- return pool;
+ protected AtomicLong getConnectionIndex() {
+ return connectionIndex;
}
/**
- * Sets the default "read only" setting for borrowed {@link Connection}s
- *
- * @param defaultReadOnly
- * the default "read only" setting for borrowed {@link Connection}s
+ * @return The collection of initialization SQL statements.
+ * @since 2.6.0
*/
- public void setDefaultReadOnly(final Boolean defaultReadOnly) {
- this.defaultReadOnly = defaultReadOnly;
+ public Collection<String> getConnectionInitSqls() {
+ return connectionInitSqls;
}
/**
- * Sets the default "auto commit" setting for borrowed {@link Connection}s
- *
- * @param defaultAutoCommit
- * the default "auto commit" setting for borrowed {@link Connection}s
+ * @return The data source JMX ObjectName
+ * @since Made public in 2.6.0.
*/
- public void setDefaultAutoCommit(final Boolean defaultAutoCommit) {
- this.defaultAutoCommit = defaultAutoCommit;
+ public ObjectName getDataSourceJmxName() {
+ return dataSourceJmxObjectName;
}
/**
- * Sets the default "Transaction Isolation" setting for borrowed {@link Connection}s
- *
- * @param defaultTransactionIsolation
- * the default "Transaction Isolation" setting for returned {@link Connection}s
+ * @return The data source JMS ObjectName.
+ * @since 2.6.0
*/
- public void setDefaultTransactionIsolation(final int defaultTransactionIsolation) {
- this.defaultTransactionIsolation = defaultTransactionIsolation;
+ public ObjectName getDataSourceJmxObjectName() {
+ return dataSourceJmxObjectName;
}
/**
- * Sets the default "catalog" setting for borrowed {@link Connection}s
- *
- * @param defaultCatalog
- * the default "catalog" setting for borrowed {@link Connection}s
+ * @return Default auto-commit value.
+ * @since 2.6.0
*/
- public void setDefaultCatalog(final String defaultCatalog) {
- this.defaultCatalog = defaultCatalog;
+ public Boolean getDefaultAutoCommit() {
+ return defaultAutoCommit;
}
/**
- * Sets the default "schema" setting for borrowed {@link Connection}s
- *
- * @param defaultSchema
- * the default "schema" setting for borrowed {@link Connection}s
- * @since 2.5.0
+ * @return Default catalog.
+ * @since 2.6.0
*/
- public void setDefaultSchema(final String defaultSchema) {
- this.defaultSchema = defaultSchema;
- }
-
- public void setCacheState(final boolean cacheState) {
- this.cacheState = cacheState;
- }
-
- public void setPoolStatements(final boolean poolStatements) {
- this.poolStatements = poolStatements;
+ public String getDefaultCatalog() {
+ return defaultCatalog;
}
/**
- * Deprecated due to typo in method name.
- *
- * @param maxOpenPreparedStatements
- * The maximum number of open prepared statements.
- * @deprecated Use {@link #setMaxOpenPreparedStatements(int)}.
+ * @return Default query timeout in seconds.
*/
- @Deprecated // Due to typo in method name.
- public void setMaxOpenPrepatedStatements(final int maxOpenPreparedStatements) {
- setMaxOpenPreparedStatements(maxOpenPreparedStatements);
+ public Integer getDefaultQueryTimeout() {
+ return defaultQueryTimeoutSeconds;
}
/**
- * Sets the maximum number of open prepared statements.
- *
- * @param maxOpenPreparedStatements
- * The maximum number of open prepared statements.
+ * @return Default query timeout in seconds.
+ * @since 2.6.0
*/
- public void setMaxOpenPreparedStatements(final int maxOpenPreparedStatements) {
- this.maxOpenPreparedStatements = maxOpenPreparedStatements;
+ public Integer getDefaultQueryTimeoutSeconds() {
+ return defaultQueryTimeoutSeconds;
}
/**
- * 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.
+ * @return Default read-only-value.
+ * @since 2.6.0
*/
- public void setMaxConnLifetimeMillis(final long maxConnLifetimeMillis) {
- this.maxConnLifetimeMillis = maxConnLifetimeMillis;
- }
-
- public boolean isEnableAutoCommitOnReturn() {
- return enableAutoCommitOnReturn;
- }
-
- public void setEnableAutoCommitOnReturn(final boolean enableAutoCommitOnReturn) {
- this.enableAutoCommitOnReturn = enableAutoCommitOnReturn;
- }
-
- public boolean isRollbackOnReturn() {
- return rollbackOnReturn;
+ public Boolean getDefaultReadOnly() {
+ return defaultReadOnly;
}
- public void setRollbackOnReturn(final boolean rollbackOnReturn) {
- this.rollbackOnReturn = rollbackOnReturn;
- }
-
- public Integer getDefaultQueryTimeout() {
- return defaultQueryTimeoutSeconds;
+ /**
+ * @return Default schema.
+ * @since 2.6.0
+ */
+ public String getDefaultSchema() {
+ return defaultSchema;
}
- public void setDefaultQueryTimeout(final Integer defaultQueryTimeoutSeconds) {
- this.defaultQueryTimeoutSeconds = defaultQueryTimeoutSeconds;
+ /**
+ * @return Default transaction isolation.
+ * @since 2.6.0
+ */
+ public int getDefaultTransactionIsolation() {
+ return defaultTransactionIsolation;
}
/**
@@ -254,51 +257,112 @@ public class PoolableConnectionFactory implements PooledObjectFactory<PoolableCo
}
/**
- * @param disconnectionSqlCodes
- * The disconnection SQL codes.
- * @see #getDisconnectionSqlCodes()
- * @since 2.1
+ * @return Maximum connection lifetime in milliseconds.
+ * @since 2.6.0
*/
- public void setDisconnectionSqlCodes(final Collection<String> disconnectionSqlCodes) {
- this.disconnectionSqlCodes = disconnectionSqlCodes;
+ public long getMaxConnLifetimeMillis() {
+ return maxConnLifetimeMillis;
+ }
+
+ protected int getMaxOpenPreparedStatements() {
+ return maxOpenPreparedStatements;
}
/**
- * True means that validation will fail immediately for connections that have previously thrown SQLExceptions with
- * SQL_STATE indicating fatal disconnection errors.
+ * Returns the {@link ObjectPool} in which {@link Connection}s are pooled.
*
- * @return true if connections created by this factory will fast fail validation.
- * @see #setDisconnectionSqlCodes(Collection)
- * @since 2.1
- * @since 2.5.0 Defaults to true, previous versions defaulted to false.
+ * @return the connection pool
*/
- public boolean isFastFailValidation() {
- return fastFailValidation;
+ public synchronized ObjectPool<PoolableConnection> getPool() {
+ return pool;
}
/**
- * @see #isFastFailValidation()
- * @param fastFailValidation
- * true means connections created by this factory will fast fail validation
- * @since 2.1
+ * @return Whether to pool statements.
+ * @since Made public in 2.6.0.
*/
- public void setFastFailValidation(final boolean fastFailValidation) {
- this.fastFailValidation = fastFailValidation;
+ public boolean getPoolStatements() {
+ return poolStatements;
}
-
- @Override
- public PooledObject<PoolableConnection> makeObject() throws Exception {
- Connection conn = connectionFactory.createConnection();
- if (conn == null) {
- throw new IllegalStateException("Connection factory returned null from createConnection");
+ /**
+ * @return Validation query.
+ * @since 2.6.0
+ */
+ public String getValidationQuery() {
+ return validationQuery;
+ }
+ /**
+ * @return Validation query timeout in seconds.
+ * @since 2.6.0
+ */
+ public int getValidationQueryTimeoutSeconds() {
+ return validationQueryTimeoutSeconds;
+ }
+ protected void initializeConnection(final Connection conn) throws SQLException {
+ final Collection<String> sqls = connectionInitSqls;
+ if (conn.isClosed()) {
+ throw new SQLException("initializeConnection: connection closed");
}
- try {
- initializeConnection(conn);
- } catch (final SQLException sqle) {
- // Make sure the connection is closed
- try {
- conn.close();
- } catch (final SQLException ignore) {
+ if (null != sqls) {
+ try (Statement stmt = conn.createStatement()) {
+ for (final String sql : sqls) {
+ Objects.requireNonNull(sql, "null connectionInitSqls element");
+ stmt.execute(sql);
+ }
+ }
+ }
+ }
+
+ /**
+ * @return Whether to auto-commit on return.
+ * @since 2.6.0
+ */
+ public boolean isAutoCommitOnReturn() {
+ return autoCommitOnReturn;
+ }
+
+ /**
+ * @return Whether to auto-commit on return.
+ * @deprecated Use {@link #isAutoCommitOnReturn()}.
+ */
+ @Deprecated
+ public boolean isEnableAutoCommitOnReturn() {
+ return autoCommitOnReturn;
+ }
+
+ /**
+ * True means that validation will fail immediately for connections that have previously thrown SQLExceptions with
+ * SQL_STATE indicating fatal disconnection errors.
+ *
+ * @return true if connections created by this factory will fast fail validation.
+ * @see #setDisconnectionSqlCodes(Collection)
+ * @since 2.1
+ * @since 2.5.0 Defaults to true, previous versions defaulted to false.
+ */
+ public boolean isFastFailValidation() {
+ return fastFailValidation;
+ }
+
+ /**
+ * @return Whether to rollback on return.
+ */
+ public boolean isRollbackOnReturn() {
+ return rollbackOnReturn;
+ }
+
+ @Override
+ public PooledObject<PoolableConnection> makeObject() throws Exception {
+ Connection conn = connectionFactory.createConnection();
+ if (conn == null) {
+ throw new IllegalStateException("Connection factory returned null from createConnection");
+ }
+ try {
+ initializeConnection(conn);
+ } catch (final SQLException sqle) {
+ // Make sure the connection is closed
+ try {
+ conn.close();
+ } catch (final SQLException ignore) {
// ignore
}
// Rethrow original exception so it is visible to caller
@@ -347,48 +411,6 @@ public class PoolableConnectionFactory implements PooledObjectFactory<PoolableCo
return new DefaultPooledObject<>(pc);
}
- protected void initializeConnection(final Connection conn) throws SQLException {
- final Collection<String> sqls = connectionInitSqls;
- if (conn.isClosed()) {
- throw new SQLException("initializeConnection: connection closed");
- }
- if (null != sqls) {
- try (Statement stmt = conn.createStatement()) {
- for (final String sql : sqls) {
- Objects.requireNonNull(sql, "null connectionInitSqls element");
- stmt.execute(sql);
- }
- }
- }
- }
-
- @Override
- public void destroyObject(final PooledObject<PoolableConnection> p) throws Exception {
- p.getObject().reallyClose();
- }
-
- @Override
- public boolean validateObject(final PooledObject<PoolableConnection> p) {
- try {
- validateLifetime(p);
-
- validateConnection(p.getObject());
- return true;
- } catch (final Exception e) {
- if (log.isDebugEnabled()) {
- log.debug(Utils.getMessage("poolableConnectionFactory.validateObject.fail"), e);
- }
- return false;
- }
- }
-
- public void validateConnection(final PoolableConnection conn) throws SQLException {
- if (conn.isClosed()) {
- throw new SQLException("validateConnection: connection closed");
- }
- conn.validate(validationQuery, validationQueryTimeoutSeconds);
- }
-
@Override
public void passivateObject(final PooledObject<PoolableConnection> p) throws Exception {
@@ -407,7 +429,7 @@ public class PoolableConnectionFactory implements PooledObjectFactory<PoolableCo
// DBCP-97 / DBCP-399 / DBCP-351 Idle connections in the pool should
// have autoCommit enabled
- if (enableAutoCommitOnReturn) {
+ if (autoCommitOnReturn) {
if (connAutoCommit == null) {
connAutoCommit = Boolean.valueOf(conn.getAutoCommit());
}
@@ -419,91 +441,217 @@ public class PoolableConnectionFactory implements PooledObjectFactory<PoolableCo
conn.passivate();
}
- @Override
- public void activateObject(final PooledObject<PoolableConnection> p) throws Exception {
+ public void setAutoCommitOnReturn(final boolean autoCommitOnReturn) {
+ this.autoCommitOnReturn = autoCommitOnReturn;
+ }
- validateLifetime(p);
+ public void setCacheState(final boolean cacheState) {
+ this.cacheState = cacheState;
+ }
- final PoolableConnection conn = p.getObject();
- conn.activate();
+ /**
+ * Sets the SQL statements I use to initialize newly created {@link Connection}s. Using {@code null} turns off
+ * connection initialization.
+ *
+ * @param connectionInitSqls
+ * SQL statement to initialize {@link Connection}s.
+ */
+ public void setConnectionInitSql(final Collection<String> connectionInitSqls) {
+ this.connectionInitSqls = connectionInitSqls;
+ }
- if (defaultAutoCommit != null && conn.getAutoCommit() != defaultAutoCommit.booleanValue()) {
- conn.setAutoCommit(defaultAutoCommit.booleanValue());
- }
- if (defaultTransactionIsolation != UNKNOWN_TRANSACTIONISOLATION
- && conn.getTransactionIsolation() != defaultTransactionIsolation) {
- conn.setTransactionIsolation(defaultTransactionIsolation);
- }
- if (defaultReadOnly != null && conn.isReadOnly() != defaultReadOnly.booleanValue()) {
- conn.setReadOnly(defaultReadOnly.booleanValue());
- }
- if (defaultCatalog != null && !defaultCatalog.equals(conn.getCatalog())) {
- conn.setCatalog(defaultCatalog);
- }
- if (defaultSchema != null && !defaultSchema.equals(conn.getSchema())) {
- conn.setSchema(defaultSchema);
- }
- conn.setDefaultQueryTimeout(defaultQueryTimeoutSeconds);
+ /**
+ * Sets the default "auto commit" setting for borrowed {@link Connection}s
+ *
+ * @param defaultAutoCommit
+ * the default "auto commit" setting for borrowed {@link Connection}s
+ */
+ public void setDefaultAutoCommit(final Boolean defaultAutoCommit) {
+ this.defaultAutoCommit = defaultAutoCommit;
}
- 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)));
- }
- }
+ /**
+ * Sets the default "catalog" setting for borrowed {@link Connection}s
+ *
+ * @param defaultCatalog
+ * the default "catalog" setting for borrowed {@link Connection}s
+ */
+ public void setDefaultCatalog(final String defaultCatalog) {
+ this.defaultCatalog = defaultCatalog;
}
- protected ConnectionFactory getConnectionFactory() {
- return connectionFactory;
+ public void setDefaultQueryTimeout(final Integer defaultQueryTimeoutSeconds) {
+ this.defaultQueryTimeoutSeconds = defaultQueryTimeoutSeconds;
+ }
+ /**
+ * Sets the default "read only" setting for borrowed {@link Connection}s
+ *
+ * @param defaultReadOnly
+ * the default "read only" setting for borrowed {@link Connection}s
+ */
+ public void setDefaultReadOnly(final Boolean defaultReadOnly) {
+ this.defaultReadOnly = defaultReadOnly;
}
- protected boolean getPoolStatements() {
- return poolStatements;
+ /**
+ * Sets the default "schema" setting for borrowed {@link Connection}s
+ *
+ * @param defaultSchema
+ * the default "schema" setting for borrowed {@link Connection}s
+ * @since 2.5.0
+ */
+ public void setDefaultSchema(final String defaultSchema) {
+ this.defaultSchema = defaultSchema;
}
- protected int getMaxOpenPreparedStatements() {
- return maxOpenPreparedStatements;
+ /**
+ * Sets the default "Transaction Isolation" setting for borrowed {@link Connection}s
+ *
+ * @param defaultTransactionIsolation
+ * the default "Transaction Isolation" setting for returned {@link Connection}s
+ */
+ public void setDefaultTransactionIsolation(final int defaultTransactionIsolation) {
+ this.defaultTransactionIsolation = defaultTransactionIsolation;
}
- protected boolean getCacheState() {
- return cacheState;
+ /**
+ * @param disconnectionSqlCodes
+ * The disconnection SQL codes.
+ * @see #getDisconnectionSqlCodes()
+ * @since 2.1
+ */
+ public void setDisconnectionSqlCodes(final Collection<String> disconnectionSqlCodes) {
+ this.disconnectionSqlCodes = disconnectionSqlCodes;
}
- protected ObjectName getDataSourceJmxName() {
- return dataSourceJmxObjectName;
+ /**
+ * @param autoCommitOnReturn Whether to auto-commit on return.
+ * @deprecated Use {@link #setAutoCommitOnReturn(boolean)}.
+ */
+ @Deprecated
+ public void setEnableAutoCommitOnReturn(final boolean autoCommitOnReturn) {
+ this.autoCommitOnReturn = autoCommitOnReturn;
}
- protected AtomicLong getConnectionIndex() {
- return connectionIndex;
+ /**
+ * @see #isFastFailValidation()
+ * @param fastFailValidation
+ * true means connections created by this factory will fast fail validation
+ * @since 2.1
+ */
+ public void setFastFailValidation(final boolean fastFailValidation) {
+ this.fastFailValidation = fastFailValidation;
}
- private final ConnectionFactory connectionFactory;
- private final ObjectName dataSourceJmxObjectName;
- private volatile String validationQuery;
- private volatile int validationQueryTimeoutSeconds = -1;
- private Collection<String> connectionInitSqls;
- private Collection<String> disconnectionSqlCodes;
- private boolean fastFailValidation = true;
- private volatile ObjectPool<PoolableConnection> pool;
- private Boolean defaultReadOnly;
- private Boolean defaultAutoCommit;
- private boolean enableAutoCommitOnReturn = true;
- private boolean rollbackOnReturn = true;
- private int defaultTransactionIsolation = UNKNOWN_TRANSACTIONISOLATION;
- private String defaultCatalog;
- private String defaultSchema;
- private boolean cacheState;
- private boolean poolStatements;
- private int maxOpenPreparedStatements = GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL_PER_KEY;
- private long maxConnLifetimeMillis = -1;
- private final AtomicLong connectionIndex = new AtomicLong(0);
- private Integer defaultQueryTimeoutSeconds;
+ /**
+ * Sets the maximum lifetime in milliseconds of a connection after which the connection will always fail activation,
+ * passivation and validation. A value of zero or less indicates an infinite lifetime. The default value is -1.
+ *
+ * @param maxConnLifetimeMillis
+ * The maximum lifetime in milliseconds.
+ */
+ public void setMaxConnLifetimeMillis(final long maxConnLifetimeMillis) {
+ this.maxConnLifetimeMillis = maxConnLifetimeMillis;
+ }
/**
- * Internal constant to indicate the level is not set.
+ * Sets the maximum number of open prepared statements.
+ *
+ * @param maxOpenPreparedStatements
+ * The maximum number of open prepared statements.
+ */
+ public void setMaxOpenPreparedStatements(final int maxOpenPreparedStatements) {
+ this.maxOpenPreparedStatements = maxOpenPreparedStatements;
+ }
+
+ /**
+ * Deprecated due to typo in method name.
+ *
+ * @param maxOpenPreparedStatements
+ * The maximum number of open prepared statements.
+ * @deprecated Use {@link #setMaxOpenPreparedStatements(int)}.
*/
- static final int UNKNOWN_TRANSACTIONISOLATION = -1;
+ @Deprecated // Due to typo in method name.
+ public void setMaxOpenPrepatedStatements(final int maxOpenPreparedStatements) {
+ setMaxOpenPreparedStatements(maxOpenPreparedStatements);
+ }
+
+ /**
+ * Sets the {@link ObjectPool} in which to pool {@link Connection}s.
+ *
+ * @param pool
+ * the {@link ObjectPool} in which to pool those {@link Connection}s
+ */
+ public synchronized void setPool(final ObjectPool<PoolableConnection> pool) {
+ if (null != this.pool && pool != this.pool) {
+ try {
+ this.pool.close();
+ } catch (final Exception e) {
+ // ignored !?!
+ }
+ }
+ this.pool = pool;
+ }
+
+ public void setPoolStatements(final boolean poolStatements) {
+ this.poolStatements = poolStatements;
+ }
+
+ public void setRollbackOnReturn(final boolean rollbackOnReturn) {
+ this.rollbackOnReturn = rollbackOnReturn;
+ }
+
+ /**
+ * Sets the query I use to {@link #validateObject validate} {@link Connection}s. Should return at least one row. If
+ * not specified, {@link Connection#isValid(int)} will be used to validate connections.
+ *
+ * @param validationQuery
+ * a query to use to {@link #validateObject validate} {@link Connection}s.
+ */
+ public void setValidationQuery(final String validationQuery) {
+ this.validationQuery = validationQuery;
+ }
+
+ /**
+ * Sets the validation query timeout, the amount of time, in seconds, that connection validation will wait for a
+ * response from the database when executing a validation query. Use a value less than or equal to 0 for no timeout.
+ *
+ * @param validationQueryTimeoutSeconds
+ * new validation query timeout value in seconds
+ */
+ public void setValidationQueryTimeout(final int validationQueryTimeoutSeconds) {
+ this.validationQueryTimeoutSeconds = validationQueryTimeoutSeconds;
+ }
+
+ public void validateConnection(final PoolableConnection conn) throws SQLException {
+ if (conn.isClosed()) {
+ throw new SQLException("validateConnection: connection closed");
+ }
+ conn.validate(validationQuery, validationQueryTimeoutSeconds);
+ }
+
+ 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)));
+ }
+ }
+ }
+
+ @Override
+ public boolean validateObject(final PooledObject<PoolableConnection> p) {
+ try {
+ validateLifetime(p);
+
+ validateConnection(p.getObject());
+ return true;
+ } catch (final Exception e) {
+ if (log.isDebugEnabled()) {
+ log.debug(Utils.getMessage("poolableConnectionFactory.validateObject.fail"), e);
+ }
+ return false;
+ }
+ }
}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/PoolingConnection.java b/java/org/apache/tomcat/dbcp/dbcp2/PoolingConnection.java
index cb9252e..57dd54a 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/PoolingConnection.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/PoolingConnection.java
@@ -579,7 +579,7 @@ public class PoolingConnection extends DelegatingConnection<Connection>
}
@Override
- public String toString() {
+ public synchronized String toString() {
if (pstmtPool != null) {
return "PoolingConnection: " + pstmtPool.toString();
}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/PoolingDataSource.java b/java/org/apache/tomcat/dbcp/dbcp2/PoolingDataSource.java
index 70601b0..38a0472 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/PoolingDataSource.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/PoolingDataSource.java
@@ -75,7 +75,7 @@ public class PoolingDataSource<C extends Connection> implements DataSource, Auto
* @since 2.1
*/
@Override
- public void close() throws Exception {
+ public void close() throws RuntimeException, SQLException {
try {
pool.close();
} catch (final RuntimeException rte) {
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/Utils.java b/java/org/apache/tomcat/dbcp/dbcp2/Utils.java
index c80de46..a24360f 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/Utils.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/Utils.java
@@ -18,9 +18,6 @@
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.ResourceBundle;
@@ -47,9 +44,9 @@ public final class Utils {
/**
* SQL codes of fatal connection errors.
* <ul>
- * <li>57P01 (ADMIN SHUTDOWN)</li>
- * <li>57P02 (CRASH SHUTDOWN)</li>
- * <li>57P03 (CANNOT CONNECT NOW)</li>
+ * <li>57P01 (Admin shutdown)</li>
+ * <li>57P02 (Crash shutdown)</li>
+ * <li>57P03 (Cannot connect now)</li>
* <li>01002 (SQL92 disconnect error)</li>
* <li>JZ0C0 (Sybase disconnect error)</li>
* <li>JZ0C1 (Sybase disconnect error)</li>
@@ -59,18 +56,14 @@ public final class Utils {
static {
DISCONNECTION_SQL_CODES = new HashSet<>();
- DISCONNECTION_SQL_CODES.add("57P01"); // ADMIN SHUTDOWN
- DISCONNECTION_SQL_CODES.add("57P02"); // CRASH SHUTDOWN
- DISCONNECTION_SQL_CODES.add("57P03"); // CANNOT CONNECT NOW
+ DISCONNECTION_SQL_CODES.add("57P01"); // Admin shutdown
+ DISCONNECTION_SQL_CODES.add("57P02"); // Crash shutdown
+ DISCONNECTION_SQL_CODES.add("57P03"); // Cannot connect now
DISCONNECTION_SQL_CODES.add("01002"); // SQL92 disconnect error
DISCONNECTION_SQL_CODES.add("JZ0C0"); // Sybase disconnect error
DISCONNECTION_SQL_CODES.add("JZ0C1"); // Sybase disconnect error
}
- private Utils() {
- // not instantiable
- }
-
/**
* Clones the given char[] if not null.
*
@@ -83,47 +76,16 @@ public final class Utils {
}
/**
- * Closes the ResultSet (which may be null).
- *
- * @param resultSet
- * a ResultSet, may be {@code null}
- */
- public static void closeQuietly(final ResultSet resultSet) {
- if (resultSet != null) {
- try {
- resultSet.close();
- } catch (final Exception e) {
- // ignored
- }
- }
- }
-
- /**
- * Closes the Connection (which may be null).
+ * Closes the AutoCloseable (which may be null).
*
- * @param connection
- * a Connection, may be {@code null}
+ * @param autoCloseable
+ * an AutoCloseable, may be {@code null}
+ * @since 2.6.0
*/
- public static void closeQuietly(final Connection connection) {
- if (connection != null) {
+ public static void closeQuietly(final AutoCloseable autoCloseable) {
+ if (autoCloseable != null) {
try {
- connection.close();
- } catch (final Exception e) {
- // ignored
- }
- }
- }
-
- /**
- * Closes the Statement (which may be null).
- *
- * @param statement
- * a Statement, may be {@code null}.
- */
- public static void closeQuietly(final Statement statement) {
- if (statement != null) {
- try {
- statement.close();
+ autoCloseable.close();
} catch (final Exception e) {
// ignored
}
@@ -181,4 +143,8 @@ public final class Utils {
return value == null ? null : String.valueOf(value);
}
+ private Utils() {
+ // not instantiable
+ }
+
}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java b/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java
index 902edfb..fe0944f 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/DriverAdapterCPDS.java
@@ -730,4 +730,49 @@ public class DriverAdapterCPDS implements ConnectionPoolDataSource, Referenceabl
}
}
}
+
+ /**
+ * Does not print the userName and userPassword field nor the 'user' or 'password' in the connectionProperties.
+ *
+ * @since 2.6.0
+ */
+ @Override
+ public synchronized String toString() {
+ final StringBuilder builder = new StringBuilder(super.toString());
+ builder.append("[description=");
+ builder.append(description);
+ builder.append(", url=");
+ // TODO What if the connection string contains a 'user' or 'password' query parameter but that connection string is not in a legal URL format?
+ builder.append(url);
+ builder.append(", driver=");
+ builder.append(driver);
+ builder.append(", loginTimeout=");
+ builder.append(loginTimeout);
+ builder.append(", poolPreparedStatements=");
+ builder.append(poolPreparedStatements);
+ builder.append(", maxIdle=");
+ builder.append(maxIdle);
+ builder.append(", timeBetweenEvictionRunsMillis=");
+ builder.append(timeBetweenEvictionRunsMillis);
+ builder.append(", numTestsPerEvictionRun=");
+ builder.append(numTestsPerEvictionRun);
+ builder.append(", minEvictableIdleTimeMillis=");
+ builder.append(minEvictableIdleTimeMillis);
+ builder.append(", maxPreparedStatements=");
+ builder.append(maxPreparedStatements);
+ builder.append(", getConnectionCalled=");
+ builder.append(getConnectionCalled);
+ builder.append(", connectionProperties=");
+ Properties tmpProps = connectionProperties;
+ final String pwdKey = "password";
+ if (connectionProperties.contains(pwdKey)) {
+ tmpProps = (Properties) connectionProperties.clone();
+ tmpProps.remove(pwdKey);
+ }
+ builder.append(tmpProps);
+ builder.append(", accessToUnderlyingConnectionAllowed=");
+ builder.append(accessToUnderlyingConnectionAllowed);
+ builder.append("]");
+ return builder.toString();
+ }
}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PooledConnectionImpl.java b/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PooledConnectionImpl.java
index babc2ad..74b9eee 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PooledConnectionImpl.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/cpdsadapter/PooledConnectionImpl.java
@@ -30,6 +30,7 @@ import javax.sql.StatementEventListener;
import org.apache.tomcat.dbcp.dbcp2.DelegatingConnection;
import org.apache.tomcat.dbcp.dbcp2.DelegatingPreparedStatement;
+import org.apache.tomcat.dbcp.dbcp2.Jdbc41Bridge;
import org.apache.tomcat.dbcp.dbcp2.PStmtKey;
import org.apache.tomcat.dbcp.dbcp2.PoolableCallableStatement;
import org.apache.tomcat.dbcp.dbcp2.PoolablePreparedStatement;
@@ -295,7 +296,7 @@ class PooledConnectionImpl
private String getSchemaOrNull() {
try {
- return connection == null ? null : connection.getSchema();
+ return connection == null ? null : Jdbc41Bridge.getSchema(connection);
} catch (final SQLException e) {
return null;
}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/datasources/CPDSConnectionFactory.java b/java/org/apache/tomcat/dbcp/dbcp2/datasources/CPDSConnectionFactory.java
index ea609f4..02929e9 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/datasources/CPDSConnectionFactory.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/datasources/CPDSConnectionFactory.java
@@ -397,4 +397,30 @@ class CPDSConnectionFactory
}
}
}
+
+ /**
+ * @since 2.6.0
+ */
+ @Override
+ public synchronized String toString() {
+ final StringBuilder builder = new StringBuilder(super.toString());
+ builder.append("[cpds=");
+ builder.append(cpds);
+ builder.append(", validationQuery=");
+ builder.append(validationQuery);
+ builder.append(", validationQueryTimeoutSeconds=");
+ builder.append(validationQueryTimeoutSeconds);
+ builder.append(", rollbackAfterValidation=");
+ builder.append(rollbackAfterValidation);
+ builder.append(", pool=");
+ builder.append(pool);
+ builder.append(", maxConnLifetimeMillis=");
+ builder.append(maxConnLifetimeMillis);
+ builder.append(", validatingSet=");
+ builder.append(validatingSet);
+ builder.append(", pcMap=");
+ builder.append(pcMap);
+ builder.append("]");
+ return builder.toString();
+ }
}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSource.java b/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSource.java
index 444ec1d..a0fe1b4 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSource.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/datasources/InstanceKeyDataSource.java
@@ -1053,4 +1053,79 @@ public abstract class InstanceKeyDataSource implements DataSource, Referenceable
}
return cpds;
}
+
+ /**
+ * @since 2.6.0
+ */
+ @Override
+ public synchronized String toString() {
+ final StringBuilder builder = new StringBuilder(super.toString());
+ builder.append("[");
+ toStringFields(builder);
+ builder.append("]");
+ return builder.toString();
+ }
+
+ protected void toStringFields(final StringBuilder builder) {
+ builder.append("getConnectionCalled=");
+ builder.append(getConnectionCalled);
+ builder.append(", dataSource=");
+ builder.append(dataSource);
+ builder.append(", dataSourceName=");
+ builder.append(dataSourceName);
+ builder.append(", description=");
+ builder.append(description);
+ builder.append(", jndiEnvironment=");
+ builder.append(jndiEnvironment);
+ builder.append(", loginTimeout=");
+ builder.append(loginTimeout);
+ builder.append(", logWriter=");
+ builder.append(logWriter);
+ builder.append(", instanceKey=");
+ builder.append(instanceKey);
+ builder.append(", defaultBlockWhenExhausted=");
+ builder.append(defaultBlockWhenExhausted);
+ builder.append(", defaultEvictionPolicyClassName=");
+ builder.append(defaultEvictionPolicyClassName);
+ builder.append(", defaultLifo=");
+ builder.append(defaultLifo);
+ builder.append(", defaultMaxIdle=");
+ builder.append(defaultMaxIdle);
+ builder.append(", defaultMaxTotal=");
+ builder.append(defaultMaxTotal);
+ builder.append(", defaultMaxWaitMillis=");
+ builder.append(defaultMaxWaitMillis);
+ builder.append(", defaultMinEvictableIdleTimeMillis=");
+ builder.append(defaultMinEvictableIdleTimeMillis);
+ builder.append(", defaultMinIdle=");
+ builder.append(defaultMinIdle);
+ builder.append(", defaultNumTestsPerEvictionRun=");
+ builder.append(defaultNumTestsPerEvictionRun);
+ builder.append(", defaultSoftMinEvictableIdleTimeMillis=");
+ builder.append(defaultSoftMinEvictableIdleTimeMillis);
+ builder.append(", defaultTestOnCreate=");
+ builder.append(defaultTestOnCreate);
+ builder.append(", defaultTestOnBorrow=");
+ builder.append(defaultTestOnBorrow);
+ builder.append(", defaultTestOnReturn=");
+ builder.append(defaultTestOnReturn);
+ builder.append(", defaultTestWhileIdle=");
+ builder.append(defaultTestWhileIdle);
+ builder.append(", defaultTimeBetweenEvictionRunsMillis=");
+ builder.append(defaultTimeBetweenEvictionRunsMillis);
+ builder.append(", validationQuery=");
+ builder.append(validationQuery);
+ builder.append(", validationQueryTimeoutSeconds=");
+ builder.append(validationQueryTimeoutSeconds);
+ builder.append(", rollbackAfterValidation=");
+ builder.append(rollbackAfterValidation);
+ builder.append(", maxConnLifetimeMillis=");
+ builder.append(maxConnLifetimeMillis);
+ builder.append(", defaultAutoCommit=");
+ builder.append(defaultAutoCommit);
+ builder.append(", defaultTransactionIsolation=");
+ builder.append(defaultTransactionIsolation);
+ builder.append(", defaultReadOnly=");
+ builder.append(defaultReadOnly);
+ }
}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/datasources/SharedPoolDataSource.java b/java/org/apache/tomcat/dbcp/dbcp2/datasources/SharedPoolDataSource.java
index 40d3851..02188c5 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/datasources/SharedPoolDataSource.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/datasources/SharedPoolDataSource.java
@@ -235,4 +235,11 @@ public class SharedPoolDataSource extends InstanceKeyDataSource {
throw new IOException("NamingException: " + e);
}
}
+
+ @Override
+ protected void toStringFields(final StringBuilder builder) {
+ super.toStringFields(builder);
+ builder.append(", maxTotal=");
+ builder.append(maxTotal);
+ }
}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/datasources/UserPassKey.java b/java/org/apache/tomcat/dbcp/dbcp2/datasources/UserPassKey.java
index 4bcf4ab..e357028 100644
--- a/java/org/apache/tomcat/dbcp/dbcp2/datasources/UserPassKey.java
+++ b/java/org/apache/tomcat/dbcp/dbcp2/datasources/UserPassKey.java
@@ -125,9 +125,10 @@ class UserPassKey implements Serializable {
@Override
public String toString() {
- final StringBuffer sb = new StringBuffer(50);
- sb.append("UserPassKey(");
- sb.append(userName).append(", ").append(userPassword).append(')');
+ final StringBuffer sb = new StringBuffer(super.toString());
+ sb.append("[");
+ sb.append(userName);
+ sb.append(']');
return sb.toString();
}
}
diff --git a/java/org/apache/tomcat/dbcp/dbcp2/overview.html b/java/org/apache/tomcat/dbcp/dbcp2/overview.html
deleted file mode 100644
index f15a5e1..0000000
--- a/java/org/apache/tomcat/dbcp/dbcp2/overview.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!--
- 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.
--->
-<html>
- <head>
- <title>Overview of the org.apache.commons.dbcp component</title>
- </head>
- <body>
- <p>
- Commons Database Connection Pooling
- </p>
- </body>
-</html>
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index fff45a8..37addb6 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -126,6 +126,11 @@
When using the <code>OneLineFormatter</code>, don't print a blank line
in the log after printing a stack trace. (markt)
</fix>
+ <update>
+ Update the internal fork of Apache Commons DBCP 2 to dcdbc72
+ (2019-04-24) to pick up some clean-up and enhancements less the JDBC 4.2
+ related changes that require Java 8. (markt)
+ </update>
</changelog>
</subsection>
</section>
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org