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