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