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.datasources;
18  
19  import java.io.OutputStreamWriter;
20  import java.io.PrintWriter;
21  import java.io.Serializable;
22  import java.nio.charset.StandardCharsets;
23  import java.sql.Connection;
24  import java.sql.SQLException;
25  import java.sql.SQLFeatureNotSupportedException;
26  import java.time.Duration;
27  import java.util.Properties;
28  import java.util.logging.Logger;
29  
30  import javax.naming.Context;
31  import javax.naming.InitialContext;
32  import javax.naming.Referenceable;
33  import javax.sql.ConnectionPoolDataSource;
34  import javax.sql.DataSource;
35  import javax.sql.PooledConnection;
36  
37  import org.apache.commons.dbcp2.Utils;
38  import org.apache.commons.pool2.impl.BaseObjectPoolConfig;
39  import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;
40  import org.apache.commons.pool2.impl.GenericObjectPool;
41  
42  /**
43   * <p>
44   * The base class for {@link SharedPoolDataSource} and {@link PerUserPoolDataSource}. Many of the
45   * configuration properties are shared and defined here. This class is declared public in order to allow particular
46   * usage with commons-beanutils; do not make direct use of it outside of <em>commons-dbcp2</em>.
47   * </p>
48   *
49   * <p>
50   * A J2EE container will normally provide some method of initializing the {@link DataSource} whose attributes are
51   * presented as bean getters/setters and then deploying it via JNDI. It is then available to an application as a source
52   * of pooled logical connections to the database. The pool needs a source of physical connections. This source is in the
53   * form of a {@link ConnectionPoolDataSource} that can be specified via the {@link #setDataSourceName(String)} used
54   * to lookup the source via JNDI.
55   * </p>
56   *
57   * <p>
58   * Although normally used within a JNDI environment, A DataSource can be instantiated and initialized as any bean. In
59   * this case the {@link ConnectionPoolDataSource} will likely be instantiated in a similar manner. This class
60   * allows the physical source of connections to be attached directly to this pool using the
61   * {@link #setConnectionPoolDataSource(ConnectionPoolDataSource)} method.
62   * </p>
63   *
64   * <p>
65   * The dbcp package contains an adapter, {@link org.apache.commons.dbcp2.cpdsadapter.DriverAdapterCPDS}, that can be
66   * used to allow the use of {@link DataSource}'s based on this class with JDBC driver implementations that do not
67   * supply a {@link ConnectionPoolDataSource}, but still provide a {@link java.sql.Driver} implementation.
68   * </p>
69   *
70   * <p>
71   * The <a href="package-summary.html">package documentation</a> contains an example using Apache Tomcat and JNDI and it
72   * also contains a non-JNDI example.
73   * </p>
74   *
75   * @since 2.0
76   */
77  public abstract class InstanceKeyDataSource implements DataSource, Referenceable, Serializable, AutoCloseable {
78  
79      private static final long serialVersionUID = -6819270431752240878L;
80  
81      private static final String GET_CONNECTION_CALLED = "A Connection was already requested from this source, "
82              + "further initialization is not allowed.";
83      private static final String BAD_TRANSACTION_ISOLATION = "The requested TransactionIsolation level is invalid.";
84  
85      /**
86       * Internal constant to indicate the level is not set.
87       */
88      protected static final int UNKNOWN_TRANSACTIONISOLATION = -1;
89  
90      /** Guards property setters - once true, setters throw IllegalStateException */
91      private volatile boolean getConnectionCalled;
92  
93      /** Underlying source of PooledConnections */
94      private ConnectionPoolDataSource dataSource;
95  
96      /** DataSource Name used to find the ConnectionPoolDataSource */
97      private String dataSourceName;
98  
99      /** Description */
100     private String description;
101 
102     /** Environment that may be used to set up a JNDI initial context. */
103     private Properties jndiEnvironment;
104 
105     /** Login Timeout */
106     private Duration loginTimeoutDuration = Duration.ZERO;
107 
108     /** Log stream */
109     private PrintWriter logWriter;
110 
111     /** Instance key */
112     private String instanceKey;
113 
114     /** Pool property defaults to {@link BaseObjectPoolConfig#DEFAULT_BLOCK_WHEN_EXHAUSTED}. */
115     private volatile boolean defaultBlockWhenExhausted = BaseObjectPoolConfig.DEFAULT_BLOCK_WHEN_EXHAUSTED;
116 
117     /** Pool property defaults to {@link BaseObjectPoolConfig#DEFAULT_EVICTION_POLICY_CLASS_NAME}. */
118     private String defaultEvictionPolicyClassName = BaseObjectPoolConfig.DEFAULT_EVICTION_POLICY_CLASS_NAME;
119 
120     /** Pool property defaults to {@link BaseObjectPoolConfig#DEFAULT_LIFO}. */
121     private volatile boolean defaultLifo = BaseObjectPoolConfig.DEFAULT_LIFO;
122 
123     /** Pool property defaults to {@link GenericKeyedObjectPoolConfig#DEFAULT_MAX_IDLE_PER_KEY}. */
124     private volatile int defaultMaxIdle = GenericKeyedObjectPoolConfig.DEFAULT_MAX_IDLE_PER_KEY;
125 
126     /** Pool property defaults to {@link GenericKeyedObjectPoolConfig#DEFAULT_MAX_TOTAL}. */
127     private volatile int defaultMaxTotal = GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL;
128 
129     /** Pool property defaults to {@link BaseObjectPoolConfig#DEFAULT_MAX_WAIT}. */
130     private Duration defaultMaxWaitDuration = BaseObjectPoolConfig.DEFAULT_MAX_WAIT;
131 
132     /** Pool property defaults to {@link BaseObjectPoolConfig#DEFAULT_MIN_EVICTABLE_IDLE_DURATION}. */
133     private Duration defaultMinEvictableIdleDuration = BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_DURATION;
134 
135     /** Pool property defaults to {@link GenericKeyedObjectPoolConfig#DEFAULT_MIN_IDLE_PER_KEY}. */
136     private volatile int defaultMinIdle = GenericKeyedObjectPoolConfig.DEFAULT_MIN_IDLE_PER_KEY;
137 
138     /** Pool property defaults to {@link BaseObjectPoolConfig#DEFAULT_NUM_TESTS_PER_EVICTION_RUN}. */
139     private volatile int defaultNumTestsPerEvictionRun = BaseObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
140 
141     /** Pool property defaults to {@link BaseObjectPoolConfig#DEFAULT_SOFT_MIN_EVICTABLE_IDLE_DURATION}. */
142     private Duration defaultSoftMinEvictableIdleDuration = BaseObjectPoolConfig.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_DURATION;
143 
144     /** Pool property defaults to {@link BaseObjectPoolConfig#DEFAULT_TEST_ON_CREATE}. */
145     private volatile boolean defaultTestOnCreate = BaseObjectPoolConfig.DEFAULT_TEST_ON_CREATE;
146 
147     /** Pool property defaults to {@link BaseObjectPoolConfig#DEFAULT_TEST_ON_BORROW}. */
148     private volatile boolean defaultTestOnBorrow = BaseObjectPoolConfig.DEFAULT_TEST_ON_BORROW;
149 
150     /** Pool property defaults to {@link BaseObjectPoolConfig#DEFAULT_TEST_ON_RETURN}. */
151     private volatile boolean defaultTestOnReturn = BaseObjectPoolConfig.DEFAULT_TEST_ON_RETURN;
152 
153     /** Pool property defaults to {@link BaseObjectPoolConfig#DEFAULT_TEST_WHILE_IDLE}. */
154     private volatile boolean defaultTestWhileIdle = BaseObjectPoolConfig.DEFAULT_TEST_WHILE_IDLE;
155 
156     /** Pool property defaults to {@link BaseObjectPoolConfig#DEFAULT_DURATION_BETWEEN_EVICTION_RUNS}. */
157     private Duration defaultDurationBetweenEvictionRuns = BaseObjectPoolConfig.DEFAULT_DURATION_BETWEEN_EVICTION_RUNS;
158 
159     /** Connection factory property defaults to null. */
160     private String validationQuery;
161 
162     /** Connection factory property defaults to -1 seconds. */
163     private Duration validationQueryTimeoutDuration = Duration.ofSeconds(-1);
164 
165     /** Connection factory property defaults to false. */
166     private volatile boolean rollbackAfterValidation;
167 
168     /** Connection factory property defaults to -1 milliseconds. */
169     private Duration maxConnDuration = Duration.ofMillis(-1);
170 
171     /** Connection property defaults to false. */
172     private Boolean defaultAutoCommit;
173 
174     /** Connection property defaults to {@link #UNKNOWN_TRANSACTIONISOLATION}. */
175     private volatile int defaultTransactionIsolation = UNKNOWN_TRANSACTIONISOLATION;
176 
177     /** Connection property defaults to false. */
178     private Boolean defaultReadOnly;
179 
180     /**
181      * Default no-arg constructor for Serialization.
182      */
183     public InstanceKeyDataSource() {
184     }
185 
186     /**
187      * Throws an IllegalStateException, if a PooledConnection has already been requested.
188      *
189      * @throws IllegalStateException Thrown if a PooledConnection has already been requested.
190      */
191     protected void assertInitializationAllowed() throws IllegalStateException {
192         if (getConnectionCalled) {
193             throw new IllegalStateException(GET_CONNECTION_CALLED);
194         }
195     }
196 
197     /**
198      * Closes the connection pool being maintained by this datasource.
199      */
200     @Override
201     public abstract void close() throws SQLException;
202 
203     private void closeDueToException(final PooledConnectionAndInfo info) {
204         if (info != null) {
205             try {
206                 info.getPooledConnection().getConnection().close();
207             } catch (final Exception e) {
208                 // do not throw this exception because we are in the middle
209                 // of handling another exception. But record it because
210                 // it potentially leaks connections from the pool.
211                 getLogWriter().println("[ERROR] Could not return connection to pool during exception handling. " + e.getMessage());
212             }
213         }
214     }
215 
216     /**
217      * Attempts to establish a database connection.
218      */
219     @Override
220     public Connection getConnection() throws SQLException {
221         return getConnection(null, null);
222     }
223 
224     /**
225      * Attempts to retrieve a database connection using {@link #getPooledConnectionAndInfo(String, String)} with the
226      * provided user name and password. The password on the {@code PooledConnectionAndInfo} instance returned by
227      * {@code getPooledConnectionAndInfo} is compared to the {@code password} parameter. If the comparison
228      * fails, a database connection using the supplied user name and password is attempted. If the connection attempt
229      * fails, an SQLException is thrown, indicating that the given password did not match the password used to create
230      * the pooled connection. If the connection attempt succeeds, this means that the database password has been
231      * changed. In this case, the {@code PooledConnectionAndInfo} instance retrieved with the old password is
232      * destroyed and the {@code getPooledConnectionAndInfo} is repeatedly invoked until a
233      * {@code PooledConnectionAndInfo} instance with the new password is returned.
234      */
235     @Override
236     public Connection getConnection(final String userName, final String userPassword) throws SQLException {
237         if (instanceKey == null) {
238             throw new SQLException("Must set the ConnectionPoolDataSource "
239                     + "through setDataSourceName or setConnectionPoolDataSource before calling getConnection.");
240         }
241         getConnectionCalled = true;
242         PooledConnectionAndInfo info = null;
243         try {
244             info = getPooledConnectionAndInfo(userName, userPassword);
245         } catch (final RuntimeException | SQLException e) {
246             closeDueToException(info);
247             throw e;
248         } catch (final Exception e) {
249             closeDueToException(info);
250             throw new SQLException("Cannot borrow connection from pool", e);
251         }
252 
253         // Password on PooledConnectionAndInfo does not match
254         if (!(null == userPassword ? null == info.getPassword() : userPassword.equals(info.getPassword()))) {
255             try { // See if password has changed by attempting connection
256                 testCPDS(userName, userPassword);
257             } catch (final SQLException ex) {
258                 // Password has not changed, so refuse client, but return connection to the pool
259                 closeDueToException(info);
260                 throw new SQLException(
261                         "Given password did not match password used to create the PooledConnection.", ex);
262             } catch (final javax.naming.NamingException ne) {
263                 throw new SQLException("NamingException encountered connecting to database", ne);
264             }
265             /*
266              * Password must have changed -> destroy connection and keep retrying until we get a new, good one,
267              * destroying any idle connections with the old password as we pull them from the pool.
268              */
269             final UserPassKey upkey = info.getUserPassKey();
270             final PooledConnectionManager manager = getConnectionManager(upkey);
271             // Destroy and remove from pool
272             manager.invalidate(info.getPooledConnection());
273             // Reset the password on the factory if using CPDSConnectionFactory
274             manager.setPassword(upkey.getPasswordCharArray());
275             info = null;
276             for (int i = 0; i < 10; i++) { // Bound the number of retries - only needed if bad instances return
277                 try {
278                     info = getPooledConnectionAndInfo(userName, userPassword);
279                 } catch (final RuntimeException | SQLException e) {
280                     closeDueToException(info);
281                     throw e;
282                 } catch (final Exception e) {
283                     closeDueToException(info);
284                     throw new SQLException("Cannot borrow connection from pool", e);
285                 }
286                 if (info != null && userPassword != null && userPassword.equals(info.getPassword())) {
287                     break;
288                 }
289                 if (info != null) {
290                     manager.invalidate(info.getPooledConnection());
291                 }
292                 info = null;
293             }
294             if (info == null) {
295                 throw new SQLException("Cannot borrow connection from pool - password change failure.");
296             }
297         }
298 
299         final Connection connection = info.getPooledConnection().getConnection();
300         try {
301             setupDefaults(connection, userName);
302             connection.clearWarnings();
303             return connection;
304         } catch (final SQLException ex) {
305             Utils.close(connection, e -> getLogWriter().println("ignoring exception during close: " + e));
306             throw ex;
307         }
308     }
309 
310     /**
311      * Gets the pooled connection manager for the given key.
312      *
313      * @param upkey the key.
314      * @return the pooled connection manager for the given key.
315      */
316     protected abstract PooledConnectionManager getConnectionManager(UserPassKey upkey);
317 
318     /**
319      * Gets the value of connectionPoolDataSource. This method will return null, if the backing data source is being
320      * accessed via JNDI.
321      *
322      * @return value of connectionPoolDataSource.
323      */
324     public ConnectionPoolDataSource getConnectionPoolDataSource() {
325         return dataSource;
326     }
327 
328     /**
329      * Gets the name of the ConnectionPoolDataSource which backs this pool. This name is used to look up the data source
330      * from a JNDI service provider.
331      *
332      * @return value of dataSourceName.
333      */
334     public String getDataSourceName() {
335         return dataSourceName;
336     }
337 
338     /**
339      * Gets the default value for {@link GenericKeyedObjectPoolConfig#getBlockWhenExhausted()} for each per user pool.
340      *
341      * @return The default value for {@link GenericKeyedObjectPoolConfig#getBlockWhenExhausted()} for each per user
342      *         pool.
343      */
344     public boolean getDefaultBlockWhenExhausted() {
345         return this.defaultBlockWhenExhausted;
346     }
347 
348     /**
349      * Gets the default value for {@link GenericObjectPool#getDurationBetweenEvictionRuns()} for each per user pool.
350      *
351      * @return The default value for {@link GenericObjectPool#getDurationBetweenEvictionRuns()} for each per user pool.
352      * @since 2.10.0
353      */
354     public Duration getDefaultDurationBetweenEvictionRuns() {
355         return this.defaultDurationBetweenEvictionRuns;
356     }
357 
358     /**
359      * Gets the default value for {@link GenericKeyedObjectPoolConfig#getEvictionPolicyClassName()} for each per user
360      * pool.
361      *
362      * @return The default value for {@link GenericKeyedObjectPoolConfig#getEvictionPolicyClassName()} for each per user
363      *         pool.
364      */
365     public String getDefaultEvictionPolicyClassName() {
366         return this.defaultEvictionPolicyClassName;
367     }
368 
369     /**
370      * Gets the default value for {@link GenericKeyedObjectPoolConfig#getLifo()} for each per user pool.
371      *
372      * @return The default value for {@link GenericKeyedObjectPoolConfig#getLifo()} for each per user pool.
373      */
374     public boolean getDefaultLifo() {
375         return this.defaultLifo;
376     }
377 
378     /**
379      * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMaxIdlePerKey()} for each per user pool.
380      *
381      * @return The default value for {@link GenericKeyedObjectPoolConfig#getMaxIdlePerKey()} for each per user pool.
382      */
383     public int getDefaultMaxIdle() {
384         return this.defaultMaxIdle;
385     }
386 
387     /**
388      * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMaxTotalPerKey()} for each per user pool.
389      *
390      * @return The default value for {@link GenericKeyedObjectPoolConfig#getMaxTotalPerKey()} for each per user pool.
391      */
392     public int getDefaultMaxTotal() {
393         return this.defaultMaxTotal;
394     }
395 
396     /**
397      * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitDuration()} for each per user pool.
398      *
399      * @return The default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitDuration()} for each per user pool.
400      * @since 2.9.0
401      */
402     public Duration getDefaultMaxWait() {
403         return this.defaultMaxWaitDuration;
404     }
405 
406     /**
407      * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitDuration()} for each per user pool.
408      *
409      * @return The default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitDuration()} for each per user pool.
410      * @deprecated Use {@link #getDefaultMaxWait()}.
411      */
412     @Deprecated
413     public long getDefaultMaxWaitMillis() {
414         return getDefaultMaxWait().toMillis();
415     }
416 
417     /**
418      * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleDuration()} for each per user
419      * pool.
420      *
421      * @return The default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleDuration()} for each per
422      *         user pool.
423      * @since 2.10.0
424      */
425     public Duration getDefaultMinEvictableIdleDuration() {
426         return this.defaultMinEvictableIdleDuration;
427     }
428 
429     /**
430      * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleDuration()} for each per user
431      * pool.
432      *
433      * @return The default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleDuration()} for each per
434      *         user pool.
435      * @deprecated Use {@link #getDefaultMinEvictableIdleDuration()}.
436      */
437     @Deprecated
438     public long getDefaultMinEvictableIdleTimeMillis() {
439         return this.defaultMinEvictableIdleDuration.toMillis();
440     }
441 
442     /**
443      * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMinIdlePerKey()} for each per user pool.
444      *
445      * @return The default value for {@link GenericKeyedObjectPoolConfig#getMinIdlePerKey()} for each per user pool.
446      */
447     public int getDefaultMinIdle() {
448         return this.defaultMinIdle;
449     }
450 
451     /**
452      * Gets the default value for {@link GenericKeyedObjectPoolConfig#getNumTestsPerEvictionRun()} for each per user
453      * pool.
454      *
455      * @return The default value for {@link GenericKeyedObjectPoolConfig#getNumTestsPerEvictionRun()} for each per user
456      *         pool.
457      */
458     public int getDefaultNumTestsPerEvictionRun() {
459         return this.defaultNumTestsPerEvictionRun;
460     }
461 
462     /**
463      * Gets the default value for {@link
464      * GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool.
465      *
466      * @return The default value for {@link
467      *         GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool.
468      * @since 2.10.0
469      */
470     public Duration getDefaultSoftMinEvictableIdleDuration() {
471         return this.defaultSoftMinEvictableIdleDuration;
472     }
473 
474     /**
475      * Gets the default value for {@link
476      * GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool.
477      *
478      * @return The default value for {@link
479      *         GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool.
480      * @deprecated Use {@link #getDefaultSoftMinEvictableIdleDuration()}.
481      */
482     @Deprecated
483     public long getDefaultSoftMinEvictableIdleTimeMillis() {
484         return this.defaultSoftMinEvictableIdleDuration.toMillis();
485     }
486 
487     /**
488      * Gets the default value for {@link
489      * GenericObjectPool#getTestOnBorrow()} for each per user pool.
490      *
491      * @return The default value for {@link
492      *         GenericObjectPool#getTestOnBorrow()} for each per user pool.
493      */
494     public boolean getDefaultTestOnBorrow() {
495         return this.defaultTestOnBorrow;
496     }
497 
498     /**
499      * Gets the default value for {@link
500      * GenericObjectPool#getTestOnCreate()} for each per user pool.
501      *
502      * @return The default value for {@link
503      *         GenericObjectPool#getTestOnCreate()} for each per user pool.
504      */
505     public boolean getDefaultTestOnCreate() {
506         return this.defaultTestOnCreate;
507     }
508 
509     /**
510      * Gets the default value for {@link
511      * GenericObjectPool#getTestOnReturn()} for each per user pool.
512      *
513      * @return The default value for {@link
514      *         GenericObjectPool#getTestOnReturn()} for each per user pool.
515      */
516     public boolean getDefaultTestOnReturn() {
517         return this.defaultTestOnReturn;
518     }
519 
520     /**
521      * Gets the default value for {@link
522      * GenericObjectPool#getTestWhileIdle()} for each per user pool.
523      *
524      * @return The default value for {@link
525      *         GenericObjectPool#getTestWhileIdle()} for each per user pool.
526      */
527     public boolean getDefaultTestWhileIdle() {
528         return this.defaultTestWhileIdle;
529     }
530 
531     /**
532      * Gets the default value for {@link GenericObjectPool#getDurationBetweenEvictionRuns ()} for each per user pool.
533      *
534      * @return The default value for {@link GenericObjectPool#getDurationBetweenEvictionRuns ()} for each per user pool.
535      * @deprecated Use {@link #getDefaultDurationBetweenEvictionRuns()}.
536      */
537     @Deprecated
538     public long getDefaultTimeBetweenEvictionRunsMillis() {
539         return this.defaultDurationBetweenEvictionRuns.toMillis();
540     }
541 
542     /**
543      * Gets the value of defaultTransactionIsolation, which defines the state of connections handed out from this pool.
544      * The value can be changed on the Connection using Connection.setTransactionIsolation(int). If this method returns
545      * -1, the default is JDBC driver dependent.
546      *
547      * @return value of defaultTransactionIsolation.
548      */
549     public int getDefaultTransactionIsolation() {
550         return defaultTransactionIsolation;
551     }
552 
553     /**
554      * Gets the description. This property is defined by JDBC as for use with GUI (or other) tools that might deploy the
555      * datasource. It serves no internal purpose.
556      *
557      * @return value of description.
558      */
559     public String getDescription() {
560         return description;
561     }
562 
563     /**
564      * Gets the instance key.
565      *
566      * @return the instance key.
567      */
568     protected String getInstanceKey() {
569         return instanceKey;
570     }
571 
572     /**
573      * Gets the value of jndiEnvironment which is used when instantiating a JNDI InitialContext. This InitialContext is
574      * used to locate the back end ConnectionPoolDataSource.
575      *
576      * @param key
577      *            JNDI environment key.
578      * @return value of jndiEnvironment.
579      */
580     public String getJndiEnvironment(final String key) {
581         String value = null;
582         if (jndiEnvironment != null) {
583             value = jndiEnvironment.getProperty(key);
584         }
585         return value;
586     }
587 
588     /**
589      * Gets the value of loginTimeout.
590      *
591      * @return value of loginTimeout.
592      * @deprecated Use {@link #getLoginTimeoutDuration()}.
593      */
594     @Deprecated
595     @Override
596     public int getLoginTimeout() {
597         return (int) loginTimeoutDuration.getSeconds();
598     }
599 
600     /**
601      * Gets the value of loginTimeout.
602      *
603      * @return value of loginTimeout.
604      * @since 2.10.0
605      */
606     public Duration getLoginTimeoutDuration() {
607         return loginTimeoutDuration;
608     }
609 
610     /**
611      * Gets the value of logWriter.
612      *
613      * @return value of logWriter.
614      */
615     @Override
616     public PrintWriter getLogWriter() {
617         if (logWriter == null) {
618             logWriter = new PrintWriter(new OutputStreamWriter(System.out, StandardCharsets.UTF_8));
619         }
620         return logWriter;
621     }
622 
623     /**
624      * Gets the maximum permitted lifetime of a connection. A value of zero or less indicates an
625      * infinite lifetime.
626      *
627      * @return The maximum permitted lifetime of a connection. A value of zero or less indicates an
628      *         infinite lifetime.
629      * @since 2.10.0
630      */
631     public Duration getMaxConnDuration() {
632         return maxConnDuration;
633     }
634 
635     /**
636      * Gets the maximum permitted lifetime of a connection. A value of zero or less indicates an
637      * infinite lifetime.
638      *
639      * @return The maximum permitted lifetime of a connection. A value of zero or less indicates an
640      *         infinite lifetime.
641      * @deprecated Use {@link #getMaxConnDuration()}.
642      */
643     @Deprecated
644     public Duration getMaxConnLifetime() {
645         return maxConnDuration;
646     }
647 
648     /**
649      * Gets the maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an
650      * infinite lifetime.
651      *
652      * @return The maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an
653      *         infinite lifetime.
654      * @deprecated Use {@link #getMaxConnLifetime()}.
655      */
656     @Deprecated
657     public long getMaxConnLifetimeMillis() {
658         return maxConnDuration.toMillis();
659     }
660 
661     @Override
662     public Logger getParentLogger() throws SQLFeatureNotSupportedException {
663         throw new SQLFeatureNotSupportedException();
664     }
665 
666     /**
667      * This method is protected but can only be implemented in this package because PooledConnectionAndInfo is a package
668      * private type.
669      *
670      * @param userName The user name.
671      * @param userPassword The user password.
672      * @return Matching PooledConnectionAndInfo.
673      * @throws SQLException Connection or registration failure.
674      */
675     protected abstract PooledConnectionAndInfo getPooledConnectionAndInfo(String userName, String userPassword)
676             throws SQLException;
677 
678     /**
679      * Gets the SQL query that will be used to validate connections from this pool before returning them to the caller.
680      * If specified, this query <strong>MUST</strong> be an SQL SELECT statement that returns at least one row. If not
681      * specified, {@link Connection#isValid(int)} will be used to validate connections.
682      *
683      * @return The SQL query that will be used to validate connections from this pool before returning them to the
684      *         caller.
685      */
686     public String getValidationQuery() {
687         return this.validationQuery;
688     }
689 
690     /**
691      * Returns the timeout in seconds before the validation query fails.
692      *
693      * @return The timeout in seconds before the validation query fails.
694      * @deprecated Use {@link #getValidationQueryTimeoutDuration()}.
695      */
696     @Deprecated
697     public int getValidationQueryTimeout() {
698         return (int) validationQueryTimeoutDuration.getSeconds();
699     }
700 
701     /**
702      * Returns the timeout Duration before the validation query fails.
703      *
704      * @return The timeout Duration before the validation query fails.
705      */
706     public Duration getValidationQueryTimeoutDuration() {
707         return validationQueryTimeoutDuration;
708     }
709 
710     /**
711      * Gets the value of defaultAutoCommit, which defines the state of connections handed out from this pool. The value
712      * can be changed on the Connection using Connection.setAutoCommit(boolean). The default is {@code null} which
713      * will use the default value for the driver.
714      *
715      * @return value of defaultAutoCommit.
716      */
717     public Boolean isDefaultAutoCommit() {
718         return defaultAutoCommit;
719     }
720 
721     /**
722      * Gets the value of defaultReadOnly, which defines the state of connections handed out from this pool. The value
723      * can be changed on the Connection using Connection.setReadOnly(boolean). The default is {@code null} which
724      * will use the default value for the driver.
725      *
726      * @return value of defaultReadOnly.
727      */
728     public Boolean isDefaultReadOnly() {
729         return defaultReadOnly;
730     }
731 
732     /**
733      * Tests whether a rollback will be issued after executing the SQL query that will be used to validate connections from
734      * this pool before returning them to the caller.
735      *
736      * @return true if a rollback will be issued after executing the validation query
737      */
738     public boolean isRollbackAfterValidation() {
739         return this.rollbackAfterValidation;
740     }
741 
742     @Override
743     public boolean isWrapperFor(final Class<?> iface) throws SQLException {
744         return iface.isInstance(this);
745     }
746 
747     /**
748      * Sets the back end ConnectionPoolDataSource. This property should not be set if using JNDI to access the
749      * data source.
750      *
751      * @param dataSource
752      *            Value to assign to connectionPoolDataSource.
753      */
754     public void setConnectionPoolDataSource(final ConnectionPoolDataSource dataSource) {
755         assertInitializationAllowed();
756         if (dataSourceName != null) {
757             throw new IllegalStateException("Cannot set the DataSource, if JNDI is used.");
758         }
759         if (this.dataSource != null) {
760             throw new IllegalStateException("The CPDS has already been set. It cannot be altered.");
761         }
762         this.dataSource = dataSource;
763         instanceKey = InstanceKeyDataSourceFactory.registerNewInstance(this);
764     }
765 
766     /**
767      * Sets the name of the ConnectionPoolDataSource which backs this pool. This name is used to look up the data source
768      * from a JNDI service provider.
769      *
770      * @param dataSourceName
771      *            Value to assign to dataSourceName.
772      */
773     public void setDataSourceName(final String dataSourceName) {
774         assertInitializationAllowed();
775         if (dataSource != null) {
776             throw new IllegalStateException("Cannot set the JNDI name for the DataSource, if already "
777                     + "set using setConnectionPoolDataSource.");
778         }
779         if (this.dataSourceName != null) {
780             throw new IllegalStateException("The DataSourceName has already been set. It cannot be altered.");
781         }
782         this.dataSourceName = dataSourceName;
783         instanceKey = InstanceKeyDataSourceFactory.registerNewInstance(this);
784     }
785 
786     /**
787      * Sets the value of defaultAutoCommit, which defines the state of connections handed out from this pool. The value
788      * can be changed on the Connection using Connection.setAutoCommit(boolean). The default is {@code null} which
789      * will use the default value for the driver.
790      *
791      * @param defaultAutoCommit
792      *            Value to assign to defaultAutoCommit.
793      */
794     public void setDefaultAutoCommit(final Boolean defaultAutoCommit) {
795         assertInitializationAllowed();
796         this.defaultAutoCommit = defaultAutoCommit;
797     }
798 
799     /**
800      * Sets the default value for {@link GenericKeyedObjectPoolConfig#getBlockWhenExhausted()} for each per user pool.
801      *
802      * @param blockWhenExhausted
803      *            The default value for {@link GenericKeyedObjectPoolConfig#getBlockWhenExhausted()} for each per user
804      *            pool.
805      */
806     public void setDefaultBlockWhenExhausted(final boolean blockWhenExhausted) {
807         assertInitializationAllowed();
808         this.defaultBlockWhenExhausted = blockWhenExhausted;
809     }
810 
811     /**
812      * Sets the default value for {@link GenericObjectPool#getDurationBetweenEvictionRuns ()} for each per user pool.
813      *
814      * @param defaultDurationBetweenEvictionRuns The default value for
815      *        {@link GenericObjectPool#getDurationBetweenEvictionRuns ()} for each per user pool.
816      * @since 2.10.0
817      */
818     public void setDefaultDurationBetweenEvictionRuns(final Duration defaultDurationBetweenEvictionRuns) {
819         assertInitializationAllowed();
820         this.defaultDurationBetweenEvictionRuns = defaultDurationBetweenEvictionRuns;
821     }
822 
823     /**
824      * Sets the default value for {@link GenericKeyedObjectPoolConfig#getEvictionPolicyClassName()} for each per user
825      * pool.
826      *
827      * @param evictionPolicyClassName
828      *            The default value for {@link GenericKeyedObjectPoolConfig#getEvictionPolicyClassName()} for each per
829      *            user pool.
830      */
831     public void setDefaultEvictionPolicyClassName(final String evictionPolicyClassName) {
832         assertInitializationAllowed();
833         this.defaultEvictionPolicyClassName = evictionPolicyClassName;
834     }
835 
836     /**
837      * Sets the default value for {@link GenericKeyedObjectPoolConfig#getLifo()} for each per user pool.
838      *
839      * @param lifo
840      *            The default value for {@link GenericKeyedObjectPoolConfig#getLifo()} for each per user pool.
841      */
842     public void setDefaultLifo(final boolean lifo) {
843         assertInitializationAllowed();
844         this.defaultLifo = lifo;
845     }
846 
847     /**
848      * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMaxIdlePerKey()} for each per user pool.
849      *
850      * @param maxIdle
851      *            The default value for {@link GenericKeyedObjectPoolConfig#getMaxIdlePerKey()} for each per user pool.
852      */
853     public void setDefaultMaxIdle(final int maxIdle) {
854         assertInitializationAllowed();
855         this.defaultMaxIdle = maxIdle;
856     }
857 
858     /**
859      * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMaxTotalPerKey()} for each per user pool.
860      *
861      * @param maxTotal
862      *            The default value for {@link GenericKeyedObjectPoolConfig#getMaxTotalPerKey()} for each per user pool.
863      */
864     public void setDefaultMaxTotal(final int maxTotal) {
865         assertInitializationAllowed();
866         this.defaultMaxTotal = maxTotal;
867     }
868 
869     /**
870      * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitDuration()} for each per user pool.
871      *
872      * @param maxWaitMillis
873      *            The default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitDuration()} for each per user pool.
874      * @since 2.9.0
875      */
876     public void setDefaultMaxWait(final Duration maxWaitMillis) {
877         assertInitializationAllowed();
878         this.defaultMaxWaitDuration = maxWaitMillis;
879     }
880 
881     /**
882      * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitMillis()} for each per user pool.
883      *
884      * @param maxWaitMillis
885      *            The default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitMillis()} for each per user pool.
886      * @deprecated Use {@link #setDefaultMaxWait(Duration)}.
887      */
888     @Deprecated
889     public void setDefaultMaxWaitMillis(final long maxWaitMillis) {
890         setDefaultMaxWait(Duration.ofMillis(maxWaitMillis));
891     }
892 
893     /**
894      * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleDuration()} for each per user
895      * pool.
896      *
897      * @param defaultMinEvictableIdleDuration
898      *            The default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleDuration()} for each
899      *            per user pool.
900      * @since 2.10.0
901      */
902     public void setDefaultMinEvictableIdle(final Duration defaultMinEvictableIdleDuration) {
903         assertInitializationAllowed();
904         this.defaultMinEvictableIdleDuration = defaultMinEvictableIdleDuration;
905     }
906 
907     /**
908      * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleDuration()} for each per user
909      * pool.
910      *
911      * @param minEvictableIdleTimeMillis
912      *            The default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleDuration()} for each
913      *            per user pool.
914      * @deprecated Use {@link #setDefaultMinEvictableIdle(Duration)}.
915      */
916     @Deprecated
917     public void setDefaultMinEvictableIdleTimeMillis(final long minEvictableIdleTimeMillis) {
918         assertInitializationAllowed();
919         this.defaultMinEvictableIdleDuration = Duration.ofMillis(minEvictableIdleTimeMillis);
920     }
921 
922     /**
923      * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMinIdlePerKey()} for each per user pool.
924      *
925      * @param minIdle
926      *            The default value for {@link GenericKeyedObjectPoolConfig#getMinIdlePerKey()} for each per user pool.
927      */
928     public void setDefaultMinIdle(final int minIdle) {
929         assertInitializationAllowed();
930         this.defaultMinIdle = minIdle;
931     }
932 
933     /**
934      * Sets the default value for {@link GenericKeyedObjectPoolConfig#getNumTestsPerEvictionRun()} for each per user
935      * pool.
936      *
937      * @param numTestsPerEvictionRun
938      *            The default value for {@link GenericKeyedObjectPoolConfig#getNumTestsPerEvictionRun()} for each per
939      *            user pool.
940      */
941     public void setDefaultNumTestsPerEvictionRun(final int numTestsPerEvictionRun) {
942         assertInitializationAllowed();
943         this.defaultNumTestsPerEvictionRun = numTestsPerEvictionRun;
944     }
945 
946     /**
947      * Sets the value of defaultReadOnly, which defines the state of connections handed out from this pool. The value
948      * can be changed on the Connection using Connection.setReadOnly(boolean). The default is {@code null} which
949      * will use the default value for the driver.
950      *
951      * @param defaultReadOnly
952      *            Value to assign to defaultReadOnly.
953      */
954     public void setDefaultReadOnly(final Boolean defaultReadOnly) {
955         assertInitializationAllowed();
956         this.defaultReadOnly = defaultReadOnly;
957     }
958 
959     /**
960      * Sets the default value for {@link
961      * GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool.
962      *
963      * @param defaultSoftMinEvictableIdleDuration
964      *            The default value for {@link
965      *            GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool.
966      * @since 2.10.0
967      */
968     public void setDefaultSoftMinEvictableIdle(final Duration defaultSoftMinEvictableIdleDuration) {
969         assertInitializationAllowed();
970         this.defaultSoftMinEvictableIdleDuration = defaultSoftMinEvictableIdleDuration;
971     }
972 
973     /**
974      * Sets the default value for {@link
975      * GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool.
976      *
977      * @param softMinEvictableIdleTimeMillis
978      *            The default value for {@link
979      *            GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool.
980      * @deprecated Use {@link #setDefaultSoftMinEvictableIdle(Duration)}.
981      */
982     @Deprecated
983     public void setDefaultSoftMinEvictableIdleTimeMillis(final long softMinEvictableIdleTimeMillis) {
984         assertInitializationAllowed();
985         this.defaultSoftMinEvictableIdleDuration = Duration.ofMillis(softMinEvictableIdleTimeMillis);
986     }
987 
988     /**
989      * Sets the default value for {@link
990      * GenericObjectPool#getTestOnBorrow()} for each per user pool.
991      *
992      * @param testOnBorrow
993      *            The default value for {@link
994      *            GenericObjectPool#getTestOnBorrow()} for each per user pool.
995      */
996     public void setDefaultTestOnBorrow(final boolean testOnBorrow) {
997         assertInitializationAllowed();
998         this.defaultTestOnBorrow = testOnBorrow;
999     }
1000 
1001     /**
1002      * Sets the default value for {@link
1003      * GenericObjectPool#getTestOnCreate()} for each per user pool.
1004      *
1005      * @param testOnCreate
1006      *            The default value for {@link
1007      *            GenericObjectPool#getTestOnCreate()} for each per user pool.
1008      */
1009     public void setDefaultTestOnCreate(final boolean testOnCreate) {
1010         assertInitializationAllowed();
1011         this.defaultTestOnCreate = testOnCreate;
1012     }
1013 
1014     /**
1015      * Sets the default value for {@link
1016      * GenericObjectPool#getTestOnReturn()} for each per user pool.
1017      *
1018      * @param testOnReturn
1019      *            The default value for {@link
1020      *            GenericObjectPool#getTestOnReturn()} for each per user pool.
1021      */
1022     public void setDefaultTestOnReturn(final boolean testOnReturn) {
1023         assertInitializationAllowed();
1024         this.defaultTestOnReturn = testOnReturn;
1025     }
1026 
1027     /**
1028      * Sets the default value for {@link
1029      * GenericObjectPool#getTestWhileIdle()} for each per user pool.
1030      *
1031      * @param testWhileIdle
1032      *            The default value for {@link
1033      *            GenericObjectPool#getTestWhileIdle()} for each per user pool.
1034      */
1035     public void setDefaultTestWhileIdle(final boolean testWhileIdle) {
1036         assertInitializationAllowed();
1037         this.defaultTestWhileIdle = testWhileIdle;
1038     }
1039 
1040     /**
1041      * Sets the default value for {@link GenericObjectPool#getDurationBetweenEvictionRuns()} for each per user pool.
1042      *
1043      * @param timeBetweenEvictionRunsMillis The default value for
1044      *        {@link GenericObjectPool#getDurationBetweenEvictionRuns()} for each per user pool.
1045      * @deprecated Use {@link #setDefaultDurationBetweenEvictionRuns(Duration)}.
1046      */
1047     @Deprecated
1048     public void setDefaultTimeBetweenEvictionRunsMillis(final long timeBetweenEvictionRunsMillis) {
1049         assertInitializationAllowed();
1050         this.defaultDurationBetweenEvictionRuns = Duration.ofMillis(timeBetweenEvictionRunsMillis);
1051     }
1052 
1053     /**
1054      * Sets the value of defaultTransactionIsolation, which defines the state of connections handed out from this pool.
1055      * The value can be changed on the Connection using Connection.setTransactionIsolation(int). The default is JDBC
1056      * driver dependent.
1057      *
1058      * @param defaultTransactionIsolation
1059      *            Value to assign to defaultTransactionIsolation
1060      */
1061     public void setDefaultTransactionIsolation(final int defaultTransactionIsolation) {
1062         assertInitializationAllowed();
1063         switch (defaultTransactionIsolation) {
1064         case Connection.TRANSACTION_NONE:
1065         case Connection.TRANSACTION_READ_COMMITTED:
1066         case Connection.TRANSACTION_READ_UNCOMMITTED:
1067         case Connection.TRANSACTION_REPEATABLE_READ:
1068         case Connection.TRANSACTION_SERIALIZABLE:
1069             break;
1070         default:
1071             throw new IllegalArgumentException(BAD_TRANSACTION_ISOLATION);
1072         }
1073         this.defaultTransactionIsolation = defaultTransactionIsolation;
1074     }
1075 
1076     /**
1077      * Sets the description. This property is defined by JDBC as for use with GUI (or other) tools that might deploy the
1078      * datasource. It serves no internal purpose.
1079      *
1080      * @param description
1081      *            Value to assign to description.
1082      */
1083     public void setDescription(final String description) {
1084         this.description = description;
1085     }
1086 
1087     /**
1088      * Sets the JNDI environment to be used when instantiating a JNDI InitialContext. This InitialContext is used to
1089      * locate the back end ConnectionPoolDataSource.
1090      *
1091      * @param properties
1092      *            the JNDI environment property to set which will overwrite any current settings
1093      */
1094     void setJndiEnvironment(final Properties properties) {
1095         if (jndiEnvironment == null) {
1096             jndiEnvironment = new Properties();
1097         } else {
1098             jndiEnvironment.clear();
1099         }
1100         jndiEnvironment.putAll(properties);
1101     }
1102 
1103     /**
1104      * Sets the value of the given JNDI environment property to be used when instantiating a JNDI InitialContext. This
1105      * InitialContext is used to locate the back end ConnectionPoolDataSource.
1106      *
1107      * @param key
1108      *            the JNDI environment property to set.
1109      * @param value
1110      *            the value assigned to specified JNDI environment property.
1111      */
1112     public void setJndiEnvironment(final String key, final String value) {
1113         if (jndiEnvironment == null) {
1114             jndiEnvironment = new Properties();
1115         }
1116         jndiEnvironment.setProperty(key, value);
1117     }
1118 
1119     /**
1120      * Sets the value of loginTimeout.
1121      *
1122      * @param loginTimeout
1123      *            Value to assign to loginTimeout.
1124      * @since 2.10.0
1125      */
1126     public void setLoginTimeout(final Duration loginTimeout) {
1127         this.loginTimeoutDuration = loginTimeout;
1128     }
1129 
1130     /**
1131      * Sets the value of loginTimeout.
1132      *
1133      * @param loginTimeout
1134      *            Value to assign to loginTimeout.
1135      * @deprecated Use {@link #setLoginTimeout(Duration)}.
1136      */
1137     @Deprecated
1138     @Override
1139     public void setLoginTimeout(final int loginTimeout) {
1140         this.loginTimeoutDuration = Duration.ofSeconds(loginTimeout);
1141     }
1142 
1143     /**
1144      * Sets the value of logWriter.
1145      *
1146      * @param logWriter
1147      *            Value to assign to logWriter.
1148      */
1149     @Override
1150     public void setLogWriter(final PrintWriter logWriter) {
1151         this.logWriter = logWriter;
1152     }
1153 
1154     /**
1155      * <p>
1156      * Sets the maximum permitted lifetime of a connection. A value of zero or less indicates an infinite lifetime.
1157      * </p>
1158      * <p>
1159      * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first time one of the following methods is
1160      * invoked: {@link #getConnection()}, {@link #setLogWriter(PrintWriter)}, {@link #setLoginTimeout(Duration)}, {@link #getLoginTimeoutDuration()},
1161      * {@link #getLogWriter()}.
1162      * </p>
1163      *
1164      * @param maxConnLifetimeMillis The maximum permitted lifetime of a connection. A value of zero or less indicates an infinite lifetime.
1165      * @since 2.9.0
1166      */
1167     public void setMaxConnLifetime(final Duration maxConnLifetimeMillis) {
1168         this.maxConnDuration = maxConnLifetimeMillis;
1169     }
1170 
1171     /**
1172      * <p>
1173      * Sets the maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an infinite lifetime.
1174      * </p>
1175      * <p>
1176      * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first time one of the following methods is
1177      * invoked: {@link #getConnection()}, {@link #setLogWriter(PrintWriter)}, {@link #setLoginTimeout(Duration)}, {@link #getLoginTimeoutDuration()},
1178      * {@link #getLogWriter()}.
1179      * </p>
1180      *
1181      * @param maxConnLifetimeMillis The maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an infinite lifetime.
1182      * @deprecated Use {@link #setMaxConnLifetime(Duration)}.
1183      */
1184     @Deprecated
1185     public void setMaxConnLifetimeMillis(final long maxConnLifetimeMillis) {
1186         setMaxConnLifetime(Duration.ofMillis(maxConnLifetimeMillis));
1187     }
1188 
1189     /**
1190      * Sets whether a rollback will be issued after executing the SQL query that will be used to validate connections from
1191      * this pool before returning them to the caller. Default behavior is NOT to issue a rollback. The setting will only
1192      * have an effect if a validation query is set
1193      *
1194      * @param rollbackAfterValidation
1195      *            new property value
1196      */
1197     public void setRollbackAfterValidation(final boolean rollbackAfterValidation) {
1198         assertInitializationAllowed();
1199         this.rollbackAfterValidation = rollbackAfterValidation;
1200     }
1201 
1202     /**
1203      * Sets up the defaults for a given connection.
1204      *
1205      * @param connection The target connection.
1206      * @param userName   The user name for the connection.
1207      * @throws SQLException if a database access error occurs or this method is called on a closed connection
1208      */
1209     protected abstract void setupDefaults(Connection connection, String userName) throws SQLException;
1210 
1211     /**
1212      * Sets the SQL query that will be used to validate connections from this pool before returning them to the caller.
1213      * If specified, this query <strong>MUST</strong> be an SQL SELECT statement that returns at least one row. If not
1214      * specified, connections will be validated using {@link Connection#isValid(int)}.
1215      *
1216      * @param validationQuery
1217      *            The SQL query that will be used to validate connections from this pool before returning them to the
1218      *            caller.
1219      */
1220     public void setValidationQuery(final String validationQuery) {
1221         assertInitializationAllowed();
1222         this.validationQuery = validationQuery;
1223     }
1224 
1225     /**
1226      * Sets the timeout duration before the validation query fails.
1227      *
1228      * @param validationQueryTimeoutDuration
1229      *            The new timeout duration.
1230      */
1231     public void setValidationQueryTimeout(final Duration validationQueryTimeoutDuration) {
1232         this.validationQueryTimeoutDuration = validationQueryTimeoutDuration;
1233     }
1234 
1235     /**
1236      * Sets the timeout in seconds before the validation query fails.
1237      *
1238      * @param validationQueryTimeoutSeconds
1239      *            The new timeout in seconds
1240      * @deprecated Use {@link #setValidationQueryTimeout(Duration)}.
1241      */
1242     @Deprecated
1243     public void setValidationQueryTimeout(final int validationQueryTimeoutSeconds) {
1244         this.validationQueryTimeoutDuration = Duration.ofSeconds(validationQueryTimeoutSeconds);
1245     }
1246 
1247     /**
1248      * Tests and returns whether a JNDI context can be created to lookup a ConnectionPoolDataSource to then access a PooledConnection connection.
1249      *
1250      * @param userName     An optional user name, may be null.
1251      * @param userPassword An optional user user password, may be null.
1252      * @return A ConnectionPoolDataSource from a JNDI context.
1253      * @throws javax.naming.NamingException if a naming exception is encountered.
1254      * @throws SQLException                 if a ConnectionPoolDataSource or PooledConnection is not available.
1255      */
1256     protected ConnectionPoolDataSource testCPDS(final String userName, final String userPassword)
1257             throws javax.naming.NamingException, SQLException {
1258         // The source of physical database connections
1259         ConnectionPoolDataSource cpds = this.dataSource;
1260         if (cpds == null) {
1261             Context ctx = null;
1262             if (jndiEnvironment == null) {
1263                 ctx = new InitialContext();
1264             } else {
1265                 ctx = new InitialContext(jndiEnvironment);
1266             }
1267             final Object ds = ctx.lookup(dataSourceName);
1268             if (!(ds instanceof ConnectionPoolDataSource)) {
1269                 throw new SQLException("Illegal configuration: DataSource " + dataSourceName + " ("
1270                         + ds.getClass().getName() + ") doesn't implement javax.sql.ConnectionPoolDataSource");
1271             }
1272             cpds = (ConnectionPoolDataSource) ds;
1273         }
1274         // try to get a connection with the supplied userName/password
1275         PooledConnection conn = null;
1276         try {
1277             if (userName != null) {
1278                 conn = cpds.getPooledConnection(userName, userPassword);
1279             } else {
1280                 conn = cpds.getPooledConnection();
1281             }
1282             if (conn == null) {
1283                 throw new SQLException("Cannot connect using the supplied userName/password");
1284             }
1285         } finally {
1286             if (conn != null) {
1287                 try {
1288                     conn.close();
1289                 } catch (final SQLException ignored) {
1290                     // at least we could connect
1291                 }
1292             }
1293         }
1294         return cpds;
1295     }
1296 
1297     /**
1298      * @since 2.6.0
1299      */
1300     @Override
1301     public synchronized String toString() {
1302         final StringBuilder builder = new StringBuilder(super.toString());
1303         builder.append('[');
1304         toStringFields(builder);
1305         builder.append(']');
1306         return builder.toString();
1307     }
1308 
1309     /**
1310      * Appends this instance's fields to a string builder.
1311      *
1312      * @param builder the target string builder.
1313      */
1314     protected void toStringFields(final StringBuilder builder) {
1315         builder.append("getConnectionCalled=");
1316         builder.append(getConnectionCalled);
1317         builder.append(", dataSource=");
1318         builder.append(dataSource);
1319         builder.append(", dataSourceName=");
1320         builder.append(dataSourceName);
1321         builder.append(", description=");
1322         builder.append(description);
1323         builder.append(", jndiEnvironment=");
1324         builder.append(jndiEnvironment);
1325         builder.append(", loginTimeoutDuration=");
1326         builder.append(loginTimeoutDuration);
1327         builder.append(", logWriter=");
1328         builder.append(logWriter);
1329         builder.append(", instanceKey=");
1330         builder.append(instanceKey);
1331         builder.append(", defaultBlockWhenExhausted=");
1332         builder.append(defaultBlockWhenExhausted);
1333         builder.append(", defaultEvictionPolicyClassName=");
1334         builder.append(defaultEvictionPolicyClassName);
1335         builder.append(", defaultLifo=");
1336         builder.append(defaultLifo);
1337         builder.append(", defaultMaxIdle=");
1338         builder.append(defaultMaxIdle);
1339         builder.append(", defaultMaxTotal=");
1340         builder.append(defaultMaxTotal);
1341         builder.append(", defaultMaxWaitDuration=");
1342         builder.append(defaultMaxWaitDuration);
1343         builder.append(", defaultMinEvictableIdleDuration=");
1344         builder.append(defaultMinEvictableIdleDuration);
1345         builder.append(", defaultMinIdle=");
1346         builder.append(defaultMinIdle);
1347         builder.append(", defaultNumTestsPerEvictionRun=");
1348         builder.append(defaultNumTestsPerEvictionRun);
1349         builder.append(", defaultSoftMinEvictableIdleDuration=");
1350         builder.append(defaultSoftMinEvictableIdleDuration);
1351         builder.append(", defaultTestOnCreate=");
1352         builder.append(defaultTestOnCreate);
1353         builder.append(", defaultTestOnBorrow=");
1354         builder.append(defaultTestOnBorrow);
1355         builder.append(", defaultTestOnReturn=");
1356         builder.append(defaultTestOnReturn);
1357         builder.append(", defaultTestWhileIdle=");
1358         builder.append(defaultTestWhileIdle);
1359         builder.append(", defaultDurationBetweenEvictionRuns=");
1360         builder.append(defaultDurationBetweenEvictionRuns);
1361         builder.append(", validationQuery=");
1362         builder.append(validationQuery);
1363         builder.append(", validationQueryTimeoutDuration=");
1364         builder.append(validationQueryTimeoutDuration);
1365         builder.append(", rollbackAfterValidation=");
1366         builder.append(rollbackAfterValidation);
1367         builder.append(", maxConnDuration=");
1368         builder.append(maxConnDuration);
1369         builder.append(", defaultAutoCommit=");
1370         builder.append(defaultAutoCommit);
1371         builder.append(", defaultTransactionIsolation=");
1372         builder.append(defaultTransactionIsolation);
1373         builder.append(", defaultReadOnly=");
1374         builder.append(defaultReadOnly);
1375     }
1376 
1377     @Override
1378     @SuppressWarnings("unchecked")
1379     public <T> T unwrap(final Class<T> iface) throws SQLException {
1380         if (isWrapperFor(iface)) {
1381             return (T) this;
1382         }
1383         throw new SQLException(this + " is not a wrapper for " + iface);
1384     }
1385 }