DataSourceProxy.java
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.tomcat.jdbc.pool;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.Properties;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;
import javax.sql.XAConnection;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.jdbc.pool.PoolProperties.InterceptorDefinition;
import org.apache.tomcat.jdbc.pool.util.MessageFactory;
/**
* The DataSource proxy lets us implements methods that don't exist in the current compiler JDK but might be methods
* that are part of a future JDK DataSource interface. <br>
* It's a trick to work around compiler issues when implementing interfaces. For example, I could put in Java 6 methods
* of javax.sql.DataSource here, and compile it with JDK 1.5 and still be able to run under Java 6 without getting
* NoSuchMethodException.
*/
public class DataSourceProxy implements PoolConfiguration {
private static final Log log = LogFactory.getLog(DataSourceProxy.class);
private final AtomicBoolean connectionWithoutCredentialsWarningIssued = new AtomicBoolean(false);
/**
* The underlying connection pool.
*/
protected volatile ConnectionPool pool = null;
/**
* The pool configuration properties.
*/
protected volatile PoolConfiguration poolProperties = null;
/**
* Terminal lifecycle flag. Set by {@link #close(boolean)} while holding this proxy's monitor, the same monitor
* under which {@link #pCreatePool()} checks the flag and publishes its result. Once set, no {@link ConnectionPool}
* is published any more: {@link #createPool()} fails with a {@link SQLException} instead of resurrecting a pool
* that its owner has already stopped tracking, and a creation that was already in flight - whose constructor the
* close did not wait for - closes the pool it built instead of publishing it.
*/
private volatile boolean closed = false;
/**
* Serializes pool construction away from this proxy's monitor. The pool constructor pre-connects
* {@link PoolConfiguration#getInitialSize() initialSize} connections, so against a hung database it blocks in the
* driver for as long as the JDBC login timeout; running that under the monitor {@link #close(boolean)} takes made
* the close wait on the driver for an unbounded, uninterruptible time. The gate keeps the construction serialized
* anyway - it is the only point at which two pools are ever built from the same {@code poolProperties}, whose
* contract is that no two pools are ever constructed from one instance at a time - while leaving the close free,
* as it only has to serialize against the short publication step, not the driver. This lock is taken before the
* proxy monitor and never while holding it, so it cannot invert against the monitor's other users:
* {@link #close(boolean)} and, in the {@link DataSource} subclass, the JMX registration callbacks; none of them
* reaches pool creation.
*/
private final Object poolCreationLock = new Object();
/**
* Construct a DataSourceProxy with default pool properties.
*/
public DataSourceProxy() {
this(new PoolProperties());
}
/**
* Construct a DataSourceProxy with the given pool configuration.
*
* @param poolProperties The pool configuration properties
*/
public DataSourceProxy(PoolConfiguration poolProperties) {
if (poolProperties == null) {
throw new NullPointerException(MessageFactory.get("dataSourceProxy.poolConfigurationNull"));
}
this.poolProperties = poolProperties;
}
/**
* Check if this proxy implements, or wraps an instance of, the given interface. The configured
* {@link PoolConfiguration#getDataSource() DataSource}, if any, is checked as the wrapped object.
* <p>
* Has to match signature in DataSource.
*
* @param iface The interface to check
*
* @return {@code true} if this proxy implements the interface or wraps an object that does
*
* @throws SQLException if the wrapped data source throws one
*/
public boolean isWrapperFor(Class<?> iface) throws SQLException {
if (iface.isInstance(this)) {
return true;
}
Object dataSource = poolProperties.getDataSource();
if (iface.isInstance(dataSource)) {
return true;
}
if (dataSource instanceof java.sql.Wrapper) {
// Like the pooled connections, the configured data source may
// itself be a wrapper - of the driver's data source, of a
// pooling data source the configuration replaced - and it is
// what answers for its own layers
return ((java.sql.Wrapper) dataSource).isWrapperFor(iface);
}
return false;
}
/**
* Unwrap the proxy to the given interface. The configured {@link PoolConfiguration#getDataSource() DataSource}, if
* any, is checked as the wrapped object.
* <p>
* Has to match signature in DataSource
*
* @param <T> The interface type
* @param iface The interface to unwrap to
*
* @return an object that implements the interface
*
* @throws SQLException if no object implementing the interface is found
*/
public <T> T unwrap(Class<T> iface) throws SQLException {
if (iface.isInstance(this)) {
return iface.cast(this);
}
Object dataSource = poolProperties.getDataSource();
if (iface.isInstance(dataSource)) {
return iface.cast(dataSource);
}
if (dataSource instanceof java.sql.Wrapper && ((java.sql.Wrapper) dataSource).isWrapperFor(iface)) {
return ((java.sql.Wrapper) dataSource).unwrap(iface);
}
// The Wrapper contract asks for a failure, not for a silent null
// that turns into an unrelated NullPointerException at the caller's
// first use of the "unwrapped" value.
throw new SQLException(MessageFactory.get("dataSourceProxy.notAWrapper", iface.getName()));
}
/**
* Get a database connection. {@link javax.sql.DataSource#getConnection()}
*
* @param username The user name
* @param password The password
*
* @return the connection
*
* @throws SQLException Connection error, or this data source has been closed
*/
public Connection getConnection(String username, String password) throws SQLException {
if (this.getPoolProperties().isAlternateUsernameAllowed()) {
// Go through createPool() rather than testing the field and then
// calling it: that reads the volatile field only once, so a
// close() running concurrently cannot turn this borrow into a
// NullPointerException.
return createPool().getConnection(username, password);
} else {
if (connectionWithoutCredentialsWarningIssued.compareAndSet(false, true)) {
log.warn(MessageFactory.get("dataSourceProxy.alternateUsernameIgnored", username));
}
return getConnection();
}
}
/**
* Return the pool configuration properties.
*
* @return the pool configuration
*/
public PoolConfiguration getPoolProperties() {
return poolProperties;
}
/**
* Sets up the connection pool, by creating a pooling driver. The reference is taken from the volatile field with a
* single read, so that the borrow paths which use this method as their single point of access cannot observe a
* {@code null} that a concurrent {@link #close(boolean)} published after they saw the field set. The result is
* never {@code null}: it is either the pool that is in use or this method fails with an {@link SQLException}.
*
* @return the connection pool
*
* @throws SQLException Error creating pool, or if this data source has been closed
*/
public ConnectionPool createPool() throws SQLException {
// Read the volatile field once. Guarding on it and then returning it
// would read it twice, and a close() landing between the reads makes
// the second one null and hands a null pool out to the caller.
final ConnectionPool p = pool;
if (p != null) {
return p;
} else {
return pCreatePool();
}
}
/**
* Sets up the connection pool, by creating a pooling driver.
*/
private ConnectionPool pCreatePool() throws SQLException {
// Runs under the construction gate, not under the monitor that
// close(boolean) takes: the constructor pre-connects the initial
// size of the pool, so against a hung database it blocks inside the
// driver's connect for as long as the JDBC login timeout, and a
// close parked behind that would be unbounded and uninterruptible.
// Returning null is not possible here: either the closed flag
// rejects the caller or a pool is published and returned.
if (closed) {
throw new SQLException(MessageFactory.get("dataSourceProxy.dataSourceClosed"));
}
synchronized (poolCreationLock) {
// Re-check under the gate: a close completed while this thread
// queued must not be resurrected, and a creator that won the
// gate has already published its pool. The gate also keeps this
// the only construction the shared poolProperties ever faces.
if (closed) {
throw new SQLException(MessageFactory.get("dataSourceProxy.dataSourceClosed"));
}
final ConnectionPool existing = pool;
if (existing != null) {
return existing;
}
// The constructor - and with it the driver connects of the
// initial pre-load - runs with the close monitor free. A failure
// here propagates directly: an init that fails after starting
// anything tears its pool down itself before throwing.
final ConnectionPool fresh = new ConnectionPool(poolProperties);
final boolean rejected;
synchronized (this) {
// Check-and-publish against the closure, which sets the flag
// and takes the field in one step under this same monitor:
// whichever of the two runs first wins, so the close either
// finds this pool published and closes it, or it found the
// field empty and this thread takes the pool down below. It
// is never neither - that was the leak - and never both.
rejected = closed;
if (!rejected) {
pool = fresh;
}
}
if (rejected) {
// close(boolean) completed while this pool was being built
// and had nothing published to close, so the sessions the
// pre-load established and the cleaner the constructor
// started are this thread's to release.
try {
fresh.close(true);
} catch (Exception x) {
log.warn(MessageFactory.get("dataSourceProxy.errorClosingPool"), x);
}
throw new SQLException(MessageFactory.get("dataSourceProxy.dataSourceClosed"));
}
return fresh;
}
}
/**
* Get a database connection. {@link javax.sql.DataSource#getConnection()}
*
* @return the connection
*
* @throws SQLException Connection error, or this data source has been closed
*/
public Connection getConnection() throws SQLException {
// One read of the volatile field, through createPool(): a guard on
// the field followed by a call on it reads it twice, and a close()
// landing between the two reads makes the second one null and a
// NullPointerException escapes this SQLException contract.
return createPool().getConnection();
}
/**
* Invokes an sync operation to retrieve the connection.
*
* @return a Future containing a reference to the connection when it becomes available
*
* @throws SQLException Connection error, or this data source has been closed
*/
public Future<Connection> getConnectionAsync() throws SQLException {
// See getConnection() on why the pool is reached through createPool()
return createPool().getConnectionAsync();
}
/**
* Get a database connection. {@link javax.sql.XADataSource#getXAConnection()}
*
* @return the connection
*
* @throws SQLException Connection error
*/
public XAConnection getXAConnection() throws SQLException {
Connection con = getConnection();
if (con instanceof XAConnection) {
return (XAConnection) con;
} else {
try {
con.close();
} catch (Exception ignore) {
// Ignore
}
throw new SQLException(MessageFactory.get("dataSourceProxy.connectionNotXA"));
}
}
/**
* Get a database connection. {@link javax.sql.XADataSource#getXAConnection(String, String)}
*
* @param username The user name
* @param password The password
*
* @return the connection
*
* @throws SQLException Connection error
*/
public XAConnection getXAConnection(String username, String password) throws SQLException {
Connection con = getConnection(username, password);
if (con instanceof XAConnection) {
return (XAConnection) con;
} else {
try {
con.close();
} catch (Exception ignore) {
// Ignore
}
throw new SQLException(MessageFactory.get("dataSourceProxy.connectionNotXA"));
}
}
/**
* Get a database connection. {@link javax.sql.DataSource#getConnection()}
*
* @return the connection
*
* @throws SQLException Connection error
*/
public javax.sql.PooledConnection getPooledConnection() throws SQLException {
return (javax.sql.PooledConnection) getConnection();
}
/**
* Get a database connection. {@link javax.sql.DataSource#getConnection(String,String)}
*
* @param username The user name
* @param password The password
*
* @return the connection
*
* @throws SQLException Connection error
*/
public javax.sql.PooledConnection getPooledConnection(String username, String password) throws SQLException {
return (javax.sql.PooledConnection) getConnection(username, password);
}
/**
* Return the underlying connection pool, creating it if necessary.
*
* @return the connection pool, or null if creation failed or this data source has been closed
*/
public ConnectionPool getPool() {
try {
return createPool();
} catch (SQLException x) {
if (closed) {
// A closed data source legitimately has no pool; this is
// a normal lifecycle state, not a creation failure.
return null;
}
log.error(MessageFactory.get("dataSourceProxy.errorCreatingPool"), x);
return null;
}
}
/**
* Close the connection pool, returning connections to the database. The closure is terminal: later borrow or pool
* creation attempts on this data source fail with an <code>SQLException</code> instead of recreating the pool.
*/
public void close() {
close(false);
}
/**
* Close the connection pool. If a pool creation is in flight, this method does not wait for it - the driver
* connects of the creation's initial pre-load can block for an unbounded, uninterruptible time against a hung
* database - it marks this data source closed and returns: the creation observes the closure at its publication
* step and closes the pool it built instead of publishing it.
*
* @param all if true close all connections, otherwise only idle ones
*/
public synchronized void close(boolean all) {
// Sets the terminal closed flag and takes the published pool in one
// step under this monitor, which the publication step of
// pCreatePool() also takes as one step: a creation whose pool is not
// yet published cannot be missed by this close and then published
// after it - it either wins the monitor and this close closes its
// pool, or this close wins and that creation tears its pool down as
// rejected. The closed flag makes the closure terminal for the pool
// creation paths as well: a closed data source no longer resurrects
// its pool on the next borrow or statistics access. The monitor is
// never held across a pool construction, so this method never waits
// on a driver connect.
closed = true;
final ConnectionPool p = pool;
pool = null;
if (p != null) {
try {
p.close(all);
} catch (Exception x) {
log.warn(MessageFactory.get("dataSourceProxy.errorClosingPool"), x);
}
}
}
/**
* Return the current number of connections in the pool.
*
* @return the pool size
*/
public int getPoolSize() {
final ConnectionPool p = pool;
if (p == null) {
return 0;
} else {
return p.getSize();
}
}
@Override
public String toString() {
return super.toString() + "{" + getPoolProperties() + "}";
}
@Override
public String getPoolName() {
return getPoolProperties().getPoolName();
}
/**
* Set the pool configuration properties directly.
*
* @param poolProperties The new pool configuration
*/
public void setPoolProperties(PoolConfiguration poolProperties) {
// Same fail-fast check as the constructor: a null configuration would
// leave the ~60 delegating accessors and the borrow paths to throw
// bare NullPointerExceptions at opaque points, while the login timeout
// accessors would silently degrade. The class invariant is that this
// field is never null, so reject the misuse at its site.
if (poolProperties == null) {
throw new NullPointerException(MessageFactory.get("dataSourceProxy.poolConfigurationNull"));
}
this.poolProperties = poolProperties;
}
@Override
public void setDriverClassName(String driverClassName) {
this.poolProperties.setDriverClassName(driverClassName);
}
@Override
public void setInitialSize(int initialSize) {
this.poolProperties.setInitialSize(initialSize);
}
@Override
public void setInitSQL(String initSQL) {
this.poolProperties.setInitSQL(initSQL);
}
@Override
public void setLogAbandoned(boolean logAbandoned) {
this.poolProperties.setLogAbandoned(logAbandoned);
}
@Override
public void setMaxActive(int maxActive) {
this.poolProperties.setMaxActive(maxActive);
}
@Override
public void setMaxIdle(int maxIdle) {
this.poolProperties.setMaxIdle(maxIdle);
}
@Override
public void setMaxWait(int maxWait) {
this.poolProperties.setMaxWait(maxWait);
}
@Override
public void setMinEvictableIdleTimeMillis(int minEvictableIdleTimeMillis) {
this.poolProperties.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
}
@Override
public void setMinIdle(int minIdle) {
this.poolProperties.setMinIdle(minIdle);
}
@Override
public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) {
this.poolProperties.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
}
/**
* Sets the password used to establish connections with, and mirrors it into the {@code password} database
* property. A {@code null} password clears the credential: the entry is removed from the database properties
* instead of the properties being set to null, which {@link java.util.Properties} rejects and which previously
* threw after the field had already been cleared, leaving the previous password behind for the driver to keep
* using. A configuration whose database properties are {@code null} only stores the field, as there is no
* property collection to mirror into. {@inheritDoc}
*/
@Override
public void setPassword(String password) {
this.poolProperties.setPassword(password);
Properties dbProperties = this.poolProperties.getDbProperties();
if (dbProperties != null) {
String storedPassword = this.poolProperties.getPassword();
if (storedPassword == null) {
dbProperties.remove(PoolUtilities.PROP_PASSWORD);
} else {
dbProperties.setProperty(PoolUtilities.PROP_PASSWORD, storedPassword);
}
}
}
@Override
public void setRemoveAbandoned(boolean removeAbandoned) {
this.poolProperties.setRemoveAbandoned(removeAbandoned);
}
@Override
public void setRemoveAbandonedTimeout(int removeAbandonedTimeout) {
this.poolProperties.setRemoveAbandonedTimeout(removeAbandonedTimeout);
}
@Override
public void setTestOnBorrow(boolean testOnBorrow) {
this.poolProperties.setTestOnBorrow(testOnBorrow);
}
@Override
public void setTestOnConnect(boolean testOnConnect) {
this.poolProperties.setTestOnConnect(testOnConnect);
}
@Override
public void setTestOnReturn(boolean testOnReturn) {
this.poolProperties.setTestOnReturn(testOnReturn);
}
@Override
public void setTestWhileIdle(boolean testWhileIdle) {
this.poolProperties.setTestWhileIdle(testWhileIdle);
}
@Override
public void setTimeBetweenEvictionRunsMillis(int timeBetweenEvictionRunsMillis) {
this.poolProperties.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
}
@Override
public void setUrl(String url) {
this.poolProperties.setUrl(url);
}
/**
* Sets the user name used to establish connections with, and mirrors it into the {@code user} database property.
* A {@code null} user name clears the credential: the entry is removed from the database properties instead of the
* properties being set to null, which {@link java.util.Properties} rejects and which previously threw after the
* field had already been cleared, leaving the previous user name behind for the driver to keep using. A
* configuration whose database properties are {@code null} only stores the field, as there is no property
* collection to mirror into. {@inheritDoc}
*/
@Override
public void setUsername(String username) {
this.poolProperties.setUsername(username);
Properties dbProperties = this.poolProperties.getDbProperties();
if (dbProperties != null) {
String storedUsername = this.poolProperties.getUsername();
if (storedUsername == null) {
dbProperties.remove(PoolUtilities.PROP_USER);
} else {
dbProperties.setProperty(PoolUtilities.PROP_USER, storedUsername);
}
}
}
@Override
public void setValidationInterval(long validationInterval) {
this.poolProperties.setValidationInterval(validationInterval);
}
@Override
public void setValidationQuery(String validationQuery) {
this.poolProperties.setValidationQuery(validationQuery);
}
@Override
public void setValidatorClassName(String className) {
this.poolProperties.setValidatorClassName(className);
}
@Override
public void setValidationQueryTimeout(int validationQueryTimeout) {
this.poolProperties.setValidationQueryTimeout(validationQueryTimeout);
}
@Override
public void setJdbcInterceptors(String interceptors) {
this.getPoolProperties().setJdbcInterceptors(interceptors);
}
@Override
public void setJmxEnabled(boolean enabled) {
this.getPoolProperties().setJmxEnabled(enabled);
}
@Override
public void setFairQueue(boolean fairQueue) {
this.getPoolProperties().setFairQueue(fairQueue);
}
@Override
public void setUseLock(boolean useLock) {
this.getPoolProperties().setUseLock(useLock);
}
@Override
public void setDefaultCatalog(String catalog) {
this.getPoolProperties().setDefaultCatalog(catalog);
}
@Override
public void setDefaultAutoCommit(Boolean autocommit) {
this.getPoolProperties().setDefaultAutoCommit(autocommit);
}
@Override
public void setDefaultTransactionIsolation(int defaultTransactionIsolation) {
this.getPoolProperties().setDefaultTransactionIsolation(defaultTransactionIsolation);
}
@Override
public void setConnectionProperties(String properties) {
try {
// Delegate so the raw string is stored as well as parsed: a
// hand-rolled merge into the database properties left
// getConnectionProperties() reporting null for a value that
// was just set, unlike every other implementation of the
// interface (PoolProperties itself and the pool's JMX wrapper).
getPoolProperties().setConnectionProperties(properties);
} catch (RuntimeException x) {
log.error(MessageFactory.get("dataSourceProxy.unableToParseConnectionProperties"), x);
throw x;
}
}
@Override
public void setUseEquals(boolean useEquals) {
this.getPoolProperties().setUseEquals(useEquals);
}
/**
* no-op {@link javax.sql.DataSource#getParentLogger}
*
* @return no return value
*
* @throws SQLFeatureNotSupportedException Unsupported
*/
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
throw new SQLFeatureNotSupportedException();
}
/**
* no-op {@link javax.sql.DataSource#getLogWriter}
*
* @return null
*
* @throws SQLException No exception
*/
public PrintWriter getLogWriter() throws SQLException {
return null;
}
/**
* no-op {@link javax.sql.DataSource#setLogWriter(PrintWriter)}
*
* @param out Ignored
*
* @throws SQLException No exception
*/
public void setLogWriter(PrintWriter out) throws SQLException {
// NOOP
}
/**
* no-op {@link javax.sql.DataSource#getLoginTimeout}
*
* @return the timeout
*/
public int getLoginTimeout() {
if (poolProperties == null) {
return 0;
} else {
return poolProperties.getMaxWait() / 1000;
}
}
/**
* {@link javax.sql.DataSource#setLoginTimeout(int)}
*
* @param i The timeout value
*/
public void setLoginTimeout(int i) {
if (poolProperties == null) {
return;
} else {
poolProperties.setMaxWait(1000 * i);
}
}
@Override
public int getSuspectTimeout() {
return getPoolProperties().getSuspectTimeout();
}
@Override
public void setSuspectTimeout(int seconds) {
getPoolProperties().setSuspectTimeout(seconds);
}
// These members expose JMX attributes through Tomcat's dynamic
// reflection.
/**
* If the pool has not been created, it will be created during this call.
*
* @return the number of established but idle connections
*/
public int getIdle() {
try {
return createPool().getIdle();
} catch (SQLException x) {
throw new RuntimeException(x);
}
}
/**
* {@link #getIdle()}
*
* @return the number of established but idle connections
*/
public int getNumIdle() {
return getIdle();
}
/**
* Forces an abandon check on the connection pool. If connections that have been abandoned exists, they will be
* closed during this run
*/
public void checkAbandoned() {
try {
createPool().checkAbandoned();
} catch (SQLException x) {
throw new RuntimeException(x);
}
}
/**
* Forces a check for resizing of the idle connections
*/
public void checkIdle() {
try {
createPool().checkIdle();
} catch (SQLException x) {
throw new RuntimeException(x);
}
}
/**
* Returns the number of connections currently in use by the application.
*
* @return number of connections in use by the application
*/
public int getActive() {
try {
return createPool().getActive();
} catch (SQLException x) {
throw new RuntimeException(x);
}
}
/**
* Returns the number of connections currently in use by the application.
*
* @return number of active connections
*/
public int getNumActive() {
return getActive();
}
/**
* Returns the number of threads currently waiting for a connection from the pool.
*
* @return number of waiting threads
*/
public int getWaitCount() {
try {
return createPool().getWaitCount();
} catch (SQLException x) {
throw new RuntimeException(x);
}
}
/**
* Returns the current total number of connections in the pool.
*
* @return current pool size
*/
public int getSize() {
try {
return createPool().getSize();
} catch (SQLException x) {
throw new RuntimeException(x);
}
}
/**
* Performs a validation on idle connections.
* <p>
* Note: this operation is safe with concurrent traffic and with a closing pool even when the per-connection lock
* is disabled (sweeper switched off and {@link PoolProperties#getUseLock()} returning {@code false}): each idle
* connection is claimed out of the idle queue before it is validated or reconnected and is handed back, released
* or - if the pool closed in the meantime - disconnected without ever re-entering the queue, as described on
* {@link ConnectionPool#testAllIdle()}.
*/
public void testIdle() {
try {
createPool().testAllIdle();
} catch (SQLException x) {
throw new RuntimeException(x);
}
}
/**
* The total number of connections borrowed from this pool.
*
* @return the borrowed connection count
*/
public long getBorrowedCount() {
try {
return createPool().getBorrowedCount();
} catch (SQLException x) {
throw new RuntimeException(x);
}
}
/**
* The total number of connections returned to this pool.
*
* @return the returned connection count
*/
public long getReturnedCount() {
try {
return createPool().getReturnedCount();
} catch (SQLException x) {
throw new RuntimeException(x);
}
}
/**
* The total number of connections created by this pool.
*
* @return the created connection count
*/
public long getCreatedCount() {
try {
return createPool().getCreatedCount();
} catch (SQLException x) {
throw new RuntimeException(x);
}
}
/**
* The total number of connections released from this pool.
*
* @return the released connection count
*/
public long getReleasedCount() {
try {
return createPool().getReleasedCount();
} catch (SQLException x) {
throw new RuntimeException(x);
}
}
/**
* The total number of connections reconnected by this pool.
*
* @return the reconnected connection count
*/
public long getReconnectedCount() {
try {
return createPool().getReconnectedCount();
} catch (SQLException x) {
throw new RuntimeException(x);
}
}
/**
* The total number of connections released by remove abandoned.
*
* @return the PoolCleaner removed abandoned connection count
*/
public long getRemoveAbandonedCount() {
try {
return createPool().getRemoveAbandonedCount();
} catch (SQLException x) {
throw new RuntimeException(x);
}
}
/**
* The total number of connections released by eviction.
*
* @return the PoolCleaner evicted idle connection count
*/
public long getReleasedIdleCount() {
try {
return createPool().getReleasedIdleCount();
} catch (SQLException x) {
throw new RuntimeException(x);
}
}
/**
* reset the statistics of this pool.
*/
public void resetStats() {
try {
createPool().resetStats();
} catch (SQLException x) {
throw new RuntimeException(x);
}
}
@Override
public String getConnectionProperties() {
return getPoolProperties().getConnectionProperties();
}
/**
* Returns a copy of the database properties with the password removed. This object doubles as its own JMX/bean
* surface and {@link #setPassword(String)} stores the password into the database properties, so returning them as
* they are would expose the plaintext password through a getter while {@link #getPassword()} is explicitly masked -
* the same protection the pool's own MBean
* ({@link org.apache.tomcat.jdbc.pool.jmx.ConnectionPool#getDbProperties()}) already applies. {@inheritDoc}
*/
@Override
public Properties getDbProperties() {
return PoolUtilities.cloneWithoutPassword(getPoolProperties().getDbProperties());
}
@Override
public String getDefaultCatalog() {
return getPoolProperties().getDefaultCatalog();
}
@Override
public int getDefaultTransactionIsolation() {
return getPoolProperties().getDefaultTransactionIsolation();
}
@Override
public String getDriverClassName() {
return getPoolProperties().getDriverClassName();
}
@Override
public int getInitialSize() {
return getPoolProperties().getInitialSize();
}
@Override
public String getInitSQL() {
return getPoolProperties().getInitSQL();
}
@Override
public String getJdbcInterceptors() {
return getPoolProperties().getJdbcInterceptors();
}
@Override
public int getMaxActive() {
return getPoolProperties().getMaxActive();
}
@Override
public int getMaxIdle() {
return getPoolProperties().getMaxIdle();
}
@Override
public int getMaxWait() {
return getPoolProperties().getMaxWait();
}
@Override
public int getMinEvictableIdleTimeMillis() {
return getPoolProperties().getMinEvictableIdleTimeMillis();
}
@Override
public int getMinIdle() {
return getPoolProperties().getMinIdle();
}
@Override
public long getMaxAge() {
return getPoolProperties().getMaxAge();
}
@Override
public String getName() {
return getPoolProperties().getName();
}
@Override
public int getNumTestsPerEvictionRun() {
return getPoolProperties().getNumTestsPerEvictionRun();
}
/**
* @return DOES NOT RETURN THE PASSWORD, IT WOULD SHOW UP IN JMX
*/
@Override
public String getPassword() {
return "Password not available as DataSource/JMX operation.";
}
@Override
public int getRemoveAbandonedTimeout() {
return getPoolProperties().getRemoveAbandonedTimeout();
}
@Override
public int getTimeBetweenEvictionRunsMillis() {
return getPoolProperties().getTimeBetweenEvictionRunsMillis();
}
@Override
public String getUrl() {
return getPoolProperties().getUrl();
}
@Override
public String getUsername() {
return getPoolProperties().getUsername();
}
@Override
public long getValidationInterval() {
return getPoolProperties().getValidationInterval();
}
@Override
public String getValidationQuery() {
return getPoolProperties().getValidationQuery();
}
@Override
public int getValidationQueryTimeout() {
return getPoolProperties().getValidationQueryTimeout();
}
@Override
public String getValidatorClassName() {
return getPoolProperties().getValidatorClassName();
}
@Override
public Validator getValidator() {
return getPoolProperties().getValidator();
}
@Override
public void setValidator(Validator validator) {
getPoolProperties().setValidator(validator);
}
@Override
public boolean isAccessToUnderlyingConnectionAllowed() {
return getPoolProperties().isAccessToUnderlyingConnectionAllowed();
}
@Override
public Boolean isDefaultAutoCommit() {
return getPoolProperties().isDefaultAutoCommit();
}
@Override
public Boolean isDefaultReadOnly() {
return getPoolProperties().isDefaultReadOnly();
}
@Override
public boolean isLogAbandoned() {
return getPoolProperties().isLogAbandoned();
}
@Override
public boolean isPoolSweeperEnabled() {
return getPoolProperties().isPoolSweeperEnabled();
}
@Override
public boolean isRemoveAbandoned() {
return getPoolProperties().isRemoveAbandoned();
}
@Override
public int getAbandonWhenPercentageFull() {
return getPoolProperties().getAbandonWhenPercentageFull();
}
@Override
public boolean isTestOnBorrow() {
return getPoolProperties().isTestOnBorrow();
}
@Override
public boolean isTestOnConnect() {
return getPoolProperties().isTestOnConnect();
}
@Override
public boolean isTestOnReturn() {
return getPoolProperties().isTestOnReturn();
}
@Override
public boolean isTestWhileIdle() {
return getPoolProperties().isTestWhileIdle();
}
@Override
public Boolean getDefaultAutoCommit() {
return getPoolProperties().getDefaultAutoCommit();
}
@Override
public Boolean getDefaultReadOnly() {
return getPoolProperties().getDefaultReadOnly();
}
@Override
public InterceptorDefinition[] getJdbcInterceptorsAsArray() {
return getPoolProperties().getJdbcInterceptorsAsArray();
}
@Override
public boolean getUseLock() {
return getPoolProperties().getUseLock();
}
@Override
public boolean isFairQueue() {
return getPoolProperties().isFairQueue();
}
@Override
public boolean isJmxEnabled() {
return getPoolProperties().isJmxEnabled();
}
@Override
public boolean isUseEquals() {
return getPoolProperties().isUseEquals();
}
@Override
public void setAbandonWhenPercentageFull(int percentage) {
getPoolProperties().setAbandonWhenPercentageFull(percentage);
}
@Override
public void setAccessToUnderlyingConnectionAllowed(boolean accessToUnderlyingConnectionAllowed) {
getPoolProperties().setAccessToUnderlyingConnectionAllowed(accessToUnderlyingConnectionAllowed);
}
@Override
public void setDbProperties(Properties dbProperties) {
getPoolProperties().setDbProperties(dbProperties);
}
@Override
public void setDefaultReadOnly(Boolean defaultReadOnly) {
getPoolProperties().setDefaultReadOnly(defaultReadOnly);
}
@Override
public void setMaxAge(long maxAge) {
getPoolProperties().setMaxAge(maxAge);
}
@Override
public void setName(String name) {
getPoolProperties().setName(name);
}
@Override
public void setDataSource(Object ds) {
getPoolProperties().setDataSource(ds);
}
@Override
public Object getDataSource() {
return getPoolProperties().getDataSource();
}
@Override
public void setDataSourceJNDI(String jndiDS) {
getPoolProperties().setDataSourceJNDI(jndiDS);
}
@Override
public String getDataSourceJNDI() {
return getPoolProperties().getDataSourceJNDI();
}
@Override
public boolean isAlternateUsernameAllowed() {
return getPoolProperties().isAlternateUsernameAllowed();
}
@Override
public void setAlternateUsernameAllowed(boolean alternateUsernameAllowed) {
getPoolProperties().setAlternateUsernameAllowed(alternateUsernameAllowed);
}
@Override
public void setCommitOnReturn(boolean commitOnReturn) {
getPoolProperties().setCommitOnReturn(commitOnReturn);
}
@Override
public boolean getCommitOnReturn() {
return getPoolProperties().getCommitOnReturn();
}
@Override
public void setRollbackOnReturn(boolean rollbackOnReturn) {
getPoolProperties().setRollbackOnReturn(rollbackOnReturn);
}
@Override
public boolean getRollbackOnReturn() {
return getPoolProperties().getRollbackOnReturn();
}
/**
* {@inheritDoc}
*
* @deprecated The disposable connection facade is always used, so this property no longer has any effect.
*/
@Override
@Deprecated
public void setUseDisposableConnectionFacade(boolean useDisposableConnectionFacade) {
getPoolProperties().setUseDisposableConnectionFacade(useDisposableConnectionFacade);
}
/**
* {@inheritDoc}
*
* @deprecated The disposable connection facade is always used, so this property no longer has any effect.
*/
@Override
@Deprecated
public boolean getUseDisposableConnectionFacade() {
return getPoolProperties().getUseDisposableConnectionFacade();
}
@Override
public void setLogValidationErrors(boolean logValidationErrors) {
getPoolProperties().setLogValidationErrors(logValidationErrors);
}
@Override
public boolean getLogValidationErrors() {
return getPoolProperties().getLogValidationErrors();
}
@Override
public boolean getPropagateInterruptState() {
return getPoolProperties().getPropagateInterruptState();
}
@Override
public void setPropagateInterruptState(boolean propagateInterruptState) {
getPoolProperties().setPropagateInterruptState(propagateInterruptState);
}
@Override
public boolean isIgnoreExceptionOnPreLoad() {
return getPoolProperties().isIgnoreExceptionOnPreLoad();
}
@Override
public void setIgnoreExceptionOnPreLoad(boolean ignoreExceptionOnPreLoad) {
getPoolProperties().setIgnoreExceptionOnPreLoad(ignoreExceptionOnPreLoad);
}
/**
* {@inheritDoc}
*
* @deprecated The statement facade is always used, so this property no longer has any effect.
*/
@Override
@Deprecated
public boolean getUseStatementFacade() {
return getPoolProperties().getUseStatementFacade();
}
/**
* {@inheritDoc}
*
* @deprecated The statement facade is always used, so this property no longer has any effect.
*/
@Override
@Deprecated
public void setUseStatementFacade(boolean useStatementFacade) {
getPoolProperties().setUseStatementFacade(useStatementFacade);
}
/**
* Purge all connections from the pool.
*/
public void purge() {
try {
createPool().purge();
} catch (SQLException x) {
log.error(MessageFactory.get("dataSourceProxy.unableToPurgePool"), x);
}
}
/**
* Enable purging of connections on return to the pool.
*/
public void purgeOnReturn() {
try {
createPool().purgeOnReturn();
} catch (SQLException x) {
log.error(MessageFactory.get("dataSourceProxy.unableToPurgePool"), x);
}
}
}