    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 */
    017
    018package org.apache.commons.dbcp2.datasources;
    019
    020import java.io.OutputStreamWriter;
    021import java.io.PrintWriter;
    022import java.io.Serializable;
    023import java.nio.charset.StandardCharsets;
    024import java.sql.Connection;
    025import java.sql.SQLException;
    026import java.sql.SQLFeatureNotSupportedException;
    027import java.util.NoSuchElementException;
    028import java.util.Properties;
    029import java.util.logging.Logger;
    030
    031import javax.naming.Context;
    032import javax.naming.InitialContext;
    033import javax.naming.Referenceable;
    034import javax.sql.ConnectionPoolDataSource;
    035import javax.sql.DataSource;
    036import javax.sql.PooledConnection;
    037
    038import org.apache.commons.pool2.impl.BaseObjectPoolConfig;
    039import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;
    040
    041/**
    042 * <p>
    043 * The base class for <code>SharedPoolDataSource</code> and <code>PerUserPoolDataSource</code>. Many of the
    044 * configuration properties are shared and defined here. This class is declared public in order to allow particular
    045 * usage with commons-beanutils; do not make direct use of it outside of <em>commons-dbcp2</em>.
    046 * </p>
    047 *
    048 * <p>
    049 * A J2EE container will normally provide some method of initializing the <code>DataSource</code> whose attributes are
    050 * presented as bean getters/setters and then deploying it via JNDI. It is then available to an application as a source
    051 * of pooled logical connections to the database. The pool needs a source of physical connections. This source is in the
    052 * form of a <code>ConnectionPoolDataSource</code> that can be specified via the {@link #setDataSourceName(String)} used
    053 * to lookup the source via JNDI.
    054 * </p>
    055 *
    056 * <p>
    057 * Although normally used within a JNDI environment, A DataSource can be instantiated and initialized as any bean. In
    058 * this case the <code>ConnectionPoolDataSource</code> will likely be instantiated in a similar manner. This class
    059 * allows the physical source of connections to be attached directly to this pool using the
    060 * {@link #setConnectionPoolDataSource(ConnectionPoolDataSource)} method.
    061 * </p>
    062 *
    063 * <p>
    064 * The dbcp package contains an adapter, {@link org.apache.commons.dbcp2.cpdsadapter.DriverAdapterCPDS}, that can be
    065 * used to allow the use of <code>DataSource</code>'s based on this class with JDBC driver implementations that do not
    066 * supply a <code>ConnectionPoolDataSource</code>, but still provide a {@link java.sql.Driver} implementation.
    067 * </p>
    068 *
    069 * <p>
    070 * The <a href="package-summary.html">package documentation</a> contains an example using Apache Tomcat and JNDI and it
    071 * also contains a non-JNDI example.
    072 * </p>
    073 *
    074 * @since 2.0
    075 */
    076public abstract class InstanceKeyDataSource implements DataSource, Referenceable, Serializable, AutoCloseable {
    077
    078    private static final long serialVersionUID = -6819270431752240878L;
    079
    080    private static final String GET_CONNECTION_CALLED = "A Connection was already requested from this source, "
    081            + "further initialization is not allowed.";
    082    private static final String BAD_TRANSACTION_ISOLATION = "The requested TransactionIsolation level is invalid.";
    083
    084    /**
    085     * Internal constant to indicate the level is not set.
    086     */
    087    protected static final int UNKNOWN_TRANSACTIONISOLATION = -1;
    088
    089    /** Guards property setters - once true, setters throw IllegalStateException */
    090    private volatile boolean getConnectionCalled;
    091
    092    /** Underlying source of PooledConnections */
    093    private ConnectionPoolDataSource dataSource;
    094
    095    /** DataSource Name used to find the ConnectionPoolDataSource */
    096    private String dataSourceName;
    097
    098    /** Description */
    099    private String description;
    100
    101    /** Environment that may be used to set up a JNDI initial context. */
    102    private Properties jndiEnvironment;
    103
    104    /** Login TimeOut in seconds */
    105    private int loginTimeout;
    106
    107    /** Log stream */
    108    private PrintWriter logWriter;
    109
    110    /** Instance key */
    111    private String instanceKey;
    112
    113    // Pool properties
    114    private boolean defaultBlockWhenExhausted = BaseObjectPoolConfig.DEFAULT_BLOCK_WHEN_EXHAUSTED;
    115    private String defaultEvictionPolicyClassName = BaseObjectPoolConfig.DEFAULT_EVICTION_POLICY_CLASS_NAME;
    116    private boolean defaultLifo = BaseObjectPoolConfig.DEFAULT_LIFO;
    117    private int defaultMaxIdle = GenericKeyedObjectPoolConfig.DEFAULT_MAX_IDLE_PER_KEY;
    118    private int defaultMaxTotal = GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL;
    119    private long defaultMaxWaitMillis = BaseObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS;
    120    private long defaultMinEvictableIdleTimeMillis = BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
    121    private int defaultMinIdle = GenericKeyedObjectPoolConfig.DEFAULT_MIN_IDLE_PER_KEY;
    122    private int defaultNumTestsPerEvictionRun = BaseObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
    123    private long defaultSoftMinEvictableIdleTimeMillis = BaseObjectPoolConfig.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
    124    private boolean defaultTestOnCreate = BaseObjectPoolConfig.DEFAULT_TEST_ON_CREATE;
    125    private boolean defaultTestOnBorrow = BaseObjectPoolConfig.DEFAULT_TEST_ON_BORROW;
    126    private boolean defaultTestOnReturn = BaseObjectPoolConfig.DEFAULT_TEST_ON_RETURN;
    127    private boolean defaultTestWhileIdle = BaseObjectPoolConfig.DEFAULT_TEST_WHILE_IDLE;
    128    private long defaultTimeBetweenEvictionRunsMillis = BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
    129
    130    // Connection factory properties
    131    private String validationQuery;
    132    private int validationQueryTimeoutSeconds = -1;
    133    private boolean rollbackAfterValidation;
    134    private long maxConnLifetimeMillis = -1;
    135
    136    // Connection properties
    137    private Boolean defaultAutoCommit;
    138    private int defaultTransactionIsolation = UNKNOWN_TRANSACTIONISOLATION;
    139    private Boolean defaultReadOnly;
    140
    141    /**
    142     * Default no-arg constructor for Serialization
    143     */
    144    public InstanceKeyDataSource() {
    145    }
    146
    147    /**
    148     * Throws an IllegalStateException, if a PooledConnection has already been requested.
    149     *
    150     * @throws IllegalStateException Thrown if a PooledConnection has already been requested.
    151     */
    152    protected void assertInitializationAllowed() throws IllegalStateException {
    153        if (getConnectionCalled) {
    154            throw new IllegalStateException(GET_CONNECTION_CALLED);
    155        }
    156    }
    157
    158    /**
    159     * Closes the connection pool being maintained by this datasource.
    160     */
    161    @Override
    162    public abstract void close() throws Exception;
    163
    164    protected abstract PooledConnectionManager getConnectionManager(UserPassKey upkey);
    165
    166    /* JDBC_4_ANT_KEY_BEGIN */
    167    @Override
    168    public boolean isWrapperFor(final Class<?> iface) throws SQLException {
    169        return false;
    170    }
    171
    172    @Override
    173    public <T> T unwrap(final Class<T> iface) throws SQLException {
    174        throw new SQLException("InstanceKeyDataSource is not a wrapper.");
    175    }
    176    /* JDBC_4_ANT_KEY_END */
    177
    178    @Override
    179    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
    180        throw new SQLFeatureNotSupportedException();
    181    }
    182
    183    // -------------------------------------------------------------------
    184    // Properties
    185
    186    /**
    187     * Gets the default value for {@link GenericKeyedObjectPoolConfig#getBlockWhenExhausted()} for each per user pool.
    188     *
    189     * @return The default value for {@link GenericKeyedObjectPoolConfig#getBlockWhenExhausted()} for each per user
    190     *         pool.
    191     */
    192    public boolean getDefaultBlockWhenExhausted() {
    193        return this.defaultBlockWhenExhausted;
    194    }
    195
    196    /**
    197     * Sets the default value for {@link GenericKeyedObjectPoolConfig#getBlockWhenExhausted()} for each per user pool.
    198     *
    199     * @param blockWhenExhausted
    200     *            The default value for {@link GenericKeyedObjectPoolConfig#getBlockWhenExhausted()} for each per user
    201     *            pool.
    202     */
    203    public void setDefaultBlockWhenExhausted(final boolean blockWhenExhausted) {
    204        assertInitializationAllowed();
    205        this.defaultBlockWhenExhausted = blockWhenExhausted;
    206    }
    207
    208    /**
    209     * Gets the default value for {@link GenericKeyedObjectPoolConfig#getEvictionPolicyClassName()} for each per user
    210     * pool.
    211     *
    212     * @return The default value for {@link GenericKeyedObjectPoolConfig#getEvictionPolicyClassName()} for each per user
    213     *         pool.
    214     */
    215    public String getDefaultEvictionPolicyClassName() {
    216        return this.defaultEvictionPolicyClassName;
    217    }
    218
    219    /**
    220     * Sets the default value for {@link GenericKeyedObjectPoolConfig#getEvictionPolicyClassName()} for each per user
    221     * pool.
    222     *
    223     * @param evictionPolicyClassName
    224     *            The default value for {@link GenericKeyedObjectPoolConfig#getEvictionPolicyClassName()} for each per
    225     *            user pool.
    226     */
    227    public void setDefaultEvictionPolicyClassName(final String evictionPolicyClassName) {
    228        assertInitializationAllowed();
    229        this.defaultEvictionPolicyClassName = evictionPolicyClassName;
    230    }
    231
    232    /**
    233     * Gets the default value for {@link GenericKeyedObjectPoolConfig#getLifo()} for each per user pool.
    234     *
    235     * @return The default value for {@link GenericKeyedObjectPoolConfig#getLifo()} for each per user pool.
    236     */
    237    public boolean getDefaultLifo() {
    238        return this.defaultLifo;
    239    }
    240
    241    /**
    242     * Sets the default value for {@link GenericKeyedObjectPoolConfig#getLifo()} for each per user pool.
    243     *
    244     * @param lifo
    245     *            The default value for {@link GenericKeyedObjectPoolConfig#getLifo()} for each per user pool.
    246     */
    247    public void setDefaultLifo(final boolean lifo) {
    248        assertInitializationAllowed();
    249        this.defaultLifo = lifo;
    250    }
    251
    252    /**
    253     * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMaxIdlePerKey()} for each per user pool.
    254     *
    255     * @return The default value for {@link GenericKeyedObjectPoolConfig#getMaxIdlePerKey()} for each per user pool.
    256     */
    257    public int getDefaultMaxIdle() {
    258        return this.defaultMaxIdle;
    259    }
    260
    261    /**
    262     * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMaxIdlePerKey()} for each per user pool.
    263     *
    264     * @param maxIdle
    265     *            The default value for {@link GenericKeyedObjectPoolConfig#getMaxIdlePerKey()} for each per user pool.
    266     */
    267    public void setDefaultMaxIdle(final int maxIdle) {
    268        assertInitializationAllowed();
    269        this.defaultMaxIdle = maxIdle;
    270    }
    271
    272    /**
    273     * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMaxTotalPerKey()} for each per user pool.
    274     *
    275     * @return The default value for {@link GenericKeyedObjectPoolConfig#getMaxTotalPerKey()} for each per user pool.
    276     */
    277    public int getDefaultMaxTotal() {
    278        return this.defaultMaxTotal;
    279    }
    280
    281    /**
    282     * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMaxTotalPerKey()} for each per user pool.
    283     *
    284     * @param maxTotal
    285     *            The default value for {@link GenericKeyedObjectPoolConfig#getMaxTotalPerKey()} for each per user pool.
    286     */
    287    public void setDefaultMaxTotal(final int maxTotal) {
    288        assertInitializationAllowed();
    289        this.defaultMaxTotal = maxTotal;
    290    }
    291
    292    /**
    293     * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitMillis()} for each per user pool.
    294     *
    295     * @return The default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitMillis()} for each per user pool.
    296     */
    297    public long getDefaultMaxWaitMillis() {
    298        return this.defaultMaxWaitMillis;
    299    }
    300
    301    /**
    302     * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitMillis()} for each per user pool.
    303     *
    304     * @param maxWaitMillis
    305     *            The default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitMillis()} for each per user pool.
    306     */
    307    public void setDefaultMaxWaitMillis(final long maxWaitMillis) {
    308        assertInitializationAllowed();
    309        this.defaultMaxWaitMillis = maxWaitMillis;
    310    }
    311
    312    /**
    313     * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleTimeMillis()} for each per user
    314     * pool.
    315     *
    316     * @return The default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleTimeMillis()} for each per
    317     *         user pool.
    318     */
    319    public long getDefaultMinEvictableIdleTimeMillis() {
    320        return this.defaultMinEvictableIdleTimeMillis;
    321    }
    322
    323    /**
    324     * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleTimeMillis()} for each per user
    325     * pool.
    326     *
    327     * @param minEvictableIdleTimeMillis
    328     *            The default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleTimeMillis()} for each
    329     *            per user pool.
    330     */
    331    public void setDefaultMinEvictableIdleTimeMillis(final long minEvictableIdleTimeMillis) {
    332        assertInitializationAllowed();
    333        this.defaultMinEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
    334    }
    335
    336    /**
    337     * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMinIdlePerKey()} for each per user pool.
    338     *
    339     * @return The default value for {@link GenericKeyedObjectPoolConfig#getMinIdlePerKey()} for each per user pool.
    340     */
    341    public int getDefaultMinIdle() {
    342        return this.defaultMinIdle;
    343    }
    344
    345    /**
    346     * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMinIdlePerKey()} for each per user pool.
    347     *
    348     * @param minIdle
    349     *            The default value for {@link GenericKeyedObjectPoolConfig#getMinIdlePerKey()} for each per user pool.
    350     */
    351    public void setDefaultMinIdle(final int minIdle) {
    352        assertInitializationAllowed();
    353        this.defaultMinIdle = minIdle;
    354    }
    355
    356    /**
    357     * Gets the default value for {@link GenericKeyedObjectPoolConfig#getNumTestsPerEvictionRun()} for each per user
    358     * pool.
    359     *
    360     * @return The default value for {@link GenericKeyedObjectPoolConfig#getNumTestsPerEvictionRun()} for each per user
    361     *         pool.
    362     */
    363    public int getDefaultNumTestsPerEvictionRun() {
    364        return this.defaultNumTestsPerEvictionRun;
    365    }
    366
    367    /**
    368     * Sets the default value for {@link GenericKeyedObjectPoolConfig#getNumTestsPerEvictionRun()} for each per user
    369     * pool.
    370     *
    371     * @param numTestsPerEvictionRun
    372     *            The default value for {@link GenericKeyedObjectPoolConfig#getNumTestsPerEvictionRun()} for each per
    373     *            user pool.
    374     */
    375    public void setDefaultNumTestsPerEvictionRun(final int numTestsPerEvictionRun) {
    376        assertInitializationAllowed();
    377        this.defaultNumTestsPerEvictionRun = numTestsPerEvictionRun;
    378    }
    379
    380    /**
    381     * Gets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
    382     * GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool.
    383     *
    384     * @return The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
    385     *         GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool.
    386     */
    387    public long getDefaultSoftMinEvictableIdleTimeMillis() {
    388        return this.defaultSoftMinEvictableIdleTimeMillis;
    389    }
    390
    391    /**
    392     * Sets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
    393     * GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool.
    394     *
    395     * @param softMinEvictableIdleTimeMillis
    396     *            The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
    397     *            GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool.
    398     */
    399    public void setDefaultSoftMinEvictableIdleTimeMillis(final long softMinEvictableIdleTimeMillis) {
    400        assertInitializationAllowed();
    401        this.defaultSoftMinEvictableIdleTimeMillis = softMinEvictableIdleTimeMillis;
    402    }
    403
    404    /**
    405     * Gets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
    406     * GenericObjectPool#getTestOnCreate()} for each per user pool.
    407     *
    408     * @return The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
    409     *         GenericObjectPool#getTestOnCreate()} for each per user pool.
    410     */
    411    public boolean getDefaultTestOnCreate() {
    412        return this.defaultTestOnCreate;
    413    }
    414
    415    /**
    416     * Sets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
    417     * GenericObjectPool#getTestOnCreate()} for each per user pool.
    418     *
    419     * @param testOnCreate
    420     *            The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
    421     *            GenericObjectPool#getTestOnCreate()} for each per user pool.
    422     */
    423    public void setDefaultTestOnCreate(final boolean testOnCreate) {
    424        assertInitializationAllowed();
    425        this.defaultTestOnCreate = testOnCreate;
    426    }
    427
    428    /**
    429     * Gets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
    430     * GenericObjectPool#getTestOnBorrow()} for each per user pool.
    431     *
    432     * @return The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
    433     *         GenericObjectPool#getTestOnBorrow()} for each per user pool.
    434     */
    435    public boolean getDefaultTestOnBorrow() {
    436        return this.defaultTestOnBorrow;
    437    }
    438
    439    /**
    440     * Sets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
    441     * GenericObjectPool#getTestOnBorrow()} for each per user pool.
    442     *
    443     * @param testOnBorrow
    444     *            The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
    445     *            GenericObjectPool#getTestOnBorrow()} for each per user pool.
    446     */
    447    public void setDefaultTestOnBorrow(final boolean testOnBorrow) {
    448        assertInitializationAllowed();
    449        this.defaultTestOnBorrow = testOnBorrow;
    450    }
    451
    452    /**
    453     * Gets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
    454     * GenericObjectPool#getTestOnReturn()} for each per user pool.
    455     *
    456     * @return The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
    457     *         GenericObjectPool#getTestOnReturn()} for each per user pool.
    458     */
    459    public boolean getDefaultTestOnReturn() {
    460        return this.defaultTestOnReturn;
    461    }
    462
    463    /**
    464     * Sets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
    465     * GenericObjectPool#getTestOnReturn()} for each per user pool.
    466     *
    467     * @param testOnReturn
    468     *            The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
    469     *            GenericObjectPool#getTestOnReturn()} for each per user pool.
    470     */
    471    public void setDefaultTestOnReturn(final boolean testOnReturn) {
    472        assertInitializationAllowed();
    473        this.defaultTestOnReturn = testOnReturn;
    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     * Sets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
    489     * GenericObjectPool#getTestWhileIdle()} for each per user pool.
    490     *
    491     * @param testWhileIdle
    492     *            The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
    493     *            GenericObjectPool#getTestWhileIdle()} for each per user pool.
    494     */
    495    public void setDefaultTestWhileIdle(final boolean testWhileIdle) {
    496        assertInitializationAllowed();
    497        this.defaultTestWhileIdle = testWhileIdle;
    498    }
    499
    500    /**
    501     * Gets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
    502     * GenericObjectPool#getTimeBetweenEvictionRunsMillis ()} for each per user pool.
    503     *
    504     * @return The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
    505     *         GenericObjectPool#getTimeBetweenEvictionRunsMillis ()} for each per user pool.
    506     */
    507    public long getDefaultTimeBetweenEvictionRunsMillis() {
    508        return this.defaultTimeBetweenEvictionRunsMillis;
    509    }
    510
    511    /**
    512     * Sets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
    513     * GenericObjectPool#getTimeBetweenEvictionRunsMillis ()} for each per user pool.
    514     *
    515     * @param timeBetweenEvictionRunsMillis
    516     *            The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
    517     *            GenericObjectPool#getTimeBetweenEvictionRunsMillis ()} for each per user pool.
    518     */
    519    public void setDefaultTimeBetweenEvictionRunsMillis(final long timeBetweenEvictionRunsMillis) {
    520        assertInitializationAllowed();
    521        this.defaultTimeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
    522    }
    523
    524    /**
    525     * Gets the value of connectionPoolDataSource. This method will return null, if the backing data source is being
    526     * accessed via JNDI.
    527     *
    528     * @return value of connectionPoolDataSource.
    529     */
    530    public ConnectionPoolDataSource getConnectionPoolDataSource() {
    531        return dataSource;
    532    }
    533
    534    /**
    535     * Sets the backend ConnectionPoolDataSource. This property should not be set if using JNDI to access the
    536     * data source.
    537     *
    538     * @param v
    539     *            Value to assign to connectionPoolDataSource.
    540     */
    541    public void setConnectionPoolDataSource(final ConnectionPoolDataSource v) {
    542        assertInitializationAllowed();
    543        if (dataSourceName != null) {
    544            throw new IllegalStateException("Cannot set the DataSource, if JNDI is used.");
    545        }
    546        if (dataSource != null) {
    547            throw new IllegalStateException("The CPDS has already been set. It cannot be altered.");
    548        }
    549        dataSource = v;
    550        instanceKey = InstanceKeyDataSourceFactory.registerNewInstance(this);
    551    }
    552
    553    /**
    554     * Gets the name of the ConnectionPoolDataSource which backs this pool. This name is used to look up the data source
    555     * from a JNDI service provider.
    556     *
    557     * @return value of dataSourceName.
    558     */
    559    public String getDataSourceName() {
    560        return dataSourceName;
    561    }
    562
    563    /**
    564     * Sets the name of the ConnectionPoolDataSource which backs this pool. This name is used to look up the data source
    565     * from a JNDI service provider.
    566     *
    567     * @param v
    568     *            Value to assign to dataSourceName.
    569     */
    570    public void setDataSourceName(final String v) {
    571        assertInitializationAllowed();
    572        if (dataSource != null) {
    573            throw new IllegalStateException("Cannot set the JNDI name for the DataSource, if already "
    574                    + "set using setConnectionPoolDataSource.");
    575        }
    576        if (dataSourceName != null) {
    577            throw new IllegalStateException("The DataSourceName has already been set. " + "It cannot be altered.");
    578        }
    579        this.dataSourceName = v;
    580        instanceKey = InstanceKeyDataSourceFactory.registerNewInstance(this);
    581    }
    582
    583    /**
    584     * Gets the value of defaultAutoCommit, which defines the state of connections handed out from this pool. The value
    585     * can be changed on the Connection using Connection.setAutoCommit(boolean). The default is <code>null</code> which
    586     * will use the default value for the drive.
    587     *
    588     * @return value of defaultAutoCommit.
    589     */
    590    public Boolean isDefaultAutoCommit() {
    591        return defaultAutoCommit;
    592    }
    593
    594    /**
    595     * Sets the value of defaultAutoCommit, which defines the state of connections handed out from this pool. The value
    596     * can be changed on the Connection using Connection.setAutoCommit(boolean). The default is <code>null</code> which
    597     * will use the default value for the drive.
    598     *
    599     * @param v
    600     *            Value to assign to defaultAutoCommit.
    601     */
    602    public void setDefaultAutoCommit(final Boolean v) {
    603        assertInitializationAllowed();
    604        this.defaultAutoCommit = v;
    605    }
    606
    607    /**
    608     * Gets the value of defaultReadOnly, which defines the state of connections handed out from this pool. The value
    609     * can be changed on the Connection using Connection.setReadOnly(boolean). The default is <code>null</code> which
    610     * will use the default value for the drive.
    611     *
    612     * @return value of defaultReadOnly.
    613     */
    614    public Boolean isDefaultReadOnly() {
    615        return defaultReadOnly;
    616    }
    617
    618    /**
    619     * Sets the value of defaultReadOnly, which defines the state of connections handed out from this pool. The value
    620     * can be changed on the Connection using Connection.setReadOnly(boolean). The default is <code>null</code> which
    621     * will use the default value for the drive.
    622     *
    623     * @param v
    624     *            Value to assign to defaultReadOnly.
    625     */
    626    public void setDefaultReadOnly(final Boolean v) {
    627        assertInitializationAllowed();
    628        this.defaultReadOnly = v;
    629    }
    630
    631    /**
    632     * Gets the value of defaultTransactionIsolation, which defines the state of connections handed out from this pool.
    633     * The value can be changed on the Connection using Connection.setTransactionIsolation(int). If this method returns
    634     * -1, the default is JDBC driver dependent.
    635     *
    636     * @return value of defaultTransactionIsolation.
    637     */
    638    public int getDefaultTransactionIsolation() {
    639        return defaultTransactionIsolation;
    640    }
    641
    642    /**
    643     * Sets the value of defaultTransactionIsolation, which defines the state of connections handed out from this pool.
    644     * The value can be changed on the Connection using Connection.setTransactionIsolation(int). The default is JDBC
    645     * driver dependent.
    646     *
    647     * @param v
    648     *            Value to assign to defaultTransactionIsolation
    649     */
    650    public void setDefaultTransactionIsolation(final int v) {
    651        assertInitializationAllowed();
    652        switch (v) {
    653        case Connection.TRANSACTION_NONE:
    654        case Connection.TRANSACTION_READ_COMMITTED:
    655        case Connection.TRANSACTION_READ_UNCOMMITTED:
    656        case Connection.TRANSACTION_REPEATABLE_READ:
    657        case Connection.TRANSACTION_SERIALIZABLE:
    658            break;
    659        default:
    660            throw new IllegalArgumentException(BAD_TRANSACTION_ISOLATION);
    661        }
    662        this.defaultTransactionIsolation = v;
    663    }
    664
    665    /**
    666     * Gets the description. This property is defined by JDBC as for use with GUI (or other) tools that might deploy the
    667     * datasource. It serves no internal purpose.
    668     *
    669     * @return value of description.
    670     */
    671    public String getDescription() {
    672        return description;
    673    }
    674
    675    /**
    676     * Sets the description. This property is defined by JDBC as for use with GUI (or other) tools that might deploy the
    677     * datasource. It serves no internal purpose.
    678     *
    679     * @param v
    680     *            Value to assign to description.
    681     */
    682    public void setDescription(final String v) {
    683        this.description = v;
    684    }
    685
    686    protected String getInstanceKey() {
    687        return instanceKey;
    688    }
    689
    690    /**
    691     * Gets the value of jndiEnvironment which is used when instantiating a JNDI InitialContext. This InitialContext is
    692     * used to locate the backend ConnectionPoolDataSource.
    693     *
    694     * @param key
    695     *            JNDI environment key.
    696     * @return value of jndiEnvironment.
    697     */
    698    public String getJndiEnvironment(final String key) {
    699        String value = null;
    700        if (jndiEnvironment != null) {
    701            value = jndiEnvironment.getProperty(key);
    702        }
    703        return value;
    704    }
    705
    706    /**
    707     * Sets the value of the given JNDI environment property to be used when instantiating a JNDI InitialContext. This
    708     * InitialContext is used to locate the backend ConnectionPoolDataSource.
    709     *
    710     * @param key
    711     *            the JNDI environment property to set.
    712     * @param value
    713     *            the value assigned to specified JNDI environment property.
    714     */
    715    public void setJndiEnvironment(final String key, final String value) {
    716        if (jndiEnvironment == null) {
    717            jndiEnvironment = new Properties();
    718        }
    719        jndiEnvironment.setProperty(key, value);
    720    }
    721
    722    /**
    723     * Sets the JNDI environment to be used when instantiating a JNDI InitialContext. This InitialContext is used to
    724     * locate the backend ConnectionPoolDataSource.
    725     *
    726     * @param properties
    727     *            the JNDI environment property to set which will overwrite any current settings
    728     */
    729    void setJndiEnvironment(final Properties properties) {
    730        if (jndiEnvironment == null) {
    731            jndiEnvironment = new Properties();
    732        } else {
    733            jndiEnvironment.clear();
    734        }
    735        jndiEnvironment.putAll(properties);
    736    }
    737
    738    /**
    739     * Gets the value of loginTimeout.
    740     *
    741     * @return value of loginTimeout.
    742     */
    743    @Override
    744    public int getLoginTimeout() {
    745        return loginTimeout;
    746    }
    747
    748    /**
    749     * Sets the value of loginTimeout.
    750     *
    751     * @param v
    752     *            Value to assign to loginTimeout.
    753     */
    754    @Override
    755    public void setLoginTimeout(final int v) {
    756        this.loginTimeout = v;
    757    }
    758
    759    /**
    760     * Gets the value of logWriter.
    761     *
    762     * @return value of logWriter.
    763     */
    764    @Override
    765    public PrintWriter getLogWriter() {
    766        if (logWriter == null) {
    767            logWriter = new PrintWriter(new OutputStreamWriter(System.out, StandardCharsets.UTF_8));
    768        }
    769        return logWriter;
    770    }
    771
    772    /**
    773     * Sets the value of logWriter.
    774     *
    775     * @param v
    776     *            Value to assign to logWriter.
    777     */
    778    @Override
    779    public void setLogWriter(final PrintWriter v) {
    780        this.logWriter = v;
    781    }
    782
    783    /**
    784     * Gets the SQL query that will be used to validate connections from this pool before returning them to the caller.
    785     * If specified, this query <strong>MUST</strong> be an SQL SELECT statement that returns at least one row. If not
    786     * specified, {@link Connection#isValid(int)} will be used to validate connections.
    787     *
    788     * @return The SQL query that will be used to validate connections from this pool before returning them to the
    789     *         caller.
    790     */
    791    public String getValidationQuery() {
    792        return this.validationQuery;
    793    }
    794
    795    /**
    796     * Sets the SQL query that will be used to validate connections from this pool before returning them to the caller.
    797     * If specified, this query <strong>MUST</strong> be an SQL SELECT statement that returns at least one row. If not
    798     * specified, connections will be validated using {@link Connection#isValid(int)}.
    799     *
    800     * @param validationQuery
    801     *            The SQL query that will be used to validate connections from this pool before returning them to the
    802     *            caller.
    803     */
    804    public void setValidationQuery(final String validationQuery) {
    805        assertInitializationAllowed();
    806        this.validationQuery = validationQuery;
    807    }
    808
    809    /**
    810     * Returns the timeout in seconds before the validation query fails.
    811     *
    812     * @return The timeout in seconds before the validation query fails.
    813     */
    814    public int getValidationQueryTimeout() {
    815        return validationQueryTimeoutSeconds;
    816    }
    817
    818    /**
    819     * Sets the timeout in seconds before the validation query fails.
    820     *
    821     * @param validationQueryTimeoutSeconds
    822     *            The new timeout in seconds
    823     */
    824    public void setValidationQueryTimeout(final int validationQueryTimeoutSeconds) {
    825        this.validationQueryTimeoutSeconds = validationQueryTimeoutSeconds;
    826    }
    827
    828    /**
    829     * Whether a rollback will be issued after executing the SQL query that will be used to validate connections from
    830     * this pool before returning them to the caller.
    831     *
    832     * @return true if a rollback will be issued after executing the validation query
    833     */
    834    public boolean isRollbackAfterValidation() {
    835        return this.rollbackAfterValidation;
    836    }
    837
    838    /**
    839     * Whether a rollback will be issued after executing the SQL query that will be used to validate connections from
    840     * this pool before returning them to the caller. Default behavior is NOT to issue a rollback. The setting will only
    841     * have an effect if a validation query is set
    842     *
    843     * @param rollbackAfterValidation
    844     *            new property value
    845     */
    846    public void setRollbackAfterValidation(final boolean rollbackAfterValidation) {
    847        assertInitializationAllowed();
    848        this.rollbackAfterValidation = rollbackAfterValidation;
    849    }
    850
    851    /**
    852     * Returns the maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an
    853     * infinite lifetime.
    854     *
    855     * @return The maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an
    856     *         infinite lifetime.
    857     */
    858    public long getMaxConnLifetimeMillis() {
    859        return maxConnLifetimeMillis;
    860    }
    861
    862    /**
    863     * <p>
    864     * Sets the maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an
    865     * infinite lifetime.
    866     * </p>
    867     * <p>
    868     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
    869     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
    870     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
    871     * </p>
    872     *
    873     * @param maxConnLifetimeMillis
    874     *            The maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an
    875     *            infinite lifetime.
    876     */
    877    public void setMaxConnLifetimeMillis(final long maxConnLifetimeMillis) {
    878        this.maxConnLifetimeMillis = maxConnLifetimeMillis;
    879    }
    880
    881    // ----------------------------------------------------------------------
    882    // Instrumentation Methods
    883
    884    // ----------------------------------------------------------------------
    885    // DataSource implementation
    886
    887    /**
    888     * Attempts to establish a database connection.
    889     */
    890    @Override
    891    public Connection getConnection() throws SQLException {
    892        return getConnection(null, null);
    893    }
    894
    895    /**
    896     * Attempts to retrieve a database connection using {@link #getPooledConnectionAndInfo(String, String)} with the
    897     * provided user name and password. The password on the {@link PooledConnectionAndInfo} instance returned by
    898     * <code>getPooledConnectionAndInfo</code> is compared to the <code>password</code> parameter. If the comparison
    899     * fails, a database connection using the supplied user name and password is attempted. If the connection attempt
    900     * fails, an SQLException is thrown, indicating that the given password did not match the password used to create
    901     * the pooled connection. If the connection attempt succeeds, this means that the database password has been
    902     * changed. In this case, the <code>PooledConnectionAndInfo</code> instance retrieved with the old password is
    903     * destroyed and the <code>getPooledConnectionAndInfo</code> is repeatedly invoked until a
    904     * <code>PooledConnectionAndInfo</code> instance with the new password is returned.
    905     */
    906    @Override
    907    public Connection getConnection(final String userName, final String userPassword) throws SQLException {
    908        if (instanceKey == null) {
    909            throw new SQLException("Must set the ConnectionPoolDataSource "
    910                    + "through setDataSourceName or setConnectionPoolDataSource" + " before calling getConnection.");
    911        }
    912        getConnectionCalled = true;
    913        PooledConnectionAndInfo info = null;
    914        try {
    915            info = getPooledConnectionAndInfo(userName, userPassword);
    916        } catch (final NoSuchElementException e) {
    917            closeDueToException(info);
    918            throw new SQLException("Cannot borrow connection from pool", e);
    919        } catch (final RuntimeException e) {
    920            closeDueToException(info);
    921            throw e;
    922        } catch (final SQLException e) {
    923            closeDueToException(info);
    924            throw e;
    925        } catch (final Exception e) {
    926            closeDueToException(info);
    927            throw new SQLException("Cannot borrow connection from pool", e);
    928        }
    929
    930        // Password on PooledConnectionAndInfo does not match
    931        if (!(null == userPassword ? null == info.getPassword() : userPassword.equals(info.getPassword()))) {
    932            try { // See if password has changed by attempting connection
    933                testCPDS(userName, userPassword);
    934            } catch (final SQLException ex) {
    935                // Password has not changed, so refuse client, but return connection to the pool
    936                closeDueToException(info);
    937                throw new SQLException(
    938                        "Given password did not match password used" + " to create the PooledConnection.", ex);
    939            } catch (final javax.naming.NamingException ne) {
    940                throw new SQLException("NamingException encountered connecting to database", ne);
    941            }
    942            /*
    943             * Password must have changed -> destroy connection and keep retrying until we get a new, good one,
    944             * destroying any idle connections with the old password as we pull them from the pool.
    945             */
    946            final UserPassKey upkey = info.getUserPassKey();
    947            final PooledConnectionManager manager = getConnectionManager(upkey);
    948            // Destroy and remove from pool
    949            manager.invalidate(info.getPooledConnection());
    950            // Reset the password on the factory if using CPDSConnectionFactory
    951            manager.setPassword(upkey.getPassword());
    952            info = null;
    953            for (int i = 0; i < 10; i++) { // Bound the number of retries - only needed if bad instances return
    954                try {
    955                    info = getPooledConnectionAndInfo(userName, userPassword);
    956                } catch (final NoSuchElementException e) {
    957                    closeDueToException(info);
    958                    throw new SQLException("Cannot borrow connection from pool", e);
    959                } catch (final RuntimeException e) {
    960                    closeDueToException(info);
    961                    throw e;
    962                } catch (final SQLException e) {
    963                    closeDueToException(info);
    964                    throw e;
    965                } catch (final Exception e) {
    966                    closeDueToException(info);
    967                    throw new SQLException("Cannot borrow connection from pool", e);
    968                }
    969                if (info != null && userPassword != null && userPassword.equals(info.getPassword())) {
    970                    break;
    971                }
    972                if (info != null) {
    973                    manager.invalidate(info.getPooledConnection());
    974                }
    975                info = null;
    976            }
    977            if (info == null) {
    978                throw new SQLException("Cannot borrow connection from pool - password change failure.");
    979            }
    980        }
    981
    982        final Connection con = info.getPooledConnection().getConnection();
    983        try {
    984            setupDefaults(con, userName);
    985            con.clearWarnings();
    986            return con;
    987        } catch (final SQLException ex) {
    988            try {
    989                con.close();
    990            } catch (final Exception exc) {
    991                getLogWriter().println("ignoring exception during close: " + exc);
    992            }
    993            throw ex;
    994        }
    995    }
    996
    997    protected abstract PooledConnectionAndInfo getPooledConnectionAndInfo(String userName, String userPassword)
    998            throws SQLException;
    999
    1000    protected abstract void setupDefaults(Connection connection, String userName) throws SQLException;
    1001
    1002    private void closeDueToException(final PooledConnectionAndInfo info) {
    1003        if (info != null) {
    1004            try {
    1005                info.getPooledConnection().getConnection().close();
    1006            } catch (final Exception e) {
    1007                // do not throw this exception because we are in the middle
    1008                // of handling another exception. But record it because
    1009                // it potentially leaks connections from the pool.
    1010                getLogWriter().println("[ERROR] Could not return connection to " + "pool during exception handling. "
    1011                        + e.getMessage());
    1012            }
    1013        }
    1014    }
    1015
    1016    protected ConnectionPoolDataSource testCPDS(final String userName, final String userPassword)
    1017            throws javax.naming.NamingException, SQLException {
    1018        // The source of physical db connections
    1019        ConnectionPoolDataSource cpds = this.dataSource;
    1020        if (cpds == null) {
    1021            Context ctx = null;
    1022            if (jndiEnvironment == null) {
    1023                ctx = new InitialContext();
    1024            } else {
    1025                ctx = new InitialContext(jndiEnvironment);
    1026            }
    1027            final Object ds = ctx.lookup(dataSourceName);
    1028            if (ds instanceof ConnectionPoolDataSource) {
    1029                cpds = (ConnectionPoolDataSource) ds;
    1030            } else {
    1031                throw new SQLException("Illegal configuration: " + "DataSource " + dataSourceName + " ("
    1032                        + ds.getClass().getName() + ")" + " doesn't implement javax.sql.ConnectionPoolDataSource");
    1033            }
    1034        }
    1035
    1036        // try to get a connection with the supplied userName/password
    1037        PooledConnection conn = null;
    1038        try {
    1039            if (userName != null) {
    1040                conn = cpds.getPooledConnection(userName, userPassword);
    1041            } else {
    1042                conn = cpds.getPooledConnection();
    1043            }
    1044            if (conn == null) {
    1045                throw new SQLException("Cannot connect using the supplied userName/password");
    1046            }
    1047        } finally {
    1048            if (conn != null) {
    1049                try {
    1050                    conn.close();
    1051                } catch (final SQLException e) {
    1052                    // at least we could connect
    1053                }
    1054            }
    1055        }
    1056        return cpds;
    1057    }
    1058
    1059    /**
    1060     * @since 2.6.0
    1061     */
    1062    @Override
    1063    public synchronized String toString() {
    1064        final StringBuilder builder = new StringBuilder(super.toString());
    1065        builder.append("[");
    1066        toStringFields(builder);
    1067        builder.append("]");
    1068        return builder.toString();
    1069    }
    1070
    1071    protected void toStringFields(final StringBuilder builder) {
    1072        builder.append("getConnectionCalled=");
    1073        builder.append(getConnectionCalled);
    1074        builder.append(", dataSource=");
    1075        builder.append(dataSource);
    1076        builder.append(", dataSourceName=");
    1077        builder.append(dataSourceName);
    1078        builder.append(", description=");
    1079        builder.append(description);
    1080        builder.append(", jndiEnvironment=");
    1081        builder.append(jndiEnvironment);
    1082        builder.append(", loginTimeout=");
    1083        builder.append(loginTimeout);
    1084        builder.append(", logWriter=");
    1085        builder.append(logWriter);
    1086        builder.append(", instanceKey=");
    1087        builder.append(instanceKey);
    1088        builder.append(", defaultBlockWhenExhausted=");
    1089        builder.append(defaultBlockWhenExhausted);
    1090        builder.append(", defaultEvictionPolicyClassName=");
    1091        builder.append(defaultEvictionPolicyClassName);
    1092        builder.append(", defaultLifo=");
    1093        builder.append(defaultLifo);
    1094        builder.append(", defaultMaxIdle=");
    1095        builder.append(defaultMaxIdle);
    1096        builder.append(", defaultMaxTotal=");
    1097        builder.append(defaultMaxTotal);
    1098        builder.append(", defaultMaxWaitMillis=");
    1099        builder.append(defaultMaxWaitMillis);
    1100        builder.append(", defaultMinEvictableIdleTimeMillis=");
    1101        builder.append(defaultMinEvictableIdleTimeMillis);
    1102        builder.append(", defaultMinIdle=");
    1103        builder.append(defaultMinIdle);
    1104        builder.append(", defaultNumTestsPerEvictionRun=");
    1105        builder.append(defaultNumTestsPerEvictionRun);
    1106        builder.append(", defaultSoftMinEvictableIdleTimeMillis=");
    1107        builder.append(defaultSoftMinEvictableIdleTimeMillis);
    1108        builder.append(", defaultTestOnCreate=");
    1109        builder.append(defaultTestOnCreate);
    1110        builder.append(", defaultTestOnBorrow=");
    1111        builder.append(defaultTestOnBorrow);
    1112        builder.append(", defaultTestOnReturn=");
    1113        builder.append(defaultTestOnReturn);
    1114        builder.append(", defaultTestWhileIdle=");
    1115        builder.append(defaultTestWhileIdle);
    1116        builder.append(", defaultTimeBetweenEvictionRunsMillis=");
    1117        builder.append(defaultTimeBetweenEvictionRunsMillis);
    1118        builder.append(", validationQuery=");
    1119        builder.append(validationQuery);
    1120        builder.append(", validationQueryTimeoutSeconds=");
    1121        builder.append(validationQueryTimeoutSeconds);
    1122        builder.append(", rollbackAfterValidation=");
    1123        builder.append(rollbackAfterValidation);
    1124        builder.append(", maxConnLifetimeMillis=");
    1125        builder.append(maxConnLifetimeMillis);
    1126        builder.append(", defaultAutoCommit=");
    1127        builder.append(defaultAutoCommit);
    1128        builder.append(", defaultTransactionIsolation=");
    1129        builder.append(defaultTransactionIsolation);
    1130        builder.append(", defaultReadOnly=");
    1131        builder.append(defaultReadOnly);
    1132    }
    1133}