    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *      http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017package org.apache.commons.dbcp2;
    018
    019import java.io.OutputStreamWriter;
    020import java.io.PrintWriter;
    021import java.nio.charset.StandardCharsets;
    022import java.security.AccessController;
    023import java.security.PrivilegedActionException;
    024import java.security.PrivilegedExceptionAction;
    025import java.sql.Connection;
    026import java.sql.Driver;
    027import java.sql.DriverManager;
    028import java.sql.SQLException;
    029import java.sql.SQLFeatureNotSupportedException;
    030import java.util.ArrayList;
    031import java.util.Collection;
    032import java.util.Collections;
    033import java.util.HashSet;
    034import java.util.List;
    035import java.util.Objects;
    036import java.util.Properties;
    037import java.util.Set;
    038import java.util.logging.Logger;
    039
    040import javax.management.MBeanRegistration;
    041import javax.management.MBeanServer;
    042import javax.management.MalformedObjectNameException;
    043import javax.management.ObjectName;
    044import javax.sql.DataSource;
    045
    046import org.apache.commons.logging.Log;
    047import org.apache.commons.logging.LogFactory;
    048import org.apache.commons.pool2.PooledObject;
    049import org.apache.commons.pool2.impl.AbandonedConfig;
    050import org.apache.commons.pool2.impl.BaseObjectPoolConfig;
    051import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;
    052import org.apache.commons.pool2.impl.GenericObjectPool;
    053import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
    054
    055/**
    056 * <p>
    057 * Basic implementation of <code>javax.sql.DataSource</code> that is configured via JavaBeans properties. This is not
    058 * the only way to combine the <em>commons-dbcp2</em> and <em>commons-pool2</em> packages, but provides a "one stop
    059 * shopping" solution for basic requirements.
    060 * </p>
    061 *
    062 * @since 2.0
    063 */
    064public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBeanRegistration, AutoCloseable {
    065
    066    private static final Log log = LogFactory.getLog(BasicDataSource.class);
    067
    068    static {
    069        // Attempt to prevent deadlocks - see DBCP - 272
    070        DriverManager.getDrivers();
    071        try {
    072            // Load classes now to prevent AccessControlExceptions later
    073            // A number of classes are loaded when getConnection() is called
    074            // but the following classes are not loaded and therefore require
    075            // explicit loading.
    076            if (Utils.IS_SECURITY_ENABLED) {
    077                final ClassLoader loader = BasicDataSource.class.getClassLoader();
    078                final String dbcpPackageName = BasicDataSource.class.getPackage().getName();
    079                loader.loadClass(dbcpPackageName + ".BasicDataSource$PaGetConnection");
    080                loader.loadClass(dbcpPackageName + ".DelegatingCallableStatement");
    081                loader.loadClass(dbcpPackageName + ".DelegatingDatabaseMetaData");
    082                loader.loadClass(dbcpPackageName + ".DelegatingPreparedStatement");
    083                loader.loadClass(dbcpPackageName + ".DelegatingResultSet");
    084                loader.loadClass(dbcpPackageName + ".PoolableCallableStatement");
    085                loader.loadClass(dbcpPackageName + ".PoolablePreparedStatement");
    086                loader.loadClass(dbcpPackageName + ".PoolingConnection$StatementType");
    087                loader.loadClass(dbcpPackageName + ".PStmtKey");
    088
    089                final String poolPackageName = PooledObject.class.getPackage().getName();
    090                loader.loadClass(poolPackageName + ".impl.LinkedBlockingDeque$Node");
    091                loader.loadClass(poolPackageName + ".impl.GenericKeyedObjectPool$ObjectDeque");
    092            }
    093        } catch (final ClassNotFoundException cnfe) {
    094            throw new IllegalStateException("Unable to pre-load classes", cnfe);
    095        }
    096    }
    097
    098    // ------------------------------------------------------------- Properties
    099
    100    /**
    101     * The default auto-commit state of connections created by this pool.
    102     */
    103    private volatile Boolean defaultAutoCommit;
    104
    105    /**
    106     * Returns the default auto-commit property.
    107     *
    108     * @return true if default auto-commit is enabled
    109     */
    110    @Override
    111    public Boolean getDefaultAutoCommit() {
    112        return defaultAutoCommit;
    113    }
    114
    115    /**
    116     * <p>
    117     * Sets default auto-commit state of connections returned by this datasource.
    118     * </p>
    119     * <p>
    120     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
    121     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
    122     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
    123     * </p>
    124     *
    125     * @param defaultAutoCommit
    126     *            default auto-commit value
    127     */
    128    public void setDefaultAutoCommit(final Boolean defaultAutoCommit) {
    129        this.defaultAutoCommit = defaultAutoCommit;
    130    }
    131
    132    /**
    133     * The default read-only state of connections created by this pool.
    134     */
    135    private transient Boolean defaultReadOnly;
    136
    137    /**
    138     * Returns the default readOnly property.
    139     *
    140     * @return true if connections are readOnly by default
    141     */
    142    @Override
    143    public Boolean getDefaultReadOnly() {
    144        return defaultReadOnly;
    145    }
    146
    147    /**
    148     * <p>
    149     * Sets defaultReadonly property.
    150     * </p>
    151     * <p>
    152     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
    153     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
    154     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
    155     * </p>
    156     *
    157     * @param defaultReadOnly
    158     *            default read-only value
    159     */
    160    public void setDefaultReadOnly(final Boolean defaultReadOnly) {
    161        this.defaultReadOnly = defaultReadOnly;
    162    }
    163
    164    /**
    165     * The default TransactionIsolation state of connections created by this pool.
    166     */
    167    private volatile int defaultTransactionIsolation = PoolableConnectionFactory.UNKNOWN_TRANSACTIONISOLATION;
    168
    169    /**
    170     * Returns the default transaction isolation state of returned connections.
    171     *
    172     * @return the default value for transaction isolation state
    173     * @see Connection#getTransactionIsolation
    174     */
    175    @Override
    176    public int getDefaultTransactionIsolation() {
    177        return this.defaultTransactionIsolation;
    178    }
    179
    180    /**
    181     * <p>
    182     * Sets the default transaction isolation state for returned connections.
    183     * </p>
    184     * <p>
    185     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
    186     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
    187     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
    188     * </p>
    189     *
    190     * @param defaultTransactionIsolation
    191     *            the default transaction isolation state
    192     * @see Connection#getTransactionIsolation
    193     */
    194    public void setDefaultTransactionIsolation(final int defaultTransactionIsolation) {
    195        this.defaultTransactionIsolation = defaultTransactionIsolation;
    196    }
    197
    198    private Integer defaultQueryTimeoutSeconds;
    199
    200    /**
    201     * Gets the default query timeout that will be used for {@link java.sql.Statement Statement}s created from this
    202     * connection. <code>null</code> means that the driver default will be used.
    203     *
    204     * @return The default query timeout in seconds.
    205     */
    206    public Integer getDefaultQueryTimeout() {
    207        return defaultQueryTimeoutSeconds;
    208    }
    209
    210    /**
    211     * Sets the default query timeout that will be used for {@link java.sql.Statement Statement}s created from this
    212     * connection. <code>null</code> means that the driver default will be used.
    213     *
    214     * @param defaultQueryTimeoutSeconds
    215     *            The default query timeout in seconds.
    216     */
    217    public void setDefaultQueryTimeout(final Integer defaultQueryTimeoutSeconds) {
    218        this.defaultQueryTimeoutSeconds = defaultQueryTimeoutSeconds;
    219    }
    220
    221    /**
    222     * The default "catalog" of connections created by this pool.
    223     */
    224    private volatile String defaultCatalog;
    225
    226    /**
    227     * Returns the default catalog.
    228     *
    229     * @return the default catalog
    230     */
    231    @Override
    232    public String getDefaultCatalog() {
    233        return this.defaultCatalog;
    234    }
    235
    236    /**
    237     * <p>
    238     * Sets the default catalog.
    239     * </p>
    240     * <p>
    241     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
    242     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
    243     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
    244     * </p>
    245     *
    246     * @param defaultCatalog
    247     *            the default catalog
    248     */
    249    public void setDefaultCatalog(final String defaultCatalog) {
    250        if (defaultCatalog != null && defaultCatalog.trim().length() > 0) {
    251            this.defaultCatalog = defaultCatalog;
    252        } else {
    253            this.defaultCatalog = null;
    254        }
    255    }
    256
    257    /**
    258     * The property that controls if the pooled connections cache some state rather than query the database for current
    259     * state to improve performance.
    260     */
    261    private boolean cacheState = true;
    262
    263    /**
    264     * Returns the state caching flag.
    265     *
    266     * @return the state caching flag
    267     */
    268    @Override
    269    public boolean getCacheState() {
    270        return cacheState;
    271    }
    272
    273    /**
    274     * Sets the state caching flag.
    275     *
    276     * @param cacheState
    277     *            The new value for the state caching flag
    278     */
    279    public void setCacheState(final boolean cacheState) {
    280        this.cacheState = cacheState;
    281    }
    282
    283    /**
    284     * The instance of the JDBC Driver to use.
    285     */
    286    private Driver driver;
    287
    288    /**
    289     * Returns the JDBC Driver that has been configured for use by this pool.
    290     * <p>
    291     * Note: This getter only returns the last value set by a call to {@link #setDriver(Driver)}. It does not return any
    292     * driver instance that may have been created from the value set via {@link #setDriverClassName(String)}.
    293     * </p>
    294     *
    295     * @return the JDBC Driver that has been configured for use by this pool
    296     */
    297    public synchronized Driver getDriver() {
    298        return driver;
    299    }
    300
    301    /**
    302     * Sets the JDBC Driver instance to use for this pool.
    303     * <p>
    304     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
    305     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
    306     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
    307     * </p>
    308     *
    309     * @param driver
    310     *            The JDBC Driver instance to use for this pool.
    311     */
    312    public synchronized void setDriver(final Driver driver) {
    313        this.driver = driver;
    314    }
    315
    316    /**
    317     * The fully qualified Java class name of the JDBC driver to be used.
    318     */
    319    private String driverClassName;
    320
    321    /**
    322     * Returns the JDBC driver class name.
    323     * <p>
    324     * Note: This getter only returns the last value set by a call to {@link #setDriverClassName(String)}. It does not
    325     * return the class name of any driver that may have been set via {@link #setDriver(Driver)}.
    326     * </p>
    327     *
    328     * @return the JDBC driver class name
    329     */
    330    @Override
    331    public synchronized String getDriverClassName() {
    332        return this.driverClassName;
    333    }
    334
    335    /**
    336     * <p>
    337     * Sets the JDBC driver class name.
    338     * </p>
    339     * <p>
    340     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
    341     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
    342     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
    343     * </p>
    344     *
    345     * @param driverClassName
    346     *            the class name of the JDBC driver
    347     */
    348    public synchronized void setDriverClassName(final String driverClassName) {
    349        if (driverClassName != null && driverClassName.trim().length() > 0) {
    350            this.driverClassName = driverClassName;
    351        } else {
    352            this.driverClassName = null;
    353        }
    354    }
    355
    356    /**
    357     * The class loader instance to use to load the JDBC driver. If not specified, {@link Class#forName(String)} is used
    358     * to load the JDBC driver. If specified, {@link Class#forName(String, boolean, ClassLoader)} is used.
    359     */
    360    private ClassLoader driverClassLoader;
    361
    362    /**
    363     * Returns the class loader specified for loading the JDBC driver. Returns <code>null</code> if no class loader has
    364     * been explicitly specified.
    365     * <p>
    366     * Note: This getter only returns the last value set by a call to {@link #setDriverClassLoader(ClassLoader)}. It
    367     * does not return the class loader of any driver that may have been set via {@link #setDriver(Driver)}.
    368     * </p>
    369     *
    370     * @return The class loader specified for loading the JDBC driver.
    371     */
    372    public synchronized ClassLoader getDriverClassLoader() {
    373        return this.driverClassLoader;
    374    }
    375
    376    /**
    377     * <p>
    378     * Sets the class loader to be used to load the JDBC driver.
    379     * </p>
    380     * <p>
    381     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
    382     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
    383     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
    384     * </p>
    385     *
    386     * @param driverClassLoader
    387     *            the class loader with which to load the JDBC driver
    388     */
    389    public synchronized void setDriverClassLoader(final ClassLoader driverClassLoader) {
    390        this.driverClassLoader = driverClassLoader;
    391    }
    392
    393    /**
    394     * True means that borrowObject returns the most recently used ("last in") connection in the pool (if there are idle
    395     * connections available). False means that the pool behaves as a FIFO queue - connections are taken from the idle
    396     * instance pool in the order that they are returned to the pool.
    397     */
    398    private boolean lifo = BaseObjectPoolConfig.DEFAULT_LIFO;
    399
    400    /**
    401     * Returns the LIFO property.
    402     *
    403     * @return true if connection pool behaves as a LIFO queue.
    404     */
    405    @Override
    406    public synchronized boolean getLifo() {
    407        return this.lifo;
    408    }
    409
    410    /**
    411     * Sets the LIFO property. True means the pool behaves as a LIFO queue; false means FIFO.
    412     *
    413     * @param lifo
    414     *            the new value for the LIFO property
    415     */
    416    public synchronized void setLifo(final boolean lifo) {
    417        this.lifo = lifo;
    418        if (connectionPool != null) {
    419            connectionPool.setLifo(lifo);
    420        }
    421    }
    422
    423    /**
    424     * The maximum number of active connections that can be allocated from this pool at the same time, or negative for
    425     * no limit.
    426     */
    427    private int maxTotal = GenericObjectPoolConfig.DEFAULT_MAX_TOTAL;
    428
    429    /**
    430     * <p>
    431     * Returns the maximum number of active connections that can be allocated at the same time.
    432     * </p>
    433     * <p>
    434     * A negative number means that there is no limit.
    435     * </p>
    436     *
    437     * @return the maximum number of active connections
    438     */
    439    @Override
    440    public synchronized int getMaxTotal() {
    441        return this.maxTotal;
    442    }
    443
    444    /**
    445     * Sets the maximum total number of idle and borrows connections that can be active at the same time. Use a negative
    446     * value for no limit.
    447     *
    448     * @param maxTotal
    449     *            the new value for maxTotal
    450     * @see #getMaxTotal()
    451     */
    452    public synchronized void setMaxTotal(final int maxTotal) {
    453        this.maxTotal = maxTotal;
    454        if (connectionPool != null) {
    455            connectionPool.setMaxTotal(maxTotal);
    456        }
    457    }
    458
    459    /**
    460     * The maximum number of connections that can remain idle in the pool, without extra ones being destroyed, or
    461     * negative for no limit. If maxIdle is set too low on heavily loaded systems it is possible you will see
    462     * connections being closed and almost immediately new connections being opened. This is a result of the active
    463     * threads momentarily closing connections faster than they are opening them, causing the number of idle connections
    464     * to rise above maxIdle. The best value for maxIdle for heavily loaded system will vary but the default is a good
    465     * starting point.
    466     */
    467    private int maxIdle = GenericObjectPoolConfig.DEFAULT_MAX_IDLE;
    468
    469    /**
    470     * <p>
    471     * Returns the maximum number of connections that can remain idle in the pool. Excess idle connections are destroyed
    472     * on return to the pool.
    473     * </p>
    474     * <p>
    475     * A negative value indicates that there is no limit
    476     * </p>
    477     *
    478     * @return the maximum number of idle connections
    479     */
    480    @Override
    481    public synchronized int getMaxIdle() {
    482        return this.maxIdle;
    483    }
    484
    485    /**
    486     * Sets the maximum number of connections that can remain idle in the pool. Excess idle connections are destroyed on
    487     * return to the pool.
    488     *
    489     * @see #getMaxIdle()
    490     * @param maxIdle
    491     *            the new value for maxIdle
    492     */
    493    public synchronized void setMaxIdle(final int maxIdle) {
    494        this.maxIdle = maxIdle;
    495        if (connectionPool != null) {
    496            connectionPool.setMaxIdle(maxIdle);
    497        }
    498    }
    499
    500    /**
    501     * The minimum number of active connections that can remain idle in the pool, without extra ones being created when
    502     * the evictor runs, or 0 to create none. The pool attempts to ensure that minIdle connections are available when
    503     * the idle object evictor runs. The value of this property has no effect unless
    504     * {@link #timeBetweenEvictionRunsMillis} has a positive value.
    505     */
    506    private int minIdle = GenericObjectPoolConfig.DEFAULT_MIN_IDLE;
    507
    508    /**
    509     * Returns the minimum number of idle connections in the pool. The pool attempts to ensure that minIdle connections
    510     * are available when the idle object evictor runs. The value of this property has no effect unless
    511     * {@link #timeBetweenEvictionRunsMillis} has a positive value.
    512     *
    513     * @return the minimum number of idle connections
    514     * @see GenericObjectPool#getMinIdle()
    515     */
    516    @Override
    517    public synchronized int getMinIdle() {
    518        return this.minIdle;
    519    }
    520
    521    /**
    522     * Sets the minimum number of idle connections in the pool. The pool attempts to ensure that minIdle connections are
    523     * available when the idle object evictor runs. The value of this property has no effect unless
    524     * {@link #timeBetweenEvictionRunsMillis} has a positive value.
    525     *
    526     * @param minIdle
    527     *            the new value for minIdle
    528     * @see GenericObjectPool#setMinIdle(int)
    529     */
    530    public synchronized void setMinIdle(final int minIdle) {
    531        this.minIdle = minIdle;
    532        if (connectionPool != null) {
    533            connectionPool.setMinIdle(minIdle);
    534        }
    535    }
    536
    537    /**
    538     * The initial number of connections that are created when the pool is started.
    539     */
    540    private int initialSize = 0;
    541
    542    /**
    543     * Returns the initial size of the connection pool.
    544     *
    545     * @return the number of connections created when the pool is initialized
    546     */
    547    @Override
    548    public synchronized int getInitialSize() {
    549        return this.initialSize;
    550    }
    551
    552    /**
    553     * <p>
    554     * Sets the initial size of the connection pool.
    555     * </p>
    556     * <p>
    557     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
    558     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
    559     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
    560     * </p>
    561     *
    562     * @param initialSize
    563     *            the number of connections created when the pool is initialized
    564     */
    565    public synchronized void setInitialSize(final int initialSize) {
    566        this.initialSize = initialSize;
    567    }
    568
    569    /**
    570     * The maximum number of milliseconds that the pool will wait (when there are no available connections) for a
    571     * connection to be returned before throwing an exception, or <= 0 to wait indefinitely.
    572     */
    573    private long maxWaitMillis = BaseObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS;
    574
    575    /**
    576     * Returns the maximum number of milliseconds that the pool will wait for a connection to be returned before
    577     * throwing an exception. A value less than or equal to zero means the pool is set to wait indefinitely.
    578     *
    579     * @return the maxWaitMillis property value
    580     */
    581    @Override
    582    public synchronized long getMaxWaitMillis() {
    583        return this.maxWaitMillis;
    584    }
    585
    586    /**
    587     * Sets the MaxWaitMillis property. Use -1 to make the pool wait indefinitely.
    588     *
    589     * @param maxWaitMillis
    590     *            the new value for MaxWaitMillis
    591     * @see #getMaxWaitMillis()
    592     */
    593    public synchronized void setMaxWaitMillis(final long maxWaitMillis) {
    594        this.maxWaitMillis = maxWaitMillis;
    595        if (connectionPool != null) {
    596            connectionPool.setMaxWaitMillis(maxWaitMillis);
    597        }
    598    }
    599
    600    /**
    601     * Prepared statement pooling for this pool. When this property is set to <code>true</code> both PreparedStatements
    602     * and CallableStatements are pooled.
    603     */
    604    private boolean poolPreparedStatements = false;
    605
    606    /**
    607     * Returns true if we are pooling statements.
    608     *
    609     * @return true if prepared and callable statements are pooled
    610     */
    611    @Override
    612    public synchronized boolean isPoolPreparedStatements() {
    613        return this.poolPreparedStatements;
    614    }
    615
    616    /**
    617     * <p>
    618     * Sets whether to pool statements or not.
    619     * </p>
    620     * <p>
    621     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
    622     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
    623     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
    624     * </p>
    625     *
    626     * @param poolingStatements
    627     *            pooling on or off
    628     */
    629    public synchronized void setPoolPreparedStatements(final boolean poolingStatements) {
    630        this.poolPreparedStatements = poolingStatements;
    631    }
    632
    633    /**
    634     * <p>
    635     * The maximum number of open statements that can be allocated from the statement pool at the same time, or negative
    636     * for no limit. Since a connection usually only uses one or two statements at a time, this is mostly used to help
    637     * detect resource leaks.
    638     * </p>
    639     * <p>
    640     * Note: As of version 1.3, CallableStatements (those produced by {@link Connection#prepareCall}) are pooled along
    641     * with PreparedStatements (produced by {@link Connection#prepareStatement}) and
    642     * <code>maxOpenPreparedStatements</code> limits the total number of prepared or callable statements that may be in
    643     * use at a given time.
    644     * </p>
    645     */
    646    private int maxOpenPreparedStatements = GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL;
    647
    648    /**
    649     * Gets the value of the <code>maxOpenPreparedStatements</code> property.
    650     *
    651     * @return the maximum number of open statements
    652     */
    653    @Override
    654    public synchronized int getMaxOpenPreparedStatements() {
    655        return this.maxOpenPreparedStatements;
    656    }
    657
    658    /**
    659     * <p>
    660     * Sets the value of the <code>maxOpenPreparedStatements</code> property.
    661     * </p>
    662     * <p>
    663     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
    664     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
    665     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
    666     * </p>
    667     *
    668     * @param maxOpenStatements
    669     *            the new maximum number of prepared statements
    670     */
    671    public synchronized void setMaxOpenPreparedStatements(final int maxOpenStatements) {
    672        this.maxOpenPreparedStatements = maxOpenStatements;
    673    }
    674
    675    /**
    676     * The indication of whether objects will be validated as soon as they have been created by the pool. If the object
    677     * fails to validate, the borrow operation that triggered the creation will fail.
    678     */
    679    private boolean testOnCreate = false;
    680
    681    /**
    682     * Returns the {@link #testOnCreate} property.
    683     *
    684     * @return true if objects are validated immediately after they are created by the pool
    685     * @see #testOnCreate
    686     */
    687    @Override
    688    public synchronized boolean getTestOnCreate() {
    689        return this.testOnCreate;
    690    }
    691
    692    /**
    693     * Sets the {@link #testOnCreate} property. This property determines whether or not the pool will validate objects
    694     * immediately after they are created by the pool
    695     *
    696     * @param testOnCreate
    697     *            new value for testOnCreate property
    698     */
    699    public synchronized void setTestOnCreate(final boolean testOnCreate) {
    700        this.testOnCreate = testOnCreate;
    701        if (connectionPool != null) {
    702            connectionPool.setTestOnCreate(testOnCreate);
    703        }
    704    }
    705
    706    /**
    707     * The indication of whether objects will be validated before being borrowed from the pool. If the object fails to
    708     * validate, it will be dropped from the pool, and we will attempt to borrow another.
    709     */
    710    private boolean testOnBorrow = true;
    711
    712    /**
    713     * Returns the {@link #testOnBorrow} property.
    714     *
    715     * @return true if objects are validated before being borrowed from the pool
    716     *
    717     * @see #testOnBorrow
    718     */
    719    @Override
    720    public synchronized boolean getTestOnBorrow() {
    721        return this.testOnBorrow;
    722    }
    723
    724    /**
    725     * Sets the {@link #testOnBorrow} property. This property determines whether or not the pool will validate objects
    726     * before they are borrowed from the pool.
    727     *
    728     * @param testOnBorrow
    729     *            new value for testOnBorrow property
    730     */
    731    public synchronized void setTestOnBorrow(final boolean testOnBorrow) {
    732        this.testOnBorrow = testOnBorrow;
    733        if (connectionPool != null) {
    734            connectionPool.setTestOnBorrow(testOnBorrow);
    735        }
    736    }
    737
    738    /**
    739     * The indication of whether objects will be validated before being returned to the pool.
    740     */
    741    private boolean testOnReturn = false;
    742
    743    /**
    744     * Returns the value of the {@link #testOnReturn} property.
    745     *
    746     * @return true if objects are validated before being returned to the pool
    747     * @see #testOnReturn
    748     */
    749    public synchronized boolean getTestOnReturn() {
    750        return this.testOnReturn;
    751    }
    752
    753    /**
    754     * Sets the <code>testOnReturn</code> property. This property determines whether or not the pool will validate
    755     * objects before they are returned to the pool.
    756     *
    757     * @param testOnReturn
    758     *            new value for testOnReturn property
    759     */
    760    public synchronized void setTestOnReturn(final boolean testOnReturn) {
    761        this.testOnReturn = testOnReturn;
    762        if (connectionPool != null) {
    763            connectionPool.setTestOnReturn(testOnReturn);
    764        }
    765    }
    766
    767    /**
    768     * The number of milliseconds to sleep between runs of the idle object evictor thread. When non-positive, no idle
    769     * object evictor thread will be run.
    770     */
    771    private long timeBetweenEvictionRunsMillis = BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
    772
    773    /**
    774     * Returns the value of the {@link #timeBetweenEvictionRunsMillis} property.
    775     *
    776     * @return the time (in milliseconds) between evictor runs
    777     * @see #timeBetweenEvictionRunsMillis
    778     */
    779    @Override
    780    public synchronized long getTimeBetweenEvictionRunsMillis() {
    781        return this.timeBetweenEvictionRunsMillis;
    782    }
    783
    784    /**
    785     * Sets the {@link #timeBetweenEvictionRunsMillis} property.
    786     *
    787     * @param timeBetweenEvictionRunsMillis
    788     *            the new time between evictor runs
    789     * @see #timeBetweenEvictionRunsMillis
    790     */
    791    public synchronized void setTimeBetweenEvictionRunsMillis(final long timeBetweenEvictionRunsMillis) {
    792        this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
    793        if (connectionPool != null) {
    794            connectionPool.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
    795        }
    796    }
    797
    798    /**
    799     * The number of objects to examine during each run of the idle object evictor thread (if any).
    800     */
    801    private int numTestsPerEvictionRun = BaseObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
    802
    803    /**
    804     * Returns the value of the {@link #numTestsPerEvictionRun} property.
    805     *
    806     * @return the number of objects to examine during idle object evictor runs
    807     * @see #numTestsPerEvictionRun
    808     */
    809    @Override
    810    public synchronized int getNumTestsPerEvictionRun() {
    811        return this.numTestsPerEvictionRun;
    812    }
    813
    814    /**
    815     * Sets the value of the {@link #numTestsPerEvictionRun} property.
    816     *
    817     * @param numTestsPerEvictionRun
    818     *            the new {@link #numTestsPerEvictionRun} value
    819     * @see #numTestsPerEvictionRun
    820     */
    821    public synchronized void setNumTestsPerEvictionRun(final int numTestsPerEvictionRun) {
    822        this.numTestsPerEvictionRun = numTestsPerEvictionRun;
    823        if (connectionPool != null) {
    824            connectionPool.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
    825        }
    826    }
    827
    828    /**
    829     * The minimum amount of time an object may sit idle in the pool before it is eligible for eviction by the idle
    830     * object evictor (if any).
    831     */
    832    private long minEvictableIdleTimeMillis = BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
    833
    834    /**
    835     * Returns the {@link #minEvictableIdleTimeMillis} property.
    836     *
    837     * @return the value of the {@link #minEvictableIdleTimeMillis} property
    838     * @see #minEvictableIdleTimeMillis
    839     */
    840    @Override
    841    public synchronized long getMinEvictableIdleTimeMillis() {
    842        return this.minEvictableIdleTimeMillis;
    843    }
    844
    845    /**
    846     * Sets the {@link #minEvictableIdleTimeMillis} property.
    847     *
    848     * @param minEvictableIdleTimeMillis
    849     *            the minimum amount of time an object may sit idle in the pool
    850     * @see #minEvictableIdleTimeMillis
    851     */
    852    public synchronized void setMinEvictableIdleTimeMillis(final long minEvictableIdleTimeMillis) {
    853        this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
    854        if (connectionPool != null) {
    855            connectionPool.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
    856        }
    857    }
    858
    859    /**
    860     * The minimum amount of time a connection may sit idle in the pool before it is eligible for eviction by the idle
    861     * object evictor, with the extra condition that at least "minIdle" connections remain in the pool. Note that
    862     * {@code minEvictableIdleTimeMillis} takes precedence over this parameter. See
    863     * {@link #getSoftMinEvictableIdleTimeMillis()}.
    864     */
    865    private long softMinEvictableIdleTimeMillis = BaseObjectPoolConfig.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
    866
    867    /**
    868     * Sets the minimum amount of time a connection may sit idle in the pool before it is eligible for eviction by the
    869     * idle object evictor, with the extra condition that at least "minIdle" connections remain in the pool.
    870     *
    871     * @param softMinEvictableIdleTimeMillis
    872     *            minimum amount of time a connection may sit idle in the pool before it is eligible for eviction,
    873     *            assuming there are minIdle idle connections in the pool.
    874     * @see #getSoftMinEvictableIdleTimeMillis
    875     */
    876    public synchronized void setSoftMinEvictableIdleTimeMillis(final long softMinEvictableIdleTimeMillis) {
    877        this.softMinEvictableIdleTimeMillis = softMinEvictableIdleTimeMillis;
    878        if (connectionPool != null) {
    879            connectionPool.setSoftMinEvictableIdleTimeMillis(softMinEvictableIdleTimeMillis);
    880        }
    881    }
    882
    883    /**
    884     * <p>
    885     * Returns the minimum amount of time a connection may sit idle in the pool before it is eligible for eviction by
    886     * the idle object evictor, with the extra condition that at least "minIdle" connections remain in the pool.
    887     * </p>
    888     *
    889     * <p>
    890     * When {@link #getMinEvictableIdleTimeMillis() minEvictableIdleTimeMillis} is set to a positive value,
    891     * minEvictableIdleTimeMillis is examined first by the idle connection evictor - i.e. when idle connections are
    892     * visited by the evictor, idle time is first compared against {@code minEvictableIdleTimeMillis} (without
    893     * considering the number of idle connections in the pool) and then against {@code softMinEvictableIdleTimeMillis},
    894     * including the {@code minIdle}, constraint.
    895     * </p>
    896     *
    897     * @return minimum amount of time a connection may sit idle in the pool before it is eligible for eviction, assuming
    898     *         there are minIdle idle connections in the pool
    899     */
    900    @Override
    901    public synchronized long getSoftMinEvictableIdleTimeMillis() {
    902        return softMinEvictableIdleTimeMillis;
    903    }
    904
    905    private String evictionPolicyClassName = BaseObjectPoolConfig.DEFAULT_EVICTION_POLICY_CLASS_NAME;
    906
    907    /**
    908     * Gets the EvictionPolicy implementation in use with this connection pool.
    909     *
    910     * @return The EvictionPolicy implementation in use with this connection pool.
    911     */
    912    public synchronized String getEvictionPolicyClassName() {
    913        return evictionPolicyClassName;
    914    }
    915
    916    /**
    917     * Sets the EvictionPolicy implementation to use with this connection pool.
    918     *
    919     * @param evictionPolicyClassName
    920     *            The fully qualified class name of the EvictionPolicy implementation
    921     */
    922    public synchronized void setEvictionPolicyClassName(final String evictionPolicyClassName) {
    923        if (connectionPool != null) {
    924            connectionPool.setEvictionPolicyClassName(evictionPolicyClassName);
    925        }
    926        this.evictionPolicyClassName = evictionPolicyClassName;
    927    }
    928
    929    /**
    930     * The indication of whether objects will be validated by the idle object evictor (if any). If an object fails to
    931     * validate, it will be dropped from the pool.
    932     */
    933    private boolean testWhileIdle = false;
    934
    935    /**
    936     * Returns the value of the {@link #testWhileIdle} property.
    937     *
    938     * @return true if objects examined by the idle object evictor are validated
    939     * @see #testWhileIdle
    940     */
    941    @Override
    942    public synchronized boolean getTestWhileIdle() {
    943        return this.testWhileIdle;
    944    }
    945
    946    /**
    947     * Sets the <code>testWhileIdle</code> property. This property determines whether or not the idle object evictor
    948     * will validate connections.
    949     *
    950     * @param testWhileIdle
    951     *            new value for testWhileIdle property
    952     */
    953    public synchronized void setTestWhileIdle(final boolean testWhileIdle) {
    954        this.testWhileIdle = testWhileIdle;
    955        if (connectionPool != null) {
    956            connectionPool.setTestWhileIdle(testWhileIdle);
    957        }
    958    }
    959
    960    /**
    961     * [Read Only] The current number of active connections that have been allocated from this data source.
    962     *
    963     * @return the current number of active connections
    964     */
    965    @Override
    966    public int getNumActive() {
    967        // Copy reference to avoid NPE if close happens after null check
    968        final GenericObjectPool<PoolableConnection> pool = connectionPool;
    969        if (pool != null) {
    970            return pool.getNumActive();
    971        }
    972        return 0;
    973    }
    974
    975    /**
    976     * [Read Only] The current number of idle connections that are waiting to be allocated from this data source.
    977     *
    978     * @return the current number of idle connections
    979     */
    980    @Override
    981    public int getNumIdle() {
    982        // Copy reference to avoid NPE if close happens after null check
    983        final GenericObjectPool<PoolableConnection> pool = connectionPool;
    984        if (pool != null) {
    985            return pool.getNumIdle();
    986        }
    987        return 0;
    988    }
    989
    990    /**
    991     * The connection password to be passed to our JDBC driver to establish a connection.
    992     */
    993    private volatile String password;
    994
    995    /**
    996     * Returns the password passed to the JDBC driver to establish connections.
    997     *
    998     * @return the connection password
    999     */
    1000    @Override
    1001    public String getPassword() {
    1002        return this.password;
    1003    }
    1004
    1005    /**
    1006     * <p>
    1007     * Sets the {@link #password}.
    1008     * </p>
    1009     * <p>
    1010     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
    1011     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
    1012     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
    1013     * </p>
    1014     *
    1015     * @param password
    1016     *            new value for the password
    1017     */
    1018    public void setPassword(final String password) {
    1019        this.password = password;
    1020    }
    1021
    1022    /**
    1023     * The connection URL to be passed to our JDBC driver to establish a connection.
    1024     */
    1025    private String url;
    1026
    1027    /**
    1028     * Returns the JDBC connection {@link #url} property.
    1029     *
    1030     * @return the {@link #url} passed to the JDBC driver to establish connections
    1031     */
    1032    @Override
    1033    public synchronized String getUrl() {
    1034        return this.url;
    1035    }
    1036
    1037    /**
    1038     * <p>
    1039     * Sets the {@link #url}.
    1040     * </p>
    1041     * <p>
    1042     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
    1043     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
    1044     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
    1045     * </p>
    1046     *
    1047     * @param url
    1048     *            the new value for the JDBC connection url
    1049     */
    1050    public synchronized void setUrl(final String url) {
    1051        this.url = url;
    1052    }
    1053
    1054    /**
    1055     * The connection user name to be passed to our JDBC driver to establish a connection.
    1056     */
    1057    private String userName;
    1058
    1059    /**
    1060     * Returns the JDBC connection {@link #userName} property.
    1061     *
    1062     * @return the {@link #userName} passed to the JDBC driver to establish connections
    1063     */
    1064    @Override
    1065    public String getUsername() {
    1066        return this.userName;
    1067    }
    1068
    1069    /**
    1070     * <p>
    1071     * Sets the {@link #userName}.
    1072     * </p>
    1073     * <p>
    1074     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
    1075     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
    1076     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
    1077     * </p>
    1078     *
    1079     * @param userName
    1080     *            the new value for the JDBC connection user name
    1081     */
    1082    public void setUsername(final String userName) {
    1083        this.userName = userName;
    1084    }
    1085
    1086    /**
    1087     * The SQL query that will be used to validate connections from this pool before returning them to the caller. If
    1088     * specified, this query <strong>MUST</strong> be an SQL SELECT statement that returns at least one row. If not
    1089     * specified, {@link Connection#isValid(int)} will be used to validate connections.
    1090     */
    1091    private volatile String validationQuery;
    1092
    1093    /**
    1094     * Returns the validation query used to validate connections before returning them.
    1095     *
    1096     * @return the SQL validation query
    1097     * @see #validationQuery
    1098     */
    1099    @Override
    1100    public String getValidationQuery() {
    1101        return this.validationQuery;
    1102    }
    1103
    1104    /**
    1105     * <p>
    1106     * Sets the {@link #validationQuery}.
    1107     * </p>
    1108     * <p>
    1109     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
    1110     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
    1111     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
    1112     * </p>
    1113     *
    1114     * @param validationQuery
    1115     *            the new value for the validation query
    1116     */
    1117    public void setValidationQuery(final String validationQuery) {
    1118        if (validationQuery != null && validationQuery.trim().length() > 0) {
    1119            this.validationQuery = validationQuery;
    1120        } else {
    1121            this.validationQuery = null;
    1122        }
    1123    }
    1124
    1125    /**
    1126     * Timeout in seconds before connection validation queries fail.
    1127     */
    1128    private volatile int validationQueryTimeoutSeconds = -1;
    1129
    1130    /**
    1131     * Returns the validation query timeout.
    1132     *
    1133     * @return the timeout in seconds before connection validation queries fail.
    1134     */
    1135    @Override
    1136    public int getValidationQueryTimeout() {
    1137        return validationQueryTimeoutSeconds;
    1138    }
    1139
    1140    /**
    1141     * Sets the validation query timeout, the amount of time, in seconds, that connection validation will wait for a
    1142     * response from the database when executing a validation query. Use a value less than or equal to 0 for no timeout.
    1143     * <p>
    1144     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
    1145     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
    1146     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
    1147     * </p>
    1148     *
    1149     * @param validationQueryTimeoutSeconds
    1150     *            new validation query timeout value in seconds
    1151     */
    1152    public void setValidationQueryTimeout(final int validationQueryTimeoutSeconds) {
    1153        this.validationQueryTimeoutSeconds = validationQueryTimeoutSeconds;
    1154    }
    1155
    1156    /**
    1157     * These SQL statements run once after a Connection is created.
    1158     * <p>
    1159     * This property can be used for example to run ALTER SESSION SET NLS_SORT=XCYECH in an Oracle Database only once
    1160     * after connection creation.
    1161     * </p>
    1162     */
    1163    private volatile List<String> connectionInitSqls;
    1164
    1165    /**
    1166     * Returns the list of SQL statements executed when a physical connection is first created. Returns an empty list if
    1167     * there are no initialization statements configured.
    1168     *
    1169     * @return initialization SQL statements
    1170     */
    1171    public List<String> getConnectionInitSqls() {
    1172        final List<String> result = connectionInitSqls;
    1173        if (result == null) {
    1174            return Collections.emptyList();
    1175        }
    1176        return result;
    1177    }
    1178
    1179    /**
    1180     * Provides the same data as {@link #getConnectionInitSqls()} but in an array so it is accessible via JMX.
    1181     */
    1182    @Override
    1183    public String[] getConnectionInitSqlsAsArray() {
    1184        final Collection<String> result = getConnectionInitSqls();
    1185        return result.toArray(new String[result.size()]);
    1186    }
    1187
    1188    /**
    1189     * Sets the list of SQL statements to be executed when a physical connection is first created.
    1190     * <p>
    1191     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
    1192     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
    1193     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
    1194     * </p>
    1195     *
    1196     * @param connectionInitSqls
    1197     *            Collection of SQL statements to execute on connection creation
    1198     */
    1199    public void setConnectionInitSqls(final Collection<String> connectionInitSqls) {
    1200        if (connectionInitSqls != null && connectionInitSqls.size() > 0) {
    1201            ArrayList<String> newVal = null;
    1202            for (final String s : connectionInitSqls) {
    1203                if (s != null && s.trim().length() > 0) {
    1204                    if (newVal == null) {
    1205                        newVal = new ArrayList<>();
    1206                    }
    1207                    newVal.add(s);
    1208                }
    1209            }
    1210            this.connectionInitSqls = newVal;
    1211        } else {
    1212            this.connectionInitSqls = null;
    1213        }
    1214    }
    1215
    1216    /**
    1217     * Controls access to the underlying connection.
    1218     */
    1219    private boolean accessToUnderlyingConnectionAllowed = false;
    1220
    1221    /**
    1222     * Returns the value of the accessToUnderlyingConnectionAllowed property.
    1223     *
    1224     * @return true if access to the underlying connection is allowed, false otherwise.
    1225     */
    1226    @Override
    1227    public synchronized boolean isAccessToUnderlyingConnectionAllowed() {
    1228        return this.accessToUnderlyingConnectionAllowed;
    1229    }
    1230
    1231    /**
    1232     * <p>
    1233     * Sets the value of the accessToUnderlyingConnectionAllowed property. It controls if the PoolGuard allows access to
    1234     * the underlying connection. (Default: false)
    1235     * </p>
    1236     * <p>
    1237     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
    1238     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
    1239     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
    1240     * </p>
    1241     *
    1242     * @param allow
    1243     *            Access to the underlying connection is granted when true.
    1244     */
    1245    public synchronized void setAccessToUnderlyingConnectionAllowed(final boolean allow) {
    1246        this.accessToUnderlyingConnectionAllowed = allow;
    1247    }
    1248
    1249    private long maxConnLifetimeMillis = -1;
    1250
    1251    /**
    1252     * Returns the maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an
    1253     * infinite lifetime.
    1254     */
    1255    @Override
    1256    public long getMaxConnLifetimeMillis() {
    1257        return maxConnLifetimeMillis;
    1258    }
    1259
    1260    private boolean logExpiredConnections = true;
    1261
    1262    /**
    1263     * When {@link #getMaxConnLifetimeMillis()} is set to limit connection lifetime, this property determines whether or
    1264     * not log messages are generated when the pool closes connections due to maximum lifetime exceeded.
    1265     *
    1266     * @since 2.1
    1267     */
    1268    @Override
    1269    public boolean getLogExpiredConnections() {
    1270        return logExpiredConnections;
    1271    }
    1272
    1273    /**
    1274     * <p>
    1275     * Sets the maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an
    1276     * infinite lifetime.
    1277     * </p>
    1278     * <p>
    1279     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
    1280     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
    1281     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
    1282     * </p>
    1283     *
    1284     * @param maxConnLifetimeMillis
    1285     *            The maximum permitted lifetime of a connection in milliseconds.
    1286     */
    1287    public void setMaxConnLifetimeMillis(final long maxConnLifetimeMillis) {
    1288        this.maxConnLifetimeMillis = maxConnLifetimeMillis;
    1289    }
    1290
    1291    /**
    1292     * When {@link #getMaxConnLifetimeMillis()} is set to limit connection lifetime, this property determines whether or
    1293     * not log messages are generated when the pool closes connections due to maximum lifetime exceeded. Set this
    1294     * property to false to suppress log messages when connections expire.
    1295     *
    1296     * @param logExpiredConnections
    1297     *            Whether or not log messages are generated when the pool closes connections due to maximum lifetime
    1298     *            exceeded.
    1299     */
    1300    public void setLogExpiredConnections(final boolean logExpiredConnections) {
    1301        this.logExpiredConnections = logExpiredConnections;
    1302    }
    1303
    1304    private String jmxName;
    1305
    1306    /**
    1307     * Returns the JMX name that has been requested for this DataSource. If the requested name is not valid, an
    1308     * alternative may be chosen.
    1309     *
    1310     * @return The JMX name that has been requested for this DataSource.
    1311     */
    1312    public String getJmxName() {
    1313        return jmxName;
    1314    }
    1315
    1316    /**
    1317     * Sets the JMX name that has been requested for this DataSource. If the requested name is not valid, an alternative
    1318     * may be chosen. This DataSource will attempt to register itself using this name. If another component registers
    1319     * this DataSource with JMX and this name is valid this name will be used in preference to any specified by the
    1320     * other component.
    1321     *
    1322     * @param jmxName
    1323     *            The JMX name that has been requested for this DataSource
    1324     */
    1325    public void setJmxName(final String jmxName) {
    1326        this.jmxName = jmxName;
    1327    }
    1328
    1329    private boolean enableAutoCommitOnReturn = true;
    1330
    1331    /**
    1332     * Returns the value of the flag that controls whether or not connections being returned to the pool will be checked
    1333     * and configured with {@link Connection#setAutoCommit(boolean) Connection.setAutoCommit(true)} if the auto commit
    1334     * setting is {@code false} when the connection is returned. It is <code>true</code> by default.
    1335     *
    1336     * @return Whether or not connections being returned to the pool will be checked and configured with auto-commit.
    1337     */
    1338    public boolean getEnableAutoCommitOnReturn() {
    1339        return enableAutoCommitOnReturn;
    1340    }
    1341
    1342    /**
    1343     * Sets the value of the flag that controls whether or not connections being returned to the pool will be checked
    1344     * and configured with {@link Connection#setAutoCommit(boolean) Connection.setAutoCommit(true)} if the auto commit
    1345     * setting is {@code false} when the connection is returned. It is <code>true</code> by default.
    1346     *
    1347     * @param enableAutoCommitOnReturn
    1348     *            Whether or not connections being returned to the pool will be checked and configured with auto-commit.
    1349     */
    1350    public void setEnableAutoCommitOnReturn(final boolean enableAutoCommitOnReturn) {
    1351        this.enableAutoCommitOnReturn = enableAutoCommitOnReturn;
    1352    }
    1353
    1354    private boolean rollbackOnReturn = true;
    1355
    1356    /**
    1357     * Gets the current value of the flag that controls whether a connection will be rolled back when it is returned to
    1358     * the pool if auto commit is not enabled and the connection is not read only.
    1359     *
    1360     * @return whether a connection will be rolled back when it is returned to the pool.
    1361     */
    1362    public boolean getRollbackOnReturn() {
    1363        return rollbackOnReturn;
    1364    }
    1365
    1366    /**
    1367     * Sets the flag that controls if a connection will be rolled back when it is returned to the pool if auto commit is
    1368     * not enabled and the connection is not read only.
    1369     *
    1370     * @param rollbackOnReturn
    1371     *            whether a connection will be rolled back when it is returned to the pool.
    1372     */
    1373    public void setRollbackOnReturn(final boolean rollbackOnReturn) {
    1374        this.rollbackOnReturn = rollbackOnReturn;
    1375    }
    1376
    1377    private volatile Set<String> disconnectionSqlCodes;
    1378
    1379    /**
    1380     * Returns the set of SQL_STATE codes considered to signal fatal conditions.
    1381     *
    1382     * @return fatal disconnection state codes
    1383     * @see #setDisconnectionSqlCodes(Collection)
    1384     * @since 2.1
    1385     */
    1386    public Set<String> getDisconnectionSqlCodes() {
    1387        final Set<String> result = disconnectionSqlCodes;
    1388        if (result == null) {
    1389            return Collections.emptySet();
    1390        }
    1391        return result;
    1392    }
    1393
    1394    /**
    1395     * Provides the same data as {@link #getDisconnectionSqlCodes} but in an array so it is accessible via JMX.
    1396     *
    1397     * @since 2.1
    1398     */
    1399    @Override
    1400    public String[] getDisconnectionSqlCodesAsArray() {
    1401        final Collection<String> result = getDisconnectionSqlCodes();
    1402        return result.toArray(new String[result.size()]);
    1403    }
    1404
    1405    /**
    1406     * Sets the SQL_STATE codes considered to signal fatal conditions.
    1407     * <p>
    1408     * Overrides the defaults in {@link Utils#DISCONNECTION_SQL_CODES} (plus anything starting with
    1409     * {@link Utils#DISCONNECTION_SQL_CODE_PREFIX}). If this property is non-null and {@link #getFastFailValidation()}
    1410     * is {@code true}, whenever connections created by this datasource generate exceptions with SQL_STATE codes in this
    1411     * list, they will be marked as "fatally disconnected" and subsequent validations will fail fast (no attempt at
    1412     * isValid or validation query).
    1413     * </p>
    1414     * <p>
    1415     * If {@link #getFastFailValidation()} is {@code false} setting this property has no effect.
    1416     * </p>
    1417     * <p>
    1418     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
    1419     * time one of the following methods is invoked: {@code getConnection, setLogwriter,
    1420     * setLoginTimeout, getLoginTimeout, getLogWriter}.
    1421     * </p>
    1422     *
    1423     * @param disconnectionSqlCodes
    1424     *            SQL_STATE codes considered to signal fatal conditions
    1425     * @since 2.1
    1426     */
    1427    public void setDisconnectionSqlCodes(final Collection<String> disconnectionSqlCodes) {
    1428        if (disconnectionSqlCodes != null && disconnectionSqlCodes.size() > 0) {
    1429            HashSet<String> newVal = null;
    1430            for (final String s : disconnectionSqlCodes) {
    1431                if (s != null && s.trim().length() > 0) {
    1432                    if (newVal == null) {
    1433                        newVal = new HashSet<>();
    1434                    }
    1435                    newVal.add(s);
    1436                }
    1437            }
    1438            this.disconnectionSqlCodes = newVal;
    1439        } else {
    1440            this.disconnectionSqlCodes = null;
    1441        }
    1442    }
    1443
    1444    private boolean fastFailValidation;
    1445
    1446    /**
    1447     * True means that validation will fail immediately for connections that have previously thrown SQLExceptions with
    1448     * SQL_STATE indicating fatal disconnection errors.
    1449     *
    1450     * @return true if connections created by this datasource will fast fail validation.
    1451     * @see #setDisconnectionSqlCodes(Collection)
    1452     * @since 2.1
    1453     */
    1454    @Override
    1455    public boolean getFastFailValidation() {
    1456        return fastFailValidation;
    1457    }
    1458
    1459    /**
    1460     * @see #getFastFailValidation()
    1461     * @param fastFailValidation
    1462     *            true means connections created by this factory will fast fail validation
    1463     * @since 2.1
    1464     */
    1465    public void setFastFailValidation(final boolean fastFailValidation) {
    1466        this.fastFailValidation = fastFailValidation;
    1467    }
    1468
    1469    /**
    1470     * The object pool that internally manages our connections.
    1471     */
    1472    private volatile GenericObjectPool<PoolableConnection> connectionPool;
    1473
    1474    protected GenericObjectPool<PoolableConnection> getConnectionPool() {
    1475        return connectionPool;
    1476    }
    1477
    1478    /**
    1479     * The connection properties that will be sent to our JDBC driver when establishing new connections.
    1480     * <strong>NOTE</strong> - The "user" and "password" properties will be passed explicitly, so they do not need to be
    1481     * included here.
    1482     */
    1483    private Properties connectionProperties = new Properties();
    1484
    1485    // For unit testing
    1486    Properties getConnectionProperties() {
    1487        return connectionProperties;
    1488    }
    1489
    1490    /**
    1491     * The data source we will use to manage connections. This object should be acquired <strong>ONLY</strong> by calls
    1492     * to the <code>createDataSource()</code> method.
    1493     */
    1494    private volatile DataSource dataSource;
    1495
    1496    /**
    1497     * The PrintWriter to which log messages should be directed.
    1498     */
    1499    private volatile PrintWriter logWriter = new PrintWriter(
    1500            new OutputStreamWriter(System.out, StandardCharsets.UTF_8));
    1501
    1502    // ----------------------------------------------------- DataSource Methods
    1503
    1504    /**
    1505     * Creates (if necessary) and return a connection to the database.
    1506     *
    1507     * @throws SQLException
    1508     *             if a database access error occurs
    1509     * @return a database connection
    1510     */
    1511    @Override
    1512    public Connection getConnection() throws SQLException {
    1513        if (Utils.IS_SECURITY_ENABLED) {
    1514            final PrivilegedExceptionAction<Connection> action = new PaGetConnection();
    1515            try {
    1516                return AccessController.doPrivileged(action);
    1517            } catch (final PrivilegedActionException e) {
    1518                final Throwable cause = e.getCause();
    1519                if (cause instanceof SQLException) {
    1520                    throw (SQLException) cause;
    1521                }
    1522                throw new SQLException(e);
    1523            }
    1524        }
    1525        return createDataSource().getConnection();
    1526    }
    1527
    1528    /**
    1529     * <strong>BasicDataSource does NOT support this method.</strong>
    1530     *
    1531     * @param user
    1532     *            Database user on whose behalf the Connection is being made
    1533     * @param pass
    1534     *            The database user's password
    1535     *
    1536     * @throws UnsupportedOperationException
    1537     *             always thrown.
    1538     * @throws SQLException
    1539     *             if a database access error occurs
    1540     * @return nothing - always throws UnsupportedOperationException
    1541     */
    1542    @Override
    1543    public Connection getConnection(final String user, final String pass) throws SQLException {
    1544        // This method isn't supported by the PoolingDataSource returned by the createDataSource
    1545        throw new UnsupportedOperationException("Not supported by BasicDataSource");
    1546    }
    1547
    1548    /**
    1549     * <strong>BasicDataSource does NOT support this method.</strong>
    1550     *
    1551     * <p>
    1552     * Returns the login timeout (in seconds) for connecting to the database.
    1553     * </p>
    1554     * <p>
    1555     * Calls {@link #createDataSource()}, so has the side effect of initializing the connection pool.
    1556     * </p>
    1557     *
    1558     * @throws SQLException
    1559     *             if a database access error occurs
    1560     * @throws UnsupportedOperationException
    1561     *             If the DataSource implementation does not support the login timeout feature.
    1562     * @return login timeout in seconds
    1563     */
    1564    @Override
    1565    public int getLoginTimeout() throws SQLException {
    1566        // This method isn't supported by the PoolingDataSource returned by the createDataSource
    1567        throw new UnsupportedOperationException("Not supported by BasicDataSource");
    1568    }
    1569
    1570    /**
    1571     * <p>
    1572     * Returns the log writer being used by this data source.
    1573     * </p>
    1574     * <p>
    1575     * Calls {@link #createDataSource()}, so has the side effect of initializing the connection pool.
    1576     * </p>
    1577     *
    1578     * @throws SQLException
    1579     *             if a database access error occurs
    1580     * @return log writer in use
    1581     */
    1582    @Override
    1583    public PrintWriter getLogWriter() throws SQLException {
    1584        return createDataSource().getLogWriter();
    1585    }
    1586
    1587    /**
    1588     * <strong>BasicDataSource does NOT support this method. </strong>
    1589     *
    1590     * <p>
    1591     * Set the login timeout (in seconds) for connecting to the database.
    1592     * </p>
    1593     * <p>
    1594     * Calls {@link #createDataSource()}, so has the side effect of initializing the connection pool.
    1595     * </p>
    1596     *
    1597     * @param loginTimeout
    1598     *            The new login timeout, or zero for no timeout
    1599     * @throws UnsupportedOperationException
    1600     *             If the DataSource implementation does not support the login timeout feature.
    1601     * @throws SQLException
    1602     *             if a database access error occurs
    1603     */
    1604    @Override
    1605    public void setLoginTimeout(final int loginTimeout) throws SQLException {
    1606        // This method isn't supported by the PoolingDataSource returned by the createDataSource
    1607        throw new UnsupportedOperationException("Not supported by BasicDataSource");
    1608    }
    1609
    1610    /**
    1611     * <p>
    1612     * Sets the log writer being used by this data source.
    1613     * </p>
    1614     * <p>
    1615     * Calls {@link #createDataSource()}, so has the side effect of initializing the connection pool.
    1616     * </p>
    1617     *
    1618     * @param logWriter
    1619     *            The new log writer
    1620     * @throws SQLException
    1621     *             if a database access error occurs
    1622     */
    1623    @Override
    1624    public void setLogWriter(final PrintWriter logWriter) throws SQLException {
    1625        createDataSource().setLogWriter(logWriter);
    1626        this.logWriter = logWriter;
    1627    }
    1628
    1629    private AbandonedConfig abandonedConfig;
    1630
    1631    /**
    1632     * <p>
    1633     * Flag to remove abandoned connections if they exceed the removeAbandonedTimeout when borrowObject is invoked.
    1634     * </p>
    1635     * <p>
    1636     * The default value is false.
    1637     * </p>
    1638     * <p>
    1639     * If set to true a connection is considered abandoned and eligible for removal if it has not been used for more
    1640     * than {@link #getRemoveAbandonedTimeout() removeAbandonedTimeout} seconds.
    1641     * </p>
    1642     * <p>
    1643     * Abandoned connections are identified and removed when {@link #getConnection()} is invoked and all of the
    1644     * following conditions hold:
    1645     * </p>
    1646     * <ul>
    1647     * <li>{@link #getRemoveAbandonedOnBorrow()}</li>
    1648     * <li>{@link #getNumActive()} &gt; {@link #getMaxTotal()} - 3</li>
    1649     * <li>{@link #getNumIdle()} &lt; 2</li>
    1650     * </ul>
    1651     *
    1652     * @see #getRemoveAbandonedTimeout()
    1653     */
    1654    @Override
    1655    public boolean getRemoveAbandonedOnBorrow() {
    1656        if (abandonedConfig != null) {
    1657            return abandonedConfig.getRemoveAbandonedOnBorrow();
    1658        }
    1659        return false;
    1660    }
    1661
    1662    /**
    1663     * @param removeAbandonedOnMaintenance
    1664     *            true means abandoned connections may be removed on pool maintenance.
    1665     * @see #getRemoveAbandonedOnMaintenance()
    1666     */
    1667    public void setRemoveAbandonedOnMaintenance(final boolean removeAbandonedOnMaintenance) {
    1668        if (abandonedConfig == null) {
    1669            abandonedConfig = new AbandonedConfig();
    1670        }
    1671        abandonedConfig.setRemoveAbandonedOnMaintenance(removeAbandonedOnMaintenance);
    1672        final GenericObjectPool<?> gop = this.connectionPool;
    1673        if (gop != null) {
    1674            gop.setAbandonedConfig(abandonedConfig);
    1675        }
    1676    }
    1677
    1678    /**
    1679     * <p>
    1680     * Flag to remove abandoned connections if they exceed the removeAbandonedTimeout during pool maintenance.
    1681     * </p>
    1682     *
    1683     * <p>
    1684     * The default value is false.
    1685     * </p>
    1686     *
    1687     * <p>
    1688     * If set to true a connection is considered abandoned and eligible for removal if it has not been used for more
    1689     * than {@link #getRemoveAbandonedTimeout() removeAbandonedTimeout} seconds.
    1690     * </p>
    1691     *
    1692     * @see #getRemoveAbandonedTimeout()
    1693     */
    1694    @Override
    1695    public boolean getRemoveAbandonedOnMaintenance() {
    1696        if (abandonedConfig != null) {
    1697            return abandonedConfig.getRemoveAbandonedOnMaintenance();
    1698        }
    1699        return false;
    1700    }
    1701
    1702    /**
    1703     * @param removeAbandonedOnBorrow
    1704     *            true means abandoned connections may be removed when connections are borrowed from the pool.
    1705     * @see #getRemoveAbandonedOnBorrow()
    1706     */
    1707    public void setRemoveAbandonedOnBorrow(final boolean removeAbandonedOnBorrow) {
    1708        if (abandonedConfig == null) {
    1709            abandonedConfig = new AbandonedConfig();
    1710        }
    1711        abandonedConfig.setRemoveAbandonedOnBorrow(removeAbandonedOnBorrow);
    1712        final GenericObjectPool<?> gop = this.connectionPool;
    1713        if (gop != null) {
    1714            gop.setAbandonedConfig(abandonedConfig);
    1715        }
    1716    }
    1717
    1718    /**
    1719     * <p>
    1720     * Timeout in seconds before an abandoned connection can be removed.
    1721     * </p>
    1722     * <p>
    1723     * Creating a Statement, PreparedStatement or CallableStatement or using one of these to execute a query (using one
    1724     * of the execute methods) resets the lastUsed property of the parent connection.
    1725     * </p>
    1726     * <p>
    1727     * Abandoned connection cleanup happens when:
    1728     * </p>
    1729     * <ul>
    1730     * <li>{@link #getRemoveAbandonedOnBorrow()} or {@link #getRemoveAbandonedOnMaintenance()} = true</li>
    1731     * <li>{@link #getNumIdle() numIdle} &lt; 2</li>
    1732     * <li>{@link #getNumActive() numActive} &gt; {@link #getMaxTotal() maxTotal} - 3</li>
    1733     * </ul>
    1734     * <p>
    1735     * The default value is 300 seconds.
    1736     * </p>
    1737     */
    1738    @Override
    1739    public int getRemoveAbandonedTimeout() {
    1740        if (abandonedConfig != null) {
    1741            return abandonedConfig.getRemoveAbandonedTimeout();
    1742        }
    1743        return 300;
    1744    }
    1745
    1746    /**
    1747     * <p>
    1748     * Sets the timeout in seconds before an abandoned connection can be removed.
    1749     * </p>
    1750     *
    1751     * <p>
    1752     * Setting this property has no effect if {@link #getRemoveAbandonedOnBorrow()} and
    1753     * {@link #getRemoveAbandonedOnMaintenance()} are false.
    1754     * </p>
    1755     *
    1756     * @param removeAbandonedTimeout
    1757     *            new abandoned timeout in seconds
    1758     * @see #getRemoveAbandonedTimeout()
    1759     * @see #getRemoveAbandonedOnBorrow()
    1760     * @see #getRemoveAbandonedOnMaintenance()
    1761     */
    1762    public void setRemoveAbandonedTimeout(final int removeAbandonedTimeout) {
    1763        if (abandonedConfig == null) {
    1764            abandonedConfig = new AbandonedConfig();
    1765        }
    1766        abandonedConfig.setRemoveAbandonedTimeout(removeAbandonedTimeout);
    1767        final GenericObjectPool<?> gop = this.connectionPool;
    1768        if (gop != null) {
    1769            gop.setAbandonedConfig(abandonedConfig);
    1770        }
    1771    }
    1772
    1773    /**
    1774     * <p>
    1775     * Flag to log stack traces for application code which abandoned a Statement or Connection.
    1776     * </p>
    1777     * <p>
    1778     * Defaults to false.
    1779     * </p>
    1780     * <p>
    1781     * Logging of abandoned Statements and Connections adds overhead for every Connection open or new Statement because
    1782     * a stack trace has to be generated.
    1783     * </p>
    1784     */
    1785    @Override
    1786    public boolean getLogAbandoned() {
    1787        if (abandonedConfig != null) {
    1788            return abandonedConfig.getLogAbandoned();
    1789        }
    1790        return false;
    1791    }
    1792
    1793    /**
    1794     * @param logAbandoned
    1795     *            new logAbandoned property value
    1796     */
    1797    public void setLogAbandoned(final boolean logAbandoned) {
    1798        if (abandonedConfig == null) {
    1799            abandonedConfig = new AbandonedConfig();
    1800        }
    1801        abandonedConfig.setLogAbandoned(logAbandoned);
    1802        final GenericObjectPool<?> gop = this.connectionPool;
    1803        if (gop != null) {
    1804            gop.setAbandonedConfig(abandonedConfig);
    1805        }
    1806    }
    1807
    1808    /**
    1809     * Gets the print writer used by this configuration to log information on abandoned objects.
    1810     *
    1811     * @return The print writer used by this configuration to log information on abandoned objects.
    1812     */
    1813    public PrintWriter getAbandonedLogWriter() {
    1814        if (abandonedConfig != null) {
    1815            return abandonedConfig.getLogWriter();
    1816        }
    1817        return null;
    1818    }
    1819
    1820    /**
    1821     * Sets the print writer to be used by this configuration to log information on abandoned objects.
    1822     *
    1823     * @param logWriter
    1824     *            The new log writer
    1825     */
    1826    public void setAbandonedLogWriter(final PrintWriter logWriter) {
    1827        if (abandonedConfig == null) {
    1828            abandonedConfig = new AbandonedConfig();
    1829        }
    1830        abandonedConfig.setLogWriter(logWriter);
    1831        final GenericObjectPool<?> gop = this.connectionPool;
    1832        if (gop != null) {
    1833            gop.setAbandonedConfig(abandonedConfig);
    1834        }
    1835    }
    1836
    1837    /**
    1838     * If the connection pool implements {@link org.apache.commons.pool2.UsageTracking UsageTracking}, should the
    1839     * connection pool record a stack trace every time a method is called on a pooled connection and retain the most
    1840     * recent stack trace to aid debugging of abandoned connections?
    1841     *
    1842     * @return <code>true</code> if usage tracking is enabled
    1843     */
    1844    @Override
    1845    public boolean getAbandonedUsageTracking() {
    1846        if (abandonedConfig != null) {
    1847            return abandonedConfig.getUseUsageTracking();
    1848        }
    1849        return false;
    1850    }
    1851
    1852    /**
    1853     * If the connection pool implements {@link org.apache.commons.pool2.UsageTracking UsageTracking}, configure whether
    1854     * the connection pool should record a stack trace every time a method is called on a pooled connection and retain
    1855     * the most recent stack trace to aid debugging of abandoned connections.
    1856     *
    1857     * @param usageTracking
    1858     *            A value of <code>true</code> will enable the recording of a stack trace on every use of a pooled
    1859     *            connection
    1860     */
    1861    public void setAbandonedUsageTracking(final boolean usageTracking) {
    1862        if (abandonedConfig == null) {
    1863            abandonedConfig = new AbandonedConfig();
    1864        }
    1865        abandonedConfig.setUseUsageTracking(usageTracking);
    1866        final GenericObjectPool<?> gop = this.connectionPool;
    1867        if (gop != null) {
    1868            gop.setAbandonedConfig(abandonedConfig);
    1869        }
    1870    }
    1871
    1872    /**
    1873     * Adds a custom connection property to the set that will be passed to our JDBC driver. This <strong>MUST</strong>
    1874     * be called before the first connection is retrieved (along with all the other configuration property setters).
    1875     * Calls to this method after the connection pool has been initialized have no effect.
    1876     *
    1877     * @param name
    1878     *            Name of the custom connection property
    1879     * @param value
    1880     *            Value of the custom connection property
    1881     */
    1882    public void addConnectionProperty(final String name, final String value) {
    1883        connectionProperties.put(name, value);
    1884    }
    1885
    1886    /**
    1887     * Removes a custom connection property.
    1888     *
    1889     * @param name
    1890     *            Name of the custom connection property to remove
    1891     * @see #addConnectionProperty(String, String)
    1892     */
    1893    public void removeConnectionProperty(final String name) {
    1894        connectionProperties.remove(name);
    1895    }
    1896
    1897    /**
    1898     * Sets the connection properties passed to driver.connect(...).
    1899     * <p>
    1900     * Format of the string must be [propertyName=property;]*
    1901     * </p>
    1902     * <p>
    1903     * NOTE - The "user" and "password" properties will be added explicitly, so they do not need to be included here.
    1904     * </p>
    1905     *
    1906     * @param connectionProperties
    1907     *            the connection properties used to create new connections
    1908     */
    1909    public void setConnectionProperties(final String connectionProperties) {
    1910        Objects.requireNonNull(connectionProperties, "connectionProperties is null");
    1911        final String[] entries = connectionProperties.split(";");
    1912        final Properties properties = new Properties();
    1913        for (final String entry : entries) {
    1914            if (entry.length() > 0) {
    1915                final int index = entry.indexOf('=');
    1916                if (index > 0) {
    1917                    final String name = entry.substring(0, index);
    1918                    final String value = entry.substring(index + 1);
    1919                    properties.setProperty(name, value);
    1920                } else {
    1921                    // no value is empty string which is how java.util.Properties works
    1922                    properties.setProperty(entry, "");
    1923                }
    1924            }
    1925        }
    1926        this.connectionProperties = properties;
    1927    }
    1928
    1929    private boolean closed;
    1930
    1931    /**
    1932     * <p>
    1933     * Closes and releases all idle connections that are currently stored in the connection pool associated with this
    1934     * data source.
    1935     * </p>
    1936     * <p>
    1937     * Connections that are checked out to clients when this method is invoked are not affected. When client
    1938     * applications subsequently invoke {@link Connection#close()} to return these connections to the pool, the
    1939     * underlying JDBC connections are closed.
    1940     * </p>
    1941     * <p>
    1942     * Attempts to acquire connections using {@link #getConnection()} after this method has been invoked result in
    1943     * SQLExceptions.
    1944     * </p>
    1945     * <p>
    1946     * This method is idempotent - i.e., closing an already closed BasicDataSource has no effect and does not generate
    1947     * exceptions.
    1948     * </p>
    1949     *
    1950     * @throws SQLException
    1951     *             if an error occurs closing idle connections
    1952     */
    1953    @Override
    1954    public synchronized void close() throws SQLException {
    1955        if (registeredJmxObjectName != null) {
    1956            registeredJmxObjectName.unregisterMBean();
    1957            registeredJmxObjectName = null;
    1958        }
    1959        closed = true;
    1960        final GenericObjectPool<?> oldpool = connectionPool;
    1961        connectionPool = null;
    1962        dataSource = null;
    1963        try {
    1964            if (oldpool != null) {
    1965                oldpool.close();
    1966            }
    1967        } catch (final RuntimeException e) {
    1968            throw e;
    1969        } catch (final Exception e) {
    1970            throw new SQLException(Utils.getMessage("pool.close.fail"), e);
    1971        }
    1972    }
    1973
    1974    /**
    1975     * If true, this data source is closed and no more connections can be retrieved from this datasource.
    1976     *
    1977     * @return true, if the data source is closed; false otherwise
    1978     */
    1979    @Override
    1980    public synchronized boolean isClosed() {
    1981        return closed;
    1982    }
    1983
    1984    @Override
    1985    public boolean isWrapperFor(final Class<?> iface) throws SQLException {
    1986        return false;
    1987    }
    1988
    1989    @Override
    1990    public <T> T unwrap(final Class<T> iface) throws SQLException {
    1991        throw new SQLException("BasicDataSource is not a wrapper.");
    1992    }
    1993
    1994    @Override
    1995    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
    1996        throw new SQLFeatureNotSupportedException();
    1997    }
    1998
    1999    /**
    2000     * Manually invalidates a connection, effectively requesting the pool to try to close it, remove it from the pool
    2001     * and reclaim pool capacity.
    2002     *
    2003     * @param connection
    2004     *            The Connection to invalidate.
    2005     *
    2006     * @throws IllegalStateException
    2007     *             if invalidating the connection failed.
    2008     * @since 2.1
    2009     */
    2010    public void invalidateConnection(final Connection connection) throws IllegalStateException {
    2011        if (connection == null) {
    2012            return;
    2013        }
    2014        if (connectionPool == null) {
    2015            throw new IllegalStateException("Cannot invalidate connection: ConnectionPool is null.");
    2016        }
    2017
    2018        final PoolableConnection poolableConnection;
    2019        try {
    2020            poolableConnection = connection.unwrap(PoolableConnection.class);
    2021            if (poolableConnection == null) {
    2022                throw new IllegalStateException(
    2023                        "Cannot invalidate connection: Connection is not a poolable connection.");
    2024            }
    2025        } catch (final SQLException e) {
    2026            throw new IllegalStateException("Cannot invalidate connection: Unwrapping poolable connection failed.", e);
    2027        }
    2028
    2029        try {
    2030            connectionPool.invalidateObject(poolableConnection);
    2031        } catch (final Exception e) {
    2032            throw new IllegalStateException("Invalidating connection threw unexpected exception", e);
    2033        }
    2034    }
    2035
    2036    // ------------------------------------------------------ Protected Methods
    2037
    2038    /**
    2039     * <p>
    2040     * Creates (if necessary) and return the internal data source we are using to manage our connections.
    2041     * </p>
    2042     *
    2043     * @throws SQLException
    2044     *             if the object pool cannot be created.
    2045     */
    2046    protected DataSource createDataSource() throws SQLException {
    2047        if (closed) {
    2048            throw new SQLException("Data source is closed");
    2049        }
    2050
    2051        // Return the pool if we have already created it
    2052        // This is double-checked locking. This is safe since dataSource is
    2053        // volatile and the code is targeted at Java 5 onwards.
    2054        if (dataSource != null) {
    2055            return dataSource;
    2056        }
    2057        synchronized (this) {
    2058            if (dataSource != null) {
    2059                return dataSource;
    2060            }
    2061
    2062            jmxRegister();
    2063
    2064            // create factory which returns raw physical connections
    2065            final ConnectionFactory driverConnectionFactory = createConnectionFactory();
    2066
    2067            // Set up the poolable connection factory
    2068            boolean success = false;
    2069            PoolableConnectionFactory poolableConnectionFactory;
    2070            try {
    2071                poolableConnectionFactory = createPoolableConnectionFactory(driverConnectionFactory);
    2072                poolableConnectionFactory.setPoolStatements(poolPreparedStatements);
    2073                poolableConnectionFactory.setMaxOpenPreparedStatements(maxOpenPreparedStatements);
    2074                success = true;
    2075            } catch (final SQLException se) {
    2076                throw se;
    2077            } catch (final RuntimeException rte) {
    2078                throw rte;
    2079            } catch (final Exception ex) {
    2080                throw new SQLException("Error creating connection factory", ex);
    2081            }
    2082
    2083            if (success) {
    2084                // create a pool for our connections
    2085                createConnectionPool(poolableConnectionFactory);
    2086            }
    2087
    2088            // Create the pooling data source to manage connections
    2089            DataSource newDataSource;
    2090            success = false;
    2091            try {
    2092                newDataSource = createDataSourceInstance();
    2093                newDataSource.setLogWriter(logWriter);
    2094                success = true;
    2095            } catch (final SQLException se) {
    2096                throw se;
    2097            } catch (final RuntimeException rte) {
    2098                throw rte;
    2099            } catch (final Exception ex) {
    2100                throw new SQLException("Error creating datasource", ex);
    2101            } finally {
    2102                if (!success) {
    2103                    closeConnectionPool();
    2104                }
    2105            }
    2106
    2107            // If initialSize > 0, preload the pool
    2108            try {
    2109                for (int i = 0; i < initialSize; i++) {
    2110                    connectionPool.addObject();
    2111                }
    2112            } catch (final Exception e) {
    2113                closeConnectionPool();
    2114                throw new SQLException("Error preloading the connection pool", e);
    2115            }
    2116
    2117            // If timeBetweenEvictionRunsMillis > 0, start the pool's evictor task
    2118            startPoolMaintenance();
    2119
    2120            dataSource = newDataSource;
    2121            return dataSource;
    2122        }
    2123    }
    2124
    2125    /**
    2126     * Creates a JDBC connection factory for this datasource. The JDBC driver is loaded using the following algorithm:
    2127     * <ol>
    2128     * <li>If a Driver instance has been specified via {@link #setDriver(Driver)} use it</li>
    2129     * <li>If no Driver instance was specified and {@link #driverClassName} is specified that class is loaded using the
    2130     * {@link ClassLoader} of this class or, if {@link #driverClassLoader} is set, {@link #driverClassName} is loaded
    2131     * with the specified {@link ClassLoader}.</li>
    2132     * <li>If {@link #driverClassName} is specified and the previous attempt fails, the class is loaded using the
    2133     * context class loader of the current thread.</li>
    2134     * <li>If a driver still isn't loaded one is loaded via the {@link DriverManager} using the specified {@link #url}.
    2135     * </ol>
    2136     * This method exists so subclasses can replace the implementation class.
    2137     */
    2138    protected ConnectionFactory createConnectionFactory() throws SQLException {
    2139        // Load the JDBC driver class
    2140        Driver driverToUse = this.driver;
    2141
    2142        if (driverToUse == null) {
    2143            Class<?> driverFromCCL = null;
    2144            if (driverClassName != null) {
    2145                try {
    2146                    try {
    2147                        if (driverClassLoader == null) {
    2148                            driverFromCCL = Class.forName(driverClassName);
    2149                        } else {
    2150                            driverFromCCL = Class.forName(driverClassName, true, driverClassLoader);
    2151                        }
    2152                    } catch (final ClassNotFoundException cnfe) {
    2153                        driverFromCCL = Thread.currentThread().getContextClassLoader().loadClass(driverClassName);
    2154                    }
    2155                } catch (final Exception t) {
    2156                    final String message = "Cannot load JDBC driver class '" + driverClassName + "'";
    2157                    logWriter.println(message);
    2158                    t.printStackTrace(logWriter);
    2159                    throw new SQLException(message, t);
    2160                }
    2161            }
    2162
    2163            try {
    2164                if (driverFromCCL == null) {
    2165                    driverToUse = DriverManager.getDriver(url);
    2166                } else {
    2167                    // Usage of DriverManager is not possible, as it does not
    2168                    // respect the ContextClassLoader
    2169                    // N.B. This cast may cause ClassCastException which is handled below
    2170                    driverToUse = (Driver) driverFromCCL.getConstructor().newInstance();
    2171                    if (!driverToUse.acceptsURL(url)) {
    2172                        throw new SQLException("No suitable driver", "08001");
    2173                    }
    2174                }
    2175            } catch (final Exception t) {
    2176                final String message = "Cannot create JDBC driver of class '"
    2177                        + (driverClassName != null ? driverClassName : "") + "' for connect URL '" + url + "'";
    2178                logWriter.println(message);
    2179                t.printStackTrace(logWriter);
    2180                throw new SQLException(message, t);
    2181            }
    2182        }
    2183
    2184        // Set up the driver connection factory we will use
    2185        final String user = userName;
    2186        if (user != null) {
    2187            connectionProperties.put("user", user);
    2188        } else {
    2189            log("DBCP DataSource configured without a 'username'");
    2190        }
    2191
    2192        final String pwd = password;
    2193        if (pwd != null) {
    2194            connectionProperties.put("password", pwd);
    2195        } else {
    2196            log("DBCP DataSource configured without a 'password'");
    2197        }
    2198
    2199        final ConnectionFactory driverConnectionFactory = new DriverConnectionFactory(driverToUse, url,
    2200                connectionProperties);
    2201        return driverConnectionFactory;
    2202    }
    2203
    2204    /**
    2205     * Creates a connection pool for this datasource. This method only exists so subclasses can replace the
    2206     * implementation class.
    2207     * <p>
    2208     * This implementation configures all pool properties other than timeBetweenEvictionRunsMillis. Setting that
    2209     * property is deferred to {@link #startPoolMaintenance()}, since setting timeBetweenEvictionRunsMillis to a
    2210     * positive value causes {@link GenericObjectPool}'s eviction timer to be started.
    2211     * </p>
    2212     */
    2213    protected void createConnectionPool(final PoolableConnectionFactory factory) {
    2214        // Create an object pool to contain our active connections
    2215        final GenericObjectPoolConfig config = new GenericObjectPoolConfig();
    2216        updateJmxName(config);
    2217        // Disable JMX on the underlying pool if the DS is not registered:
    2218        config.setJmxEnabled(registeredJmxObjectName != null);
    2219        final GenericObjectPool<PoolableConnection> gop = createObjectPool(factory, config, abandonedConfig);
    2220        gop.setMaxTotal(maxTotal);
    2221        gop.setMaxIdle(maxIdle);
    2222        gop.setMinIdle(minIdle);
    2223        gop.setMaxWaitMillis(maxWaitMillis);
    2224        gop.setTestOnCreate(testOnCreate);
    2225        gop.setTestOnBorrow(testOnBorrow);
    2226        gop.setTestOnReturn(testOnReturn);
    2227        gop.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
    2228        gop.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
    2229        gop.setSoftMinEvictableIdleTimeMillis(softMinEvictableIdleTimeMillis);
    2230        gop.setTestWhileIdle(testWhileIdle);
    2231        gop.setLifo(lifo);
    2232        gop.setSwallowedExceptionListener(new SwallowedExceptionLogger(log, logExpiredConnections));
    2233        gop.setEvictionPolicyClassName(evictionPolicyClassName);
    2234        factory.setPool(gop);
    2235        connectionPool = gop;
    2236    }
    2237
    2238    /**
    2239     * Creates an object pool used to provide pooling support for {@link Connection JDBC connections}.
    2240     *
    2241     * @param factory
    2242     *            the object factory
    2243     * @param poolConfig
    2244     *            the object pool configuration
    2245     * @param abandonedConfig
    2246     *            the abandoned objects configuration
    2247     * @return a non-null instance
    2248     */
    2249    protected GenericObjectPool<PoolableConnection> createObjectPool(final PoolableConnectionFactory factory,
    2250            final GenericObjectPoolConfig poolConfig, final AbandonedConfig abandonedConfig) {
    2251        GenericObjectPool<PoolableConnection> gop;
    2252        if (abandonedConfig != null && (abandonedConfig.getRemoveAbandonedOnBorrow()
    2253                || abandonedConfig.getRemoveAbandonedOnMaintenance())) {
    2254            gop = new GenericObjectPool<>(factory, poolConfig, abandonedConfig);
    2255        } else {
    2256            gop = new GenericObjectPool<>(factory, poolConfig);
    2257        }
    2258        return gop;
    2259    }
    2260
    2261    /**
    2262     * Closes the connection pool, silently swallowing any exception that occurs.
    2263     */
    2264    private void closeConnectionPool() {
    2265        final GenericObjectPool<?> oldpool = connectionPool;
    2266        connectionPool = null;
    2267        try {
    2268            if (oldpool != null) {
    2269                oldpool.close();
    2270            }
    2271        } catch (final Exception e) {
    2272            /* Ignore */
    2273        }
    2274    }
    2275
    2276    /**
    2277     * Starts the connection pool maintenance task, if configured.
    2278     */
    2279    protected void startPoolMaintenance() {
    2280        if (connectionPool != null && timeBetweenEvictionRunsMillis > 0) {
    2281            connectionPool.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
    2282        }
    2283    }
    2284
    2285    /**
    2286     * Creates the actual data source instance. This method only exists so that subclasses can replace the
    2287     * implementation class.
    2288     *
    2289     * @throws SQLException
    2290     *             if unable to create a datasource instance
    2291     */
    2292    protected DataSource createDataSourceInstance() throws SQLException {
    2293        final PoolingDataSource<PoolableConnection> pds = new PoolingDataSource<>(connectionPool);
    2294        pds.setAccessToUnderlyingConnectionAllowed(isAccessToUnderlyingConnectionAllowed());
    2295        return pds;
    2296    }
    2297
    2298    /**
    2299     * Creates the PoolableConnectionFactory and attaches it to the connection pool. This method only exists so
    2300     * subclasses can replace the default implementation.
    2301     *
    2302     * @param driverConnectionFactory
    2303     *            JDBC connection factory
    2304     * @throws SQLException
    2305     *             if an error occurs creating the PoolableConnectionFactory
    2306     */
    2307    protected PoolableConnectionFactory createPoolableConnectionFactory(final ConnectionFactory driverConnectionFactory)
    2308            throws SQLException {
    2309        PoolableConnectionFactory connectionFactory = null;
    2310        try {
    2311            connectionFactory = new PoolableConnectionFactory(driverConnectionFactory,
    2312                    ObjectNameWrapper.unwrap(registeredJmxObjectName));
    2313            connectionFactory.setValidationQuery(validationQuery);
    2314            connectionFactory.setValidationQueryTimeout(validationQueryTimeoutSeconds);
    2315            connectionFactory.setConnectionInitSql(connectionInitSqls);
    2316            connectionFactory.setDefaultReadOnly(defaultReadOnly);
    2317            connectionFactory.setDefaultAutoCommit(defaultAutoCommit);
    2318            connectionFactory.setDefaultTransactionIsolation(defaultTransactionIsolation);
    2319            connectionFactory.setDefaultCatalog(defaultCatalog);
    2320            connectionFactory.setCacheState(cacheState);
    2321            connectionFactory.setPoolStatements(poolPreparedStatements);
    2322            connectionFactory.setMaxOpenPreparedStatements(maxOpenPreparedStatements);
    2323            connectionFactory.setMaxConnLifetimeMillis(maxConnLifetimeMillis);
    2324            connectionFactory.setRollbackOnReturn(getRollbackOnReturn());
    2325            connectionFactory.setEnableAutoCommitOnReturn(getEnableAutoCommitOnReturn());
    2326            connectionFactory.setDefaultQueryTimeout(getDefaultQueryTimeout());
    2327            connectionFactory.setFastFailValidation(fastFailValidation);
    2328            connectionFactory.setDisconnectionSqlCodes(disconnectionSqlCodes);
    2329            validateConnectionFactory(connectionFactory);
    2330        } catch (final RuntimeException e) {
    2331            throw e;
    2332        } catch (final Exception e) {
    2333            throw new SQLException("Cannot create PoolableConnectionFactory (" + e.getMessage() + ")", e);
    2334        }
    2335        return connectionFactory;
    2336    }
    2337
    2338    protected static void validateConnectionFactory(final PoolableConnectionFactory connectionFactory)
    2339            throws Exception {
    2340        PoolableConnection conn = null;
    2341        PooledObject<PoolableConnection> p = null;
    2342        try {
    2343            p = connectionFactory.makeObject();
    2344            conn = p.getObject();
    2345            connectionFactory.activateObject(p);
    2346            connectionFactory.validateConnection(conn);
    2347            connectionFactory.passivateObject(p);
    2348        } finally {
    2349            if (p != null) {
    2350                connectionFactory.destroyObject(p);
    2351            }
    2352        }
    2353    }
    2354
    2355    protected void log(final String message) {
    2356        if (logWriter != null) {
    2357            logWriter.println(message);
    2358        }
    2359    }
    2360
    2361    /**
    2362     * Actual name under which this component has been registered.
    2363     */
    2364    private ObjectNameWrapper registeredJmxObjectName;
    2365
    2366    private void jmxRegister() {
    2367        // Return immediately if this DataSource has already been registered
    2368        if (registeredJmxObjectName != null) {
    2369            return;
    2370        }
    2371        // Return immediately if no JMX name has been specified
    2372        final String requestedName = getJmxName();
    2373        if (requestedName == null) {
    2374            return;
    2375        }
    2376        try {
    2377            ObjectNameWrapper.wrap(requestedName).registerMBean(this);
    2378        } catch (final MalformedObjectNameException e) {
    2379            log.warn("The requested JMX name [" + requestedName + "] was not valid and will be ignored.");
    2380        }
    2381    }
    2382
    2383    @Override
    2384    public ObjectName preRegister(final MBeanServer server, final ObjectName objectName) {
    2385        final String requestedName = getJmxName();
    2386        if (requestedName != null) {
    2387            try {
    2388                registeredJmxObjectName = ObjectNameWrapper.wrap(requestedName);
    2389            } catch (final MalformedObjectNameException e) {
    2390                log.warn("The requested JMX name [" + requestedName + "] was not valid and will be ignored.");
    2391            }
    2392        }
    2393        if (registeredJmxObjectName == null) {
    2394            registeredJmxObjectName = ObjectNameWrapper.wrap(objectName);
    2395        }
    2396        return ObjectNameWrapper.unwrap(registeredJmxObjectName);
    2397    }
    2398
    2399    @Override
    2400    public void postRegister(final Boolean registrationDone) {
    2401        // NO-OP
    2402    }
    2403
    2404    @Override
    2405    public void preDeregister() throws Exception {
    2406        // NO-OP
    2407    }
    2408
    2409    @Override
    2410    public void postDeregister() {
    2411        // NO-OP
    2412    }
    2413
    2414    private void updateJmxName(final GenericObjectPoolConfig config) {
    2415        if (registeredJmxObjectName == null) {
    2416            return;
    2417        }
    2418        final StringBuilder base = new StringBuilder(registeredJmxObjectName.toString());
    2419        base.append(Constants.JMX_CONNECTION_POOL_BASE_EXT);
    2420        config.setJmxNameBase(base.toString());
    2421        config.setJmxNamePrefix(Constants.JMX_CONNECTION_POOL_PREFIX);
    2422    }
    2423
    2424    protected ObjectName getRegisteredJmxName() {
    2425        return ObjectNameWrapper.unwrap(registeredJmxObjectName);
    2426    }
    2427
    2428    /**
    2429     * @since 2.0
    2430     */
    2431    private class PaGetConnection implements PrivilegedExceptionAction<Connection> {
    2432
    2433        @Override
    2434        public Connection run() throws SQLException {
    2435            return createDataSource().getConnection();
    2436        }
    2437    }
    2438}