/* | |
* 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.commons.dbcp2; | |
import java.io.OutputStreamWriter; | |
import java.io.PrintWriter; | |
import java.nio.charset.StandardCharsets; | |
import java.security.AccessController; | |
import java.security.PrivilegedActionException; | |
import java.security.PrivilegedExceptionAction; | |
import java.sql.Connection; | |
import java.sql.Driver; | |
import java.sql.DriverManager; | |
import java.sql.SQLException; | |
import java.sql.SQLFeatureNotSupportedException; | |
import java.util.ArrayList; | |
import java.util.Collection; | |
import java.util.Collections; | |
import java.util.HashSet; | |
import java.util.List; | |
import java.util.Objects; | |
import java.util.Properties; | |
import java.util.Set; | |
import java.util.logging.Logger; | |
import javax.management.MBeanRegistration; | |
import javax.management.MBeanServer; | |
import javax.management.MalformedObjectNameException; | |
import javax.management.ObjectName; | |
import javax.sql.DataSource; | |
import org.apache.commons.logging.Log; | |
import org.apache.commons.logging.LogFactory; | |
import org.apache.commons.pool2.PooledObject; | |
import org.apache.commons.pool2.impl.AbandonedConfig; | |
import org.apache.commons.pool2.impl.BaseObjectPoolConfig; | |
import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig; | |
import org.apache.commons.pool2.impl.GenericObjectPool; | |
import org.apache.commons.pool2.impl.GenericObjectPoolConfig; | |
/** | |
* <p> | |
* Basic implementation of <code>javax.sql.DataSource</code> that is configured via JavaBeans properties. This is not | |
* the only way to combine the <em>commons-dbcp2</em> and <em>commons-pool2</em> packages, but provides a "one stop | |
* shopping" solution for basic requirements. | |
* </p> | |
* | |
* @since 2.0 | |
*/ | |
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(); | |
try { | |
// Load classes now to prevent AccessControlExceptions later | |
// A number of classes are loaded when getConnection() is called | |
// but the following classes are not loaded and therefore require | |
// explicit loading. | |
if (Utils.IS_SECURITY_ENABLED) { | |
final ClassLoader loader = BasicDataSource.class.getClassLoader(); | |
final String dbcpPackageName = BasicDataSource.class.getPackage().getName(); | |
loader.loadClass(dbcpPackageName + ".BasicDataSource$PaGetConnection"); | |
loader.loadClass(dbcpPackageName + ".DelegatingCallableStatement"); | |
loader.loadClass(dbcpPackageName + ".DelegatingDatabaseMetaData"); | |
loader.loadClass(dbcpPackageName + ".DelegatingPreparedStatement"); | |
loader.loadClass(dbcpPackageName + ".DelegatingResultSet"); | |
loader.loadClass(dbcpPackageName + ".PoolableCallableStatement"); | |
loader.loadClass(dbcpPackageName + ".PoolablePreparedStatement"); | |
loader.loadClass(dbcpPackageName + ".PoolingConnection$StatementType"); | |
loader.loadClass(dbcpPackageName + ".PStmtKey"); | |
final String poolPackageName = PooledObject.class.getPackage().getName(); | |
loader.loadClass(poolPackageName + ".impl.LinkedBlockingDeque$Node"); | |
loader.loadClass(poolPackageName + ".impl.GenericKeyedObjectPool$ObjectDeque"); | |
} | |
} catch (final ClassNotFoundException cnfe) { | |
throw new IllegalStateException("Unable to pre-load classes", cnfe); | |
} | |
} | |
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. | |
*/ | |
private volatile Boolean defaultAutoCommit; | |
/** | |
* The default read-only state of connections created by this pool. | |
*/ | |
private transient Boolean defaultReadOnly; | |
/** | |
* The default TransactionIsolation state of connections created by this pool. | |
*/ | |
private volatile int defaultTransactionIsolation = PoolableConnectionFactory.UNKNOWN_TRANSACTION_ISOLATION; | |
private Integer defaultQueryTimeoutSeconds; | |
/** | |
* The default "catalog" of connections created by this pool. | |
*/ | |
private volatile String defaultCatalog; | |
/** | |
* The default "schema" of connections created by this pool. | |
*/ | |
private volatile String defaultSchema; | |
/** | |
* The property that controls if the pooled connections cache some state rather than query the database for current | |
* state to improve performance. | |
*/ | |
private boolean cacheState = true; | |
/** | |
* The instance of the JDBC Driver to use. | |
*/ | |
private Driver driver; | |
/** | |
* The fully qualified Java class name of the JDBC driver to be used. | |
*/ | |
private String driverClassName; | |
/** | |
* 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. | |
*/ | |
private ClassLoader driverClassLoader; | |
/** | |
* 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; | |
/** | |
* The maximum number of active connections that can be allocated from this pool at the same time, or negative for | |
* no limit. | |
*/ | |
private int maxTotal = GenericObjectPoolConfig.DEFAULT_MAX_TOTAL; | |
/** | |
* 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. | |
*/ | |
private int maxIdle = GenericObjectPoolConfig.DEFAULT_MAX_IDLE; | |
/** | |
* 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; | |
/** | |
* The initial number of connections that are created when the pool is started. | |
*/ | |
private int initialSize = 0; | |
/** | |
* 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; | |
/** | |
* 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; | |
/** | |
* <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. | |
* </p> | |
*/ | |
private int maxOpenPreparedStatements = GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL; | |
/** | |
* 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; | |
/** | |
* 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; | |
/** | |
* The indication of whether objects will be validated before being returned to the pool. | |
*/ | |
private boolean testOnReturn = 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. | |
*/ | |
private long timeBetweenEvictionRunsMillis = BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS; | |
/** | |
* 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; | |
/** | |
* The minimum amount of time an object may sit idle in the pool before it is eligible for eviction by the idle | |
* object evictor (if any). | |
*/ | |
private long minEvictableIdleTimeMillis = BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS; | |
/** | |
* 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()}. | |
*/ | |
private long softMinEvictableIdleTimeMillis = BaseObjectPoolConfig.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS; | |
private String evictionPolicyClassName = BaseObjectPoolConfig.DEFAULT_EVICTION_POLICY_CLASS_NAME; | |
/** | |
* 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; | |
/** | |
* The connection password to be passed to our JDBC driver to establish a connection. | |
*/ | |
private volatile String password; | |
/** | |
* The connection URL to be passed to our JDBC driver to establish a connection. | |
*/ | |
private String url; | |
/** | |
* The connection user name to be passed to our JDBC driver to establish a connection. | |
*/ | |
private String userName; | |
/** | |
* 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; | |
/** | |
* Timeout in seconds before connection validation queries fail. | |
*/ | |
private volatile int validationQueryTimeoutSeconds = -1; | |
/** | |
* The fully qualified Java class name of a {@link ConnectionFactory} implementation. | |
*/ | |
private String connectionFactoryClassName; | |
/** | |
* 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> | |
*/ | |
private volatile List<String> connectionInitSqls; | |
/** | |
* Controls access to the underlying connection. | |
*/ | |
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; | |
/** | |
* The object pool that internally manages our connections. | |
*/ | |
private volatile GenericObjectPool<PoolableConnection> connectionPool; | |
/** | |
* 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(); | |
/** | |
* 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)); | |
private AbandonedConfig abandonedConfig; | |
private boolean closed; | |
/** | |
* Actual name under which this component has been registered. | |
*/ | |
private ObjectNameWrapper registeredJmxObjectName; | |
/** | |
* 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 | |
*/ | |
public void addConnectionProperty(final String name, final String value) { | |
connectionProperties.put(name, value); | |
} | |
/** | |
* <p> | |
* Closes and releases all idle connections that are currently stored in the connection pool associated with this | |
* data source. | |
* </p> | |
* <p> | |
* Connections that are checked out to clients when this method is invoked are not affected. When client | |
* applications subsequently invoke {@link Connection#close()} to return these connections to the pool, the | |
* 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> | |
* | |
* @throws SQLException | |
* if an error occurs closing idle connections | |
*/ | |
@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); | |
} | |
} | |
/** | |
* Closes the connection pool, silently swallowing any exception that occurs. | |
*/ | |
private void closeConnectionPool() { | |
final GenericObjectPool<?> oldPool = connectionPool; | |
connectionPool = null; | |
try { | |
if (oldPool != null) { | |
oldPool.close(); | |
} | |
} catch (final Exception e) { | |
/* Ignore */ | |
} | |
} | |
/** | |
* 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 A new connection factory. | |
* | |
* @throws SQLException | |
* If the connection factort cannot be created | |
*/ | |
protected ConnectionFactory createConnectionFactory() throws SQLException { | |
// Load the JDBC driver class | |
Driver driverToUse = this.driver; | |
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); | |
} | |
} | |
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); | |
} | |
} | |
// 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'"); | |
} | |
final String pwd = password; | |
if (pwd != null) { | |
connectionProperties.put("password", pwd); | |
} else { | |
log("DBCP DataSource configured without a 'password'"); | |
} | |
return createConnectionFactory(driverToUse); | |
} | |
/** | |
* 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. | |
* </p> | |
* | |
* @param factory | |
* The factory to use to create new connections for this pool. | |
*/ | |
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> | |
* Creates (if necessary) and return the internal data source we are using to manage our connections. | |
* </p> | |
* | |
* @return The current internal DataSource or a newly created instance if it has not yet been created. | |
* @throws SQLException | |
* if the object pool cannot be created. | |
*/ | |
protected DataSource createDataSource() throws SQLException { | |
if (closed) { | |
throw new SQLException("Data source is closed"); | |
} | |
// 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; | |
} | |
jmxRegister(); | |
// create factory which returns raw physical connections | |
final ConnectionFactory driverConnectionFactory = createConnectionFactory(); | |
// 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; | |
} | |
} | |
/** | |
* 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 | |
* | |
* @return A new DataSource instance | |
*/ | |
protected DataSource createDataSourceInstance() throws SQLException { | |
final PoolingDataSource<PoolableConnection> pds = new PoolingDataSource<>(connectionPool); | |
pds.setAccessToUnderlyingConnectionAllowed(isAccessToUnderlyingConnectionAllowed()); | |
return pds; | |
} | |
/** | |
* Creates an object pool used to provide pooling support for {@link Connection JDBC connections}. | |
* | |
* @param factory | |
* the object factory | |
* @param poolConfig | |
* the object pool configuration | |
* @param abandonedConfig | |
* the abandoned objects configuration | |
* @return a non-null instance | |
*/ | |
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; | |
} | |
/** | |
* 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 | |
*/ | |
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; | |
} | |
/** | |
* Gets the print writer used by this configuration to log information on abandoned objects. | |
* | |
* @return The print writer used by this configuration to log information on abandoned objects. | |
*/ | |
public PrintWriter getAbandonedLogWriter() { | |
if (abandonedConfig != null) { | |
return abandonedConfig.getLogWriter(); | |
} | |
return null; | |
} | |
/** | |
* 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? | |
* | |
* @return <code>true</code> if usage tracking is enabled | |
*/ | |
@Override | |
public boolean getAbandonedUsageTracking() { | |
if (abandonedConfig != null) { | |
return abandonedConfig.getUseUsageTracking(); | |
} | |
return false; | |
} | |
/** | |
* 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. | |
*/ | |
public boolean getAutoCommitOnReturn() { | |
return autoCommitOnReturn; | |
} | |
/** | |
* Returns the state caching flag. | |
* | |
* @return the state caching flag | |
*/ | |
@Override | |
public boolean getCacheState() { | |
return cacheState; | |
} | |
/** | |
* Creates (if necessary) and return a connection to the database. | |
* | |
* @throws SQLException | |
* if a database access error occurs | |
* @return a database connection | |
*/ | |
@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(); | |
} | |
/** | |
* <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 | |
* | |
* @throws UnsupportedOperationException | |
* always thrown. | |
* @throws SQLException | |
* if a database access error occurs | |
* @return nothing - always throws UnsupportedOperationException | |
*/ | |
@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"); | |
} | |
/** | |
* 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 | |
*/ | |
public List<String> getConnectionInitSqls() { | |
final List<String> result = connectionInitSqls; | |
if (result == null) { | |
return Collections.emptyList(); | |
} | |
return result; | |
} | |
/** | |
* Provides the same data as {@link #getConnectionInitSqls()} but in an array so it is accessible via JMX. | |
*/ | |
@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 default auto-commit property. | |
* | |
* @return true if default auto-commit is enabled | |
*/ | |
@Override | |
public Boolean getDefaultAutoCommit() { | |
return defaultAutoCommit; | |
} | |
/** | |
* Returns the default catalog. | |
* | |
* @return the default catalog | |
*/ | |
@Override | |
public String getDefaultCatalog() { | |
return this.defaultCatalog; | |
} | |
/** | |
* 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. | |
*/ | |
public Integer getDefaultQueryTimeout() { | |
return defaultQueryTimeoutSeconds; | |
} | |
/** | |
* Returns the default readOnly property. | |
* | |
* @return true if connections are readOnly by default | |
*/ | |
@Override | |
public Boolean getDefaultReadOnly() { | |
return defaultReadOnly; | |
} | |
/** | |
* Returns the default schema. | |
* | |
* @return the default schema. | |
* @since 2.5.0 | |
*/ | |
@Override | |
public String getDefaultSchema() { | |
return this.defaultSchema; | |
} | |
/** | |
* Returns the default transaction isolation state of returned connections. | |
* | |
* @return the default value for transaction isolation state | |
* @see Connection#getTransactionIsolation | |
*/ | |
@Override | |
public int getDefaultTransactionIsolation() { | |
return this.defaultTransactionIsolation; | |
} | |
/** | |
* Returns the set of SQL_STATE codes considered to signal fatal conditions. | |
* | |
* @return fatal disconnection state codes | |
* @see #setDisconnectionSqlCodes(Collection) | |
* @since 2.1 | |
*/ | |
public Set<String> getDisconnectionSqlCodes() { | |
final Set<String> result = disconnectionSqlCodes; | |
if (result == null) { | |
return Collections.emptySet(); | |
} | |
return result; | |
} | |
/** | |
* Provides the same data as {@link #getDisconnectionSqlCodes} but in an array so it is accessible via JMX. | |
* | |
* @since 2.1 | |
*/ | |
@Override | |
public String[] getDisconnectionSqlCodesAsArray() { | |
final Collection<String> result = getDisconnectionSqlCodes(); | |
return result.toArray(new String[result.size()]); | |
} | |
/** | |
* 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 | |
*/ | |
public synchronized Driver getDriver() { | |
return driver; | |
} | |
/** | |
* 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. | |
*/ | |
public synchronized ClassLoader getDriverClassLoader() { | |
return this.driverClassLoader; | |
} | |
/** | |
* 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 | |
*/ | |
@Override | |
public synchronized String getDriverClassName() { | |
return this.driverClassName; | |
} | |
/** | |
* Returns the ConnectionFactoryClassName that has been configured for use by this pool. | |
* <p> | |
* Note: This getter only returns the last value set by a call to | |
* {@link #setConnectionFactoryClassName(String)}. | |
* </p> | |
* | |
* @return the ConnectionFactoryClassName that has been configured for use by this pool. | |
* @since 2.7.0 | |
*/ | |
public String getConnectionFactoryClassName() { | |
return this.connectionFactoryClassName; | |
} | |
/** | |
* 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()}. | |
*/ | |
@Deprecated | |
public boolean getEnableAutoCommitOnReturn() { | |
return autoCommitOnReturn; | |
} | |
/** | |
* Gets the EvictionPolicy implementation in use with this connection pool. | |
* | |
* @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 boolean getFastFailValidation() { | |
return fastFailValidation; | |
} | |
/** | |
* Returns the initial size of the connection pool. | |
* | |
* @return the number of connections created when the pool is initialized | |
*/ | |
@Override | |
public synchronized int getInitialSize() { | |
return this.initialSize; | |
} | |
/** | |
* 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. | |
*/ | |
public String getJmxName() { | |
return jmxName; | |
} | |
/** | |
* Returns the LIFO property. | |
* | |
* @return true if connection pool behaves as a LIFO queue. | |
*/ | |
@Override | |
public synchronized boolean getLifo() { | |
return this.lifo; | |
} | |
/** | |
* <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; | |
} | |
/** | |
* 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. | |
* | |
* @since 2.1 | |
*/ | |
@Override | |
public boolean getLogExpiredConnections() { | |
return logExpiredConnections; | |
} | |
/** | |
* <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> | |
* | |
* @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 getLoginTimeout() throws SQLException { | |
// This method isn't supported by the PoolingDataSource returned by the createDataSource | |
throw new UnsupportedOperationException("Not supported by BasicDataSource"); | |
} | |
/** | |
* <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 | |
*/ | |
@Override | |
public PrintWriter getLogWriter() throws SQLException { | |
return createDataSource().getLogWriter(); | |
} | |
/** | |
* Returns the maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an | |
* infinite lifetime. | |
*/ | |
@Override | |
public long getMaxConnLifetimeMillis() { | |
return maxConnLifetimeMillis; | |
} | |
/** | |
* <p> | |
* 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> | |
* | |
* @return the maximum number of idle connections | |
*/ | |
@Override | |
public synchronized int getMaxIdle() { | |
return this.maxIdle; | |
} | |
/** | |
* Gets the value of the <code>maxOpenPreparedStatements</code> property. | |
* | |
* @return the maximum number of open statements | |
*/ | |
@Override | |
public synchronized int getMaxOpenPreparedStatements() { | |
return this.maxOpenPreparedStatements; | |
} | |
/** | |
* <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 | |
*/ | |
@Override | |
public synchronized int getMaxTotal() { | |
return this.maxTotal; | |
} | |
/** | |
* 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; | |
} | |
/** | |
* Returns the {@link #minEvictableIdleTimeMillis} property. | |
* | |
* @return the value of the {@link #minEvictableIdleTimeMillis} property | |
* @see #minEvictableIdleTimeMillis | |
*/ | |
@Override | |
public synchronized long getMinEvictableIdleTimeMillis() { | |
return this.minEvictableIdleTimeMillis; | |
} | |
/** | |
* 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; | |
} | |
/** | |
* [Read Only] The current number of active connections that have been allocated from this data source. | |
* | |
* @return the current number of active connections | |
*/ | |
@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; | |
} | |
/** | |
* [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 value of the {@link #numTestsPerEvictionRun} property. | |
* | |
* @return the number of objects to examine during idle object evictor runs | |
* @see #numTestsPerEvictionRun | |
*/ | |
@Override | |
public synchronized int getNumTestsPerEvictionRun() { | |
return this.numTestsPerEvictionRun; | |
} | |
@Override | |
public Logger getParentLogger() throws SQLFeatureNotSupportedException { | |
throw new SQLFeatureNotSupportedException(); | |
} | |
/** | |
* Returns the password passed to the JDBC driver to establish connections. | |
* | |
* @return the connection password | |
*/ | |
@Override | |
public String getPassword() { | |
return this.password; | |
} | |
protected ObjectName getRegisteredJmxName() { | |
return ObjectNameWrapper.unwrap(registeredJmxObjectName); | |
} | |
/** | |
* <p> | |
* Flag to remove abandoned connections if they exceed the removeAbandonedTimeout when borrowObject is invoked. | |
* </p> | |
* <p> | |
* The default value is false. | |
* </p> | |
* <p> | |
* If set to true a connection is considered abandoned and eligible for removal if it has not been used for more | |
* than {@link #getRemoveAbandonedTimeout() removeAbandonedTimeout} seconds. | |
* </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; | |
} | |
/** | |
* <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; | |
} | |
/** | |
* <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; | |
} | |
/** | |
* 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 whether a connection will be rolled back when it is returned to the pool. | |
*/ | |
public boolean getRollbackOnReturn() { | |
return rollbackOnReturn; | |
} | |
/** | |
* <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> | |
* | |
* @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 | |
*/ | |
@Override | |
public synchronized long getSoftMinEvictableIdleTimeMillis() { | |
return softMinEvictableIdleTimeMillis; | |
} | |
/** | |
* Returns the {@link #testOnBorrow} property. | |
* | |
* @return true if objects are validated before being borrowed from the pool | |
* | |
* @see #testOnBorrow | |
*/ | |
@Override | |
public synchronized boolean getTestOnBorrow() { | |
return this.testOnBorrow; | |
} | |
/** | |
* 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; | |
} | |
/** | |
* Returns the value of the {@link #testOnReturn} property. | |
* | |
* @return true if objects are validated before being returned to the pool | |
* @see #testOnReturn | |
*/ | |
public synchronized boolean getTestOnReturn() { | |
return this.testOnReturn; | |
} | |
/** | |
* Returns the value of the {@link #testWhileIdle} property. | |
* | |
* @return true if objects examined by the idle object evictor are validated | |
* @see #testWhileIdle | |
*/ | |
@Override | |
public synchronized boolean getTestWhileIdle() { | |
return this.testWhileIdle; | |
} | |
/** | |
* Returns the value of the {@link #timeBetweenEvictionRunsMillis} property. | |
* | |
* @return the time (in milliseconds) between evictor runs | |
* @see #timeBetweenEvictionRunsMillis | |
*/ | |
@Override | |
public synchronized long getTimeBetweenEvictionRunsMillis() { | |
return this.timeBetweenEvictionRunsMillis; | |
} | |
/** | |
* Returns the JDBC connection {@link #url} property. | |
* | |
* @return the {@link #url} passed to the JDBC driver to establish connections | |
*/ | |
@Override | |
public synchronized String getUrl() { | |
return this.url; | |
} | |
/** | |
* Returns the JDBC connection {@link #userName} property. | |
* | |
* @return the {@link #userName} passed to the JDBC driver to establish connections | |
*/ | |
@Override | |
public String getUsername() { | |
return this.userName; | |
} | |
/** | |
* Returns the validation query used to validate connections before returning them. | |
* | |
* @return the SQL validation query | |
* @see #validationQuery | |
*/ | |
@Override | |
public String getValidationQuery() { | |
return this.validationQuery; | |
} | |
/** | |
* Returns the validation query timeout. | |
* | |
* @return the timeout in seconds before connection validation queries fail. | |
*/ | |
@Override | |
public int getValidationQueryTimeout() { | |
return validationQueryTimeoutSeconds; | |
} | |
/** | |
* 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 | |
*/ | |
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."); | |
} | |
} 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); | |
} | |
} | |
/** | |
* Manually evicts idle connections. | |
* | |
* @throws Exception Thrown by {@link GenericObjectPool#evict()}. | |
* @see GenericObjectPool#evict() | |
*/ | |
public void evict() throws Exception { | |
if (connectionPool != null) { | |
connectionPool.evict(); | |
} | |
} | |
/** | |
* Returns the value of the accessToUnderlyingConnectionAllowed property. | |
* | |
* @return true if access to the underlying connection is allowed, false otherwise. | |
*/ | |
@Override | |
public synchronized boolean isAccessToUnderlyingConnectionAllowed() { | |
return this.accessToUnderlyingConnectionAllowed; | |
} | |
/** | |
* If true, this data source is closed and no more connections can be retrieved from this datasource. | |
* | |
* @return true, if the data source is closed; false otherwise | |
*/ | |
@Override | |
public synchronized boolean isClosed() { | |
return closed; | |
} | |
/** | |
* Delegates in a null-safe manner to {@link String#isEmpty()}. | |
* | |
* @param value the string to test, may be null. | |
* @return boolean false if value is null, otherwise {@link String#isEmpty()}. | |
*/ | |
private boolean isEmpty(String value) { | |
return value == null ? true : value.trim().isEmpty(); | |
} | |
/** | |
* Returns true if we are pooling statements. | |
* | |
* @return true if prepared and callable statements are pooled | |
*/ | |
@Override | |
public synchronized boolean isPoolPreparedStatements() { | |
return this.poolPreparedStatements; | |
} | |
@Override | |
public boolean isWrapperFor(final Class<?> iface) throws SQLException { | |
return false; | |
} | |
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."); | |
} | |
} | |
protected void log(final String message) { | |
if (logWriter != null) { | |
logWriter.println(message); | |
} | |
} | |
@Override | |
public void postDeregister() { | |
// NO-OP | |
} | |
@Override | |
public void postRegister(final Boolean registrationDone) { | |
// NO-OP | |
} | |
@Override | |
public void preDeregister() throws Exception { | |
// NO-OP | |
} | |
@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); | |
} | |
return ObjectNameWrapper.unwrap(registeredJmxObjectName); | |
} | |
/** | |
* Removes a custom connection property. | |
* | |
* @param name | |
* Name of the custom connection property to remove | |
* @see #addConnectionProperty(String, String) | |
*/ | |
public void removeConnectionProperty(final String name) { | |
connectionProperties.remove(name); | |
} | |
/** | |
* Sets the print writer to be used by this configuration to log information on abandoned objects. | |
* | |
* @param logWriter | |
* The new log writer | |
*/ | |
public void setAbandonedLogWriter(final PrintWriter logWriter) { | |
if (abandonedConfig == null) { | |
abandonedConfig = new AbandonedConfig(); | |
} | |
abandonedConfig.setLogWriter(logWriter); | |
final GenericObjectPool<?> gop = this.connectionPool; | |
if (gop != null) { | |
gop.setAbandonedConfig(abandonedConfig); | |
} | |
} | |
/** | |
* If the connection pool implements {@link org.apache.commons.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. | |
* | |
* @param usageTracking | |
* A value of <code>true</code> will enable the recording of a stack trace on every use of a pooled | |
* connection | |
*/ | |
public void setAbandonedUsageTracking(final boolean usageTracking) { | |
if (abandonedConfig == null) { | |
abandonedConfig = new AbandonedConfig(); | |
} | |
abandonedConfig.setUseUsageTracking(usageTracking); | |
final GenericObjectPool<?> gop = this.connectionPool; | |
if (gop != null) { | |
gop.setAbandonedConfig(abandonedConfig); | |
} | |
} | |
/** | |
* <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 allow | |
* Access to the underlying connection is granted when true. | |
*/ | |
public synchronized void setAccessToUnderlyingConnectionAllowed(final boolean allow) { | |
this.accessToUnderlyingConnectionAllowed = allow; | |
} | |
/** | |
* 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. | |
* @since 2.6.0 | |
*/ | |
public void setAutoCommitOnReturn(final boolean autoCommitOnReturn) { | |
this.autoCommitOnReturn = autoCommitOnReturn; | |
} | |
/** | |
* 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: 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 (!isEmpty(s)) { | |
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 | |
* the connection properties used to create new connections | |
*/ | |
public void setConnectionProperties(final String connectionProperties) { | |
Objects.requireNonNull(connectionProperties, "connectionProperties is null"); | |
final String[] entries = connectionProperties.split(";"); | |
final Properties properties = new Properties(); | |
for (final String entry : entries) { | |
if (entry.length() > 0) { | |
final int index = entry.indexOf('='); | |
if (index > 0) { | |
final String name = entry.substring(0, index); | |
final String value = entry.substring(index + 1); | |
properties.setProperty(name, value); | |
} else { | |
// no value is empty string which is how java.util.Properties works | |
properties.setProperty(entry, ""); | |
} | |
} | |
} | |
this.connectionProperties = properties; | |
} | |
/** | |
* <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 | |
*/ | |
public void setDefaultAutoCommit(final Boolean defaultAutoCommit) { | |
this.defaultAutoCommit = defaultAutoCommit; | |
} | |
/** | |
* <p> | |
* Sets the default catalog. | |
* </p> | |
* <p> | |
* Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first | |
* time one of the following methods is invoked: <code>getConnection, setLogwriter, | |
* setLoginTimeout, getLoginTimeout, getLogWriter.</code> | |
* </p> | |
* | |
* @param defaultCatalog | |
* the default catalog | |
*/ | |
public void setDefaultCatalog(final String defaultCatalog) { | |
if (isEmpty(defaultCatalog)) { | |
this.defaultCatalog = null; | |
} else { | |
this.defaultCatalog = defaultCatalog; | |
} | |
} | |
/** | |
* 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. | |
*/ | |
public void setDefaultQueryTimeout(final Integer defaultQueryTimeoutSeconds) { | |
this.defaultQueryTimeoutSeconds = defaultQueryTimeoutSeconds; | |
} | |
/** | |
* <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; | |
} | |
/** | |
* <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 (isEmpty(defaultSchema)) { | |
this.defaultSchema = null; | |
} else { | |
this.defaultSchema = defaultSchema; | |
} | |
} | |
/** | |
* <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; | |
} | |
/** | |
* 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> | |
* | |
* @param disconnectionSqlCodes | |
* SQL_STATE codes considered to signal fatal conditions | |
* @since 2.1 | |
*/ | |
public void setDisconnectionSqlCodes(final Collection<String> disconnectionSqlCodes) { | |
if (disconnectionSqlCodes != null && disconnectionSqlCodes.size() > 0) { | |
HashSet<String> newVal = null; | |
for (final String s : disconnectionSqlCodes) { | |
if (!isEmpty(s)) { | |
if (newVal == null) { | |
newVal = new HashSet<>(); | |
} | |
newVal.add(s); | |
} | |
} | |
this.disconnectionSqlCodes = newVal; | |
} else { | |
this.disconnectionSqlCodes = null; | |
} | |
} | |
/** | |
* 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> | |
* 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> | |
* | |
* @param driverClassLoader | |
* the class loader with which to load the JDBC driver | |
*/ | |
public synchronized void setDriverClassLoader(final ClassLoader driverClassLoader) { | |
this.driverClassLoader = driverClassLoader; | |
} | |
/** | |
* <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 (isEmpty(driverClassName)) { | |
this.driverClassName = null; | |
} else { | |
this.driverClassName = driverClassName; | |
} | |
} | |
/** | |
* Sets the ConnectionFactory class name. | |
* | |
* @param connectionFactoryClassName | |
* @since 2.7.0 | |
*/ | |
public void setConnectionFactoryClassName(final String connectionFactoryClassName) { | |
if (isEmpty(connectionFactoryClassName)) { | |
this.connectionFactoryClassName = null; | |
} else { | |
this.connectionFactoryClassName = connectionFactoryClassName; | |
} | |
} | |
/** | |
* 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; | |
} | |
/** | |
* 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; | |
} | |
/** | |
* @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; | |
} | |
/** | |
* <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; | |
} | |
/** | |
* 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; | |
} | |
/** | |
* 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); | |
} | |
} | |
/** | |
* 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); | |
} | |
} | |
/** | |
* 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); | |
} | |
} | |
/** | |
* Sets the value of the {@link #numTestsPerEvictionRun} property. | |
* | |
* @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> | |
* | |
* @param password | |
* new value for the password | |
*/ | |
public void setPassword(final String password) { | |
this.password = password; | |
} | |
/** | |
* <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; | |
} | |
/** | |
* @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); | |
} | |
} | |
/** | |
* @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); | |
} | |
} | |
/** | |
* <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); | |
} | |
} | |
/** | |
* 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 rollbackOnReturn | |
* whether a connection will be rolled back when it is returned to the pool. | |
*/ | |
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); | |
} | |
} | |
/** | |
* 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 | |
*/ | |
public synchronized void setTestOnBorrow(final boolean testOnBorrow) { | |
this.testOnBorrow = testOnBorrow; | |
if (connectionPool != null) { | |
connectionPool.setTestOnBorrow(testOnBorrow); | |
} | |
} | |
/** | |
* 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); | |
} | |
} | |
/** | |
* Sets the <code>testOnReturn</code> property. This property determines whether or not the pool will validate | |
* objects before they are returned to the pool. | |
* | |
* @param testOnReturn | |
* new value for testOnReturn property | |
*/ | |
public synchronized void setTestOnReturn(final boolean testOnReturn) { | |
this.testOnReturn = testOnReturn; | |
if (connectionPool != null) { | |
connectionPool.setTestOnReturn(testOnReturn); | |
} | |
} | |
/** | |
* Sets the <code>testWhileIdle</code> property. This property determines whether or not the idle object evictor | |
* will validate connections. | |
* | |
* @param testWhileIdle | |
* new value for testWhileIdle property | |
*/ | |
public synchronized void setTestWhileIdle(final boolean testWhileIdle) { | |
this.testWhileIdle = testWhileIdle; | |
if (connectionPool != null) { | |
connectionPool.setTestWhileIdle(testWhileIdle); | |
} | |
} | |
/** | |
* 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); | |
} | |
} | |
/** | |
* <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; | |
} | |
/** | |
* <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 | |
*/ | |
public void setUsername(final String userName) { | |
this.userName = userName; | |
} | |
/** | |
* <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 (isEmpty(validationQuery)) { | |
this.validationQuery = null; | |
} else { | |
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. | |
* <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; | |
} | |
/** | |
* Starts the connection pool maintenance task, if configured. | |
*/ | |
protected void startPoolMaintenance() { | |
if (connectionPool != null && timeBetweenEvictionRunsMillis > 0) { | |
connectionPool.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis); | |
} | |
} | |
@Override | |
public <T> T unwrap(final Class<T> iface) throws SQLException { | |
throw new SQLException("BasicDataSource is not a wrapper."); | |
} | |
private void updateJmxName(final GenericObjectPoolConfig<?> config) { | |
if (registeredJmxObjectName == null) { | |
return; | |
} | |
final StringBuilder base = new StringBuilder(registeredJmxObjectName.toString()); | |
base.append(Constants.JMX_CONNECTION_POOL_BASE_EXT); | |
config.setJmxNameBase(base.toString()); | |
config.setJmxNamePrefix(Constants.JMX_CONNECTION_POOL_PREFIX); | |
} | |
private ConnectionFactory createConnectionFactory(final Driver driver) throws SQLException { | |
if (connectionFactoryClassName != null) { | |
try { | |
Class<?> connectionFactoryFromCCL = Class.forName(connectionFactoryClassName); | |
return (ConnectionFactory) connectionFactoryFromCCL | |
.getConstructor(Driver.class, String.class, Properties.class) | |
.newInstance(driver, url, connectionProperties); | |
} catch (final Exception t) { | |
final String message = "Cannot load ConnectionFactory implementation '" + connectionFactoryClassName + "'"; | |
logWriter.println(message); | |
t.printStackTrace(logWriter); | |
throw new SQLException(message, t); | |
} | |
} | |
return new DriverConnectionFactory(driver, url, connectionProperties); | |
} | |
} |