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