001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.dbcp2.datasources;
018
019import java.io.OutputStreamWriter;
020import java.io.PrintWriter;
021import java.io.Serializable;
022import java.nio.charset.StandardCharsets;
023import java.sql.Connection;
024import java.sql.SQLException;
025import java.sql.SQLFeatureNotSupportedException;
026import java.time.Duration;
027import java.util.Properties;
028import java.util.logging.Logger;
029
030import javax.naming.Context;
031import javax.naming.InitialContext;
032import javax.naming.Referenceable;
033import javax.sql.ConnectionPoolDataSource;
034import javax.sql.DataSource;
035import javax.sql.PooledConnection;
036
037import org.apache.commons.dbcp2.Utils;
038import org.apache.commons.pool2.impl.BaseObjectPoolConfig;
039import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;
040import org.apache.commons.pool2.impl.GenericObjectPool;
041
042/**
043 * <p>
044 * The base class for {@code SharedPoolDataSource} and {@code PerUserPoolDataSource}. Many of the
045 * configuration properties are shared and defined here. This class is declared public in order to allow particular
046 * usage with commons-beanutils; do not make direct use of it outside of <em>commons-dbcp2</em>.
047 * </p>
048 *
049 * <p>
050 * A J2EE container will normally provide some method of initializing the {@code DataSource} whose attributes are
051 * presented as bean getters/setters and then deploying it via JNDI. It is then available to an application as a source
052 * of pooled logical connections to the database. The pool needs a source of physical connections. This source is in the
053 * form of a {@code ConnectionPoolDataSource} that can be specified via the {@link #setDataSourceName(String)} used
054 * to lookup the source via JNDI.
055 * </p>
056 *
057 * <p>
058 * Although normally used within a JNDI environment, A DataSource can be instantiated and initialized as any bean. In
059 * this case the {@code ConnectionPoolDataSource} will likely be instantiated in a similar manner. This class
060 * allows the physical source of connections to be attached directly to this pool using the
061 * {@link #setConnectionPoolDataSource(ConnectionPoolDataSource)} method.
062 * </p>
063 *
064 * <p>
065 * The dbcp package contains an adapter, {@link org.apache.commons.dbcp2.cpdsadapter.DriverAdapterCPDS}, that can be
066 * used to allow the use of {@code DataSource}'s based on this class with JDBC driver implementations that do not
067 * supply a {@code ConnectionPoolDataSource}, but still provide a {@link java.sql.Driver} implementation.
068 * </p>
069 *
070 * <p>
071 * The <a href="package-summary.html">package documentation</a> contains an example using Apache Tomcat and JNDI and it
072 * also contains a non-JNDI example.
073 * </p>
074 *
075 * @since 2.0
076 */
077public abstract class InstanceKeyDataSource implements DataSource, Referenceable, Serializable, AutoCloseable {
078
079    private static final long serialVersionUID = -6819270431752240878L;
080
081    private static final String GET_CONNECTION_CALLED = "A Connection was already requested from this source, "
082            + "further initialization is not allowed.";
083    private static final String BAD_TRANSACTION_ISOLATION = "The requested TransactionIsolation level is invalid.";
084
085    /**
086     * Internal constant to indicate the level is not set.
087     */
088    protected static final int UNKNOWN_TRANSACTIONISOLATION = -1;
089
090    /** Guards property setters - once true, setters throw IllegalStateException */
091    private volatile boolean getConnectionCalled;
092
093    /** Underlying source of PooledConnections */
094    private ConnectionPoolDataSource dataSource;
095
096    /** DataSource Name used to find the ConnectionPoolDataSource */
097    private String dataSourceName;
098
099    /** 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}