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