http://git-wip-us.apache.org/repos/asf/commons-dbcp/blob/6c97f898/src/main/java/org/apache/commons/dbcp2/BasicDataSource.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/dbcp2/BasicDataSource.java b/src/main/java/org/apache/commons/dbcp2/BasicDataSource.java index 84ce723..a944da3 100644 --- a/src/main/java/org/apache/commons/dbcp2/BasicDataSource.java +++ b/src/main/java/org/apache/commons/dbcp2/BasicDataSource.java @@ -63,8 +63,21 @@ import org.apache.commons.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,1293 +131,1227 @@ 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_TRANSACTION_ISOLATION; + 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.commons.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); + @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(); } /** - * 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; - - /** - * 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. - */ - private volatile String password; - - /** - * Returns the password passed to the JDBC driver to establish connections. + * 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 the connection password + * @return Whether or not connections being returned to the pool will be checked and configured with auto-commit. + * @deprecated Use {@link #getAutoCommitOnReturn()}. */ - @Override - public String getPassword() { - return this.password; + @Deprecated + public boolean getEnableAutoCommitOnReturn() { + return autoCommitOnReturn; } /** - * <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> + * Gets the EvictionPolicy implementation in use with this connection pool. * - * @param password - * new value for the password + * @return The EvictionPolicy implementation in use with this connection pool. */ - public void setPassword(final String password) { - this.password = password; + public synchronized String getEvictionPolicyClassName() { + return evictionPolicyClassName; } /** - * The connection URL to be passed to our JDBC driver to establish a connection. - */ - private String url; - - /** - * Returns the JDBC connection {@link #url} property. + * True means that validation will fail immediately for connections that have previously thrown SQLExceptions with + * SQL_STATE indicating fatal disconnection errors. * - * @return the {@link #url} passed to the JDBC driver to establish connections + * @return true if connections created by this datasource will fast fail validation. + * @see #setDisconnectionSqlCodes(Collection) + * @since 2.1 */ @Override - public synchronized String getUrl() { - return this.url; + public boolean getFastFailValidation() { + return fastFailValidation; } /** - * <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> + * Returns the initial size of the connection pool. * - * @param url - * the new value for the JDBC connection url + * @return the number of connections created when the pool is initialized */ - public synchronized void setUrl(final String url) { - this.url = url; + @Override + public synchronized int getInitialSize() { + return this.initialSize; } /** - * The connection user name 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 userName; + public String getJmxName() { + return jmxName; + } /** - * Returns the JDBC connection {@link #userName} property. + * Returns the LIFO property. * - * @return the {@link #userName} passed to the JDBC driver to establish connections + * @return true if connection pool behaves as a LIFO queue. */ @Override - public String getUsername() { - return this.userName; + public synchronized boolean getLifo() { + return this.lifo; } /** * <p> - * Sets the {@link #userName}. + * 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 userName - * the new value for the JDBC connection user name */ - public void setUsername(final String userName) { - this.userName = userName; + @Override + public boolean getLogAbandoned() { + if (abandonedConfig != null) { + return abandonedConfig.getLogAbandoned(); + } + return false; } /** - * 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. - */ - private volatile String validationQuery; - - /** - * Returns the validation query used to validate connections before returning them. + * 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 SQL validation query - * @see #validationQuery + * @since 2.1 */ @Override - public String getValidationQuery() { - return this.validationQuery; + public boolean getLogExpiredConnections() { + return logExpiredConnections; } /** + * <strong>BasicDataSource does NOT support this method.</strong> + * * <p> - * Sets the {@link #validationQuery}. + * 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 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; - } - } - - /** - * Timeout in seconds before connection validation queries fail. - */ - private volatile int validationQueryTimeoutSeconds = -1; - - /** - * Returns the validation query timeout. - * - * @return the timeout in seconds before connection validation queries fail. + * @throws SQLException + * if a database access error occurs + * @throws UnsupportedOperationException + * If the DataSource implementation does not support the login timeout feature. + * @return login timeout in seconds */ @Override - public int getValidationQueryTimeout() { - return validationQueryTimeoutSeconds; + public int getLoginTimeout() throws SQLException { + // This method isn't supported by the PoolingDataSource returned by the createDataSource + throw new UnsupportedOperationException("Not supported by BasicDataSource"); } /** - * 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 log writer being used by this data source. * </p> - * - * @param validationQueryTimeoutSeconds - * new validation query timeout value in seconds - */ - public void setValidationQueryTimeout(final int validationQueryTimeoutSeconds) { - this.validationQueryTimeoutSeconds = validationQueryTimeoutSeconds; - } - - /** - * 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. + * Calls {@link #createDataSource()}, so has the side effect of initializing the connection pool. * </p> - */ - private volatile List<String> connectionInitSqls; - - /** - * 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. * - * @return initialization SQL statements + * @throws SQLException + * if a database access error occurs + * @return log writer in use */ - public List<String> getConnectionInitSqls() { - final List<String> result = connectionInitSqls; - if (result == null) { - return Collections.emptyList(); - } - return result; + @Override + public PrintWriter getLogWriter() throws SQLException { + return createDataSource().getLogWriter(); } /** - * Provides the same data as {@link #getConnectionInitSqls()} but in an array so it is accessible via JMX. + * Returns the maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an + * infinite lifetime. */ @Override - public String[] getConnectionInitSqlsAsArray() { - final Collection<String> result = getConnectionInitSqls(); - return result.toArray(new String[result.size()]); + public long getMaxConnLifetimeMillis() { + return maxConnLifetimeMillis; } /** - * 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> + * 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> + * A negative value indicates that there is no limit * </p> * - * @param connectionInitSqls - * Collection of SQL statements to execute on connection creation + * @return the maximum number of idle 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 synchronized int getMaxIdle() { + return this.maxIdle; } /** - * Controls access to the underlying connection. - */ - private boolean accessToUnderlyingConnectionAllowed = false; - - /** - * Returns the value of the accessToUnderlyingConnectionAllowed property. + * Gets the value of the <code>maxOpenPreparedStatements</code> property. * - * @return true if access to the underlying connection is allowed, false otherwise. + * @return the maximum number of open statements */ @Override - public synchronized boolean isAccessToUnderlyingConnectionAllowed() { - return this.accessToUnderlyingConnectionAllowed; + public synchronized int getMaxOpenPreparedStatements() { + return this.maxOpenPreparedStatements; } /** * <p> - * Sets the value of the accessToUnderlyingConnectionAllowed property. It controls if the PoolGuard allows access to - * the underlying connection. (Default: false) + * Returns the maximum number of active connections that can be allocated at the same time. * </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 number means that there is no limit. * </p> * - * @param allow - * Access to the underlying connection is granted when true. + * @return the maximum number of active connections */ - public synchronized void setAccessToUnderlyingConnectionAllowed(final boolean allow) { - this.accessToUnderlyingConnectionAllowed = allow; + @Override + public synchronized int getMaxTotal() { + return this.maxTotal; } - private long maxConnLifetimeMillis = -1; - /** - * Returns the maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an - * infinite lifetime. + * 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 long getMaxConnLifetimeMillis() { - return maxConnLifetimeMillis; + public synchronized long getMaxWaitMillis() { + return this.maxWaitMillis; } - private boolean logExpiredConnections = true; - /** - * 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. + * Returns the {@link #minEvictableIdleTimeMillis} property. * - * @since 2.1 + * @return the value of the {@link #minEvictableIdleTimeMillis} property + * @see #minEvictableIdleTimeMillis */ @Override - public boolean getLogExpiredConnections() { - return logExpiredConnections; + public synchronized long getMinEvictableIdleTimeMillis() { + return this.minEvictableIdleTimeMillis; } /** - * <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> + * 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. * - * @param maxConnLifetimeMillis - * The maximum permitted lifetime of a connection in milliseconds. + * @return the minimum number of idle connections + * @see GenericObjectPool#getMinIdle() */ - public void setMaxConnLifetimeMillis(final long maxConnLifetimeMillis) { - this.maxConnLifetimeMillis = maxConnLifetimeMillis; + @Override + public synchronized int getMinIdle() { + return this.minIdle; } /** - * 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. + * [Read Only] The current number of active connections that have been allocated from this data source. * - * @param logExpiredConnections - * Whether or not log messages are generated when the pool closes connections due to maximum lifetime - * exceeded. + * @return the current number of active connections */ - public void setLogExpiredConnections(final boolean logExpiredConnections) { - this.logExpiredConnections = logExpiredConnections; + @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; } - private String jmxName; + /** + * [Read Only] The current number of idle connections that are waiting to be allocated from this data source. + * + * @return the current number of idle connections + */ + @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; + } /** - * Returns the JMX name that has been requested for this DataSource. If the requested name is not valid, an - * alternative may be chosen. + * Returns the value of the {@link #numTestsPerEvictionRun} property. * - * @return The JMX name that has been requested for this DataSource. + * @return the number of objects to examine during idle object evictor runs + * @see #numTestsPerEvictionRun */ - public String getJmxName() { - return jmxName; + @Override + public synchronized int getNumTestsPerEvictionRun() { + return this.numTestsPerEvictionRun; + } + + @Override + public Logger getParentLogger() throws SQLFeatureNotSupportedException { + throw new SQLFeatureNotSupportedException(); } /** - * 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. + * Returns the password passed to the JDBC driver to establish connections. * - * @param jmxName - * The JMX name that has been requested for this DataSource + * @return the connection password */ - public void setJmxName(final String jmxName) { - this.jmxName = jmxName; + @Override + public String getPassword() { + return this.password; } - private boolean enableAutoCommitOnReturn = true; + protected ObjectName getRegisteredJmxName() { + return ObjectNameWrapper.unwrap(registeredJmxObjectName); + } /** - * 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 commi
<TRUNCATED>