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