    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_TIME_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}