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