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