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