InstanceKeyDataSource.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.apache.commons.dbcp2.datasources;

  18. import java.io.OutputStreamWriter;
  19. import java.io.PrintWriter;
  20. import java.io.Serializable;
  21. import java.nio.charset.StandardCharsets;
  22. import java.sql.Connection;
  23. import java.sql.SQLException;
  24. import java.sql.SQLFeatureNotSupportedException;
  25. import java.time.Duration;
  26. import java.util.Properties;
  27. import java.util.logging.Logger;

  28. import javax.naming.Context;
  29. import javax.naming.InitialContext;
  30. import javax.naming.Referenceable;
  31. import javax.sql.ConnectionPoolDataSource;
  32. import javax.sql.DataSource;
  33. import javax.sql.PooledConnection;

  34. import org.apache.commons.dbcp2.Utils;
  35. import org.apache.commons.pool2.impl.BaseObjectPoolConfig;
  36. import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;
  37. import org.apache.commons.pool2.impl.GenericObjectPool;

  38. /**
  39.  * <p>
  40.  * The base class for {@code SharedPoolDataSource} and {@code PerUserPoolDataSource}. Many of the
  41.  * configuration properties are shared and defined here. This class is declared public in order to allow particular
  42.  * usage with commons-beanutils; do not make direct use of it outside of <em>commons-dbcp2</em>.
  43.  * </p>
  44.  *
  45.  * <p>
  46.  * A J2EE container will normally provide some method of initializing the {@code DataSource} whose attributes are
  47.  * presented as bean getters/setters and then deploying it via JNDI. It is then available to an application as a source
  48.  * of pooled logical connections to the database. The pool needs a source of physical connections. This source is in the
  49.  * form of a {@code ConnectionPoolDataSource} that can be specified via the {@link #setDataSourceName(String)} used
  50.  * to lookup the source via JNDI.
  51.  * </p>
  52.  *
  53.  * <p>
  54.  * Although normally used within a JNDI environment, A DataSource can be instantiated and initialized as any bean. In
  55.  * this case the {@code ConnectionPoolDataSource} will likely be instantiated in a similar manner. This class
  56.  * allows the physical source of connections to be attached directly to this pool using the
  57.  * {@link #setConnectionPoolDataSource(ConnectionPoolDataSource)} method.
  58.  * </p>
  59.  *
  60.  * <p>
  61.  * The dbcp package contains an adapter, {@link org.apache.commons.dbcp2.cpdsadapter.DriverAdapterCPDS}, that can be
  62.  * used to allow the use of {@code DataSource}'s based on this class with JDBC driver implementations that do not
  63.  * supply a {@code ConnectionPoolDataSource}, but still provide a {@link java.sql.Driver} implementation.
  64.  * </p>
  65.  *
  66.  * <p>
  67.  * The <a href="package-summary.html">package documentation</a> contains an example using Apache Tomcat and JNDI and it
  68.  * also contains a non-JNDI example.
  69.  * </p>
  70.  *
  71.  * @since 2.0
  72.  */
  73. public abstract class InstanceKeyDataSource implements DataSource, Referenceable, Serializable, AutoCloseable {

  74.     private static final long serialVersionUID = -6819270431752240878L;

  75.     private static final String GET_CONNECTION_CALLED = "A Connection was already requested from this source, "
  76.             + "further initialization is not allowed.";
  77.     private static final String BAD_TRANSACTION_ISOLATION = "The requested TransactionIsolation level is invalid.";

  78.     /**
  79.      * Internal constant to indicate the level is not set.
  80.      */
  81.     protected static final int UNKNOWN_TRANSACTIONISOLATION = -1;

  82.     /** Guards property setters - once true, setters throw IllegalStateException */
  83.     private volatile boolean getConnectionCalled;

  84.     /** Underlying source of PooledConnections */
  85.     private ConnectionPoolDataSource dataSource;

  86.     /** DataSource Name used to find the ConnectionPoolDataSource */
  87.     private String dataSourceName;

  88.     /** Description */
  89.     private String description;

  90.     /** Environment that may be used to set up a JNDI initial context. */
  91.     private Properties jndiEnvironment;

  92.     /** Login Timeout */
  93.     private Duration loginTimeoutDuration = Duration.ZERO;

  94.     /** Log stream */
  95.     private PrintWriter logWriter;

  96.     /** Instance key */
  97.     private String instanceKey;

  98.     // Pool properties
  99.     private boolean defaultBlockWhenExhausted = BaseObjectPoolConfig.DEFAULT_BLOCK_WHEN_EXHAUSTED;
  100.     private String defaultEvictionPolicyClassName = BaseObjectPoolConfig.DEFAULT_EVICTION_POLICY_CLASS_NAME;
  101.     private boolean defaultLifo = BaseObjectPoolConfig.DEFAULT_LIFO;
  102.     private int defaultMaxIdle = GenericKeyedObjectPoolConfig.DEFAULT_MAX_IDLE_PER_KEY;
  103.     private int defaultMaxTotal = GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL;
  104.     private Duration defaultMaxWaitDuration = BaseObjectPoolConfig.DEFAULT_MAX_WAIT;
  105.     private Duration defaultMinEvictableIdleDuration = BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_DURATION;
  106.     private int defaultMinIdle = GenericKeyedObjectPoolConfig.DEFAULT_MIN_IDLE_PER_KEY;
  107.     private int defaultNumTestsPerEvictionRun = BaseObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
  108.     private Duration defaultSoftMinEvictableIdleDuration = BaseObjectPoolConfig.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_DURATION;
  109.     private boolean defaultTestOnCreate = BaseObjectPoolConfig.DEFAULT_TEST_ON_CREATE;
  110.     private boolean defaultTestOnBorrow = BaseObjectPoolConfig.DEFAULT_TEST_ON_BORROW;
  111.     private boolean defaultTestOnReturn = BaseObjectPoolConfig.DEFAULT_TEST_ON_RETURN;
  112.     private boolean defaultTestWhileIdle = BaseObjectPoolConfig.DEFAULT_TEST_WHILE_IDLE;
  113.     private Duration defaultDurationBetweenEvictionRuns = BaseObjectPoolConfig.DEFAULT_DURATION_BETWEEN_EVICTION_RUNS;

  114.     // Connection factory properties
  115.     private String validationQuery;
  116.     private Duration validationQueryTimeoutDuration = Duration.ofSeconds(-1);
  117.     private boolean rollbackAfterValidation;
  118.     private Duration maxConnDuration = Duration.ofMillis(-1);

  119.     // Connection properties
  120.     private Boolean defaultAutoCommit;
  121.     private int defaultTransactionIsolation = UNKNOWN_TRANSACTIONISOLATION;
  122.     private Boolean defaultReadOnly;

  123.     /**
  124.      * Default no-arg constructor for Serialization.
  125.      */
  126.     public InstanceKeyDataSource() {
  127.     }

  128.     /**
  129.      * Throws an IllegalStateException, if a PooledConnection has already been requested.
  130.      *
  131.      * @throws IllegalStateException Thrown if a PooledConnection has already been requested.
  132.      */
  133.     protected void assertInitializationAllowed() throws IllegalStateException {
  134.         if (getConnectionCalled) {
  135.             throw new IllegalStateException(GET_CONNECTION_CALLED);
  136.         }
  137.     }

  138.     /**
  139.      * Closes the connection pool being maintained by this datasource.
  140.      */
  141.     @Override
  142.     public abstract void close() throws SQLException;

  143.     private void closeDueToException(final PooledConnectionAndInfo info) {
  144.         if (info != null) {
  145.             try {
  146.                 info.getPooledConnection().getConnection().close();
  147.             } catch (final Exception e) {
  148.                 // do not throw this exception because we are in the middle
  149.                 // of handling another exception. But record it because
  150.                 // it potentially leaks connections from the pool.
  151.                 getLogWriter().println("[ERROR] Could not return connection to pool during exception handling. " + e.getMessage());
  152.             }
  153.         }
  154.     }

  155.     /**
  156.      * Attempts to establish a database connection.
  157.      */
  158.     @Override
  159.     public Connection getConnection() throws SQLException {
  160.         return getConnection(null, null);
  161.     }

  162.     /**
  163.      * Attempts to retrieve a database connection using {@link #getPooledConnectionAndInfo(String, String)} with the
  164.      * provided user name and password. The password on the {@code PooledConnectionAndInfo} instance returned by
  165.      * {@code getPooledConnectionAndInfo} is compared to the {@code password} parameter. If the comparison
  166.      * fails, a database connection using the supplied user name and password is attempted. If the connection attempt
  167.      * fails, an SQLException is thrown, indicating that the given password did not match the password used to create
  168.      * the pooled connection. If the connection attempt succeeds, this means that the database password has been
  169.      * changed. In this case, the {@code PooledConnectionAndInfo} instance retrieved with the old password is
  170.      * destroyed and the {@code getPooledConnectionAndInfo} is repeatedly invoked until a
  171.      * {@code PooledConnectionAndInfo} instance with the new password is returned.
  172.      */
  173.     @Override
  174.     public Connection getConnection(final String userName, final String userPassword) throws SQLException {
  175.         if (instanceKey == null) {
  176.             throw new SQLException("Must set the ConnectionPoolDataSource "
  177.                     + "through setDataSourceName or setConnectionPoolDataSource" + " before calling getConnection.");
  178.         }
  179.         getConnectionCalled = true;
  180.         PooledConnectionAndInfo info = null;
  181.         try {
  182.             info = getPooledConnectionAndInfo(userName, userPassword);
  183.         } catch (final RuntimeException | SQLException e) {
  184.             closeDueToException(info);
  185.             throw e;
  186.         } catch (final Exception e) {
  187.             closeDueToException(info);
  188.             throw new SQLException("Cannot borrow connection from pool", e);
  189.         }

  190.         // Password on PooledConnectionAndInfo does not match
  191.         if (!(null == userPassword ? null == info.getPassword() : userPassword.equals(info.getPassword()))) {
  192.             try { // See if password has changed by attempting connection
  193.                 testCPDS(userName, userPassword);
  194.             } catch (final SQLException ex) {
  195.                 // Password has not changed, so refuse client, but return connection to the pool
  196.                 closeDueToException(info);
  197.                 throw new SQLException(
  198.                         "Given password did not match password used" + " to create the PooledConnection.", ex);
  199.             } catch (final javax.naming.NamingException ne) {
  200.                 throw new SQLException("NamingException encountered connecting to database", ne);
  201.             }
  202.             /*
  203.              * Password must have changed -> destroy connection and keep retrying until we get a new, good one,
  204.              * destroying any idle connections with the old password as we pull them from the pool.
  205.              */
  206.             final UserPassKey upkey = info.getUserPassKey();
  207.             final PooledConnectionManager manager = getConnectionManager(upkey);
  208.             // Destroy and remove from pool
  209.             manager.invalidate(info.getPooledConnection());
  210.             // Reset the password on the factory if using CPDSConnectionFactory
  211.             manager.setPassword(upkey.getPassword());
  212.             info = null;
  213.             for (int i = 0; i < 10; i++) { // Bound the number of retries - only needed if bad instances return
  214.                 try {
  215.                     info = getPooledConnectionAndInfo(userName, userPassword);
  216.                 } catch (final RuntimeException | SQLException e) {
  217.                     closeDueToException(info);
  218.                     throw e;
  219.                 } catch (final Exception e) {
  220.                     closeDueToException(info);
  221.                     throw new SQLException("Cannot borrow connection from pool", e);
  222.                 }
  223.                 if (info != null && userPassword != null && userPassword.equals(info.getPassword())) {
  224.                     break;
  225.                 }
  226.                 if (info != null) {
  227.                     manager.invalidate(info.getPooledConnection());
  228.                 }
  229.                 info = null;
  230.             }
  231.             if (info == null) {
  232.                 throw new SQLException("Cannot borrow connection from pool - password change failure.");
  233.             }
  234.         }

  235.         final Connection connection = info.getPooledConnection().getConnection();
  236.         try {
  237.             setupDefaults(connection, userName);
  238.             connection.clearWarnings();
  239.             return connection;
  240.         } catch (final SQLException ex) {
  241.             Utils.close(connection, e -> getLogWriter().println("ignoring exception during close: " + e));
  242.             throw ex;
  243.         }
  244.     }

  245.     protected abstract PooledConnectionManager getConnectionManager(UserPassKey upkey);

  246.     /**
  247.      * Gets the value of connectionPoolDataSource. This method will return null, if the backing data source is being
  248.      * accessed via JNDI.
  249.      *
  250.      * @return value of connectionPoolDataSource.
  251.      */
  252.     public ConnectionPoolDataSource getConnectionPoolDataSource() {
  253.         return dataSource;
  254.     }

  255.     /**
  256.      * Gets the name of the ConnectionPoolDataSource which backs this pool. This name is used to look up the data source
  257.      * from a JNDI service provider.
  258.      *
  259.      * @return value of dataSourceName.
  260.      */
  261.     public String getDataSourceName() {
  262.         return dataSourceName;
  263.     }

  264.     /**
  265.      * Gets the default value for {@link GenericKeyedObjectPoolConfig#getBlockWhenExhausted()} for each per user pool.
  266.      *
  267.      * @return The default value for {@link GenericKeyedObjectPoolConfig#getBlockWhenExhausted()} for each per user
  268.      *         pool.
  269.      */
  270.     public boolean getDefaultBlockWhenExhausted() {
  271.         return this.defaultBlockWhenExhausted;
  272.     }

  273.     /**
  274.      * Gets the default value for {@link GenericObjectPool#getDurationBetweenEvictionRuns()} for each per user pool.
  275.      *
  276.      * @return The default value for {@link GenericObjectPool#getDurationBetweenEvictionRuns()} for each per user pool.
  277.      * @since 2.10.0
  278.      */
  279.     public Duration getDefaultDurationBetweenEvictionRuns() {
  280.         return this.defaultDurationBetweenEvictionRuns;
  281.     }

  282.     /**
  283.      * Gets the default value for {@link GenericKeyedObjectPoolConfig#getEvictionPolicyClassName()} for each per user
  284.      * pool.
  285.      *
  286.      * @return The default value for {@link GenericKeyedObjectPoolConfig#getEvictionPolicyClassName()} for each per user
  287.      *         pool.
  288.      */
  289.     public String getDefaultEvictionPolicyClassName() {
  290.         return this.defaultEvictionPolicyClassName;
  291.     }

  292.     /**
  293.      * Gets the default value for {@link GenericKeyedObjectPoolConfig#getLifo()} for each per user pool.
  294.      *
  295.      * @return The default value for {@link GenericKeyedObjectPoolConfig#getLifo()} for each per user pool.
  296.      */
  297.     public boolean getDefaultLifo() {
  298.         return this.defaultLifo;
  299.     }

  300.     /**
  301.      * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMaxIdlePerKey()} for each per user pool.
  302.      *
  303.      * @return The default value for {@link GenericKeyedObjectPoolConfig#getMaxIdlePerKey()} for each per user pool.
  304.      */
  305.     public int getDefaultMaxIdle() {
  306.         return this.defaultMaxIdle;
  307.     }

  308.     /**
  309.      * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMaxTotalPerKey()} for each per user pool.
  310.      *
  311.      * @return The default value for {@link GenericKeyedObjectPoolConfig#getMaxTotalPerKey()} for each per user pool.
  312.      */
  313.     public int getDefaultMaxTotal() {
  314.         return this.defaultMaxTotal;
  315.     }

  316.     /**
  317.      * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitDuration()} for each per user pool.
  318.      *
  319.      * @return The default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitDuration()} for each per user pool.
  320.      * @since 2.9.0
  321.      */
  322.     public Duration getDefaultMaxWait() {
  323.         return this.defaultMaxWaitDuration;
  324.     }

  325.     /**
  326.      * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitDuration()} for each per user pool.
  327.      *
  328.      * @return The default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitDuration()} for each per user pool.
  329.      * @deprecated Use {@link #getDefaultMaxWait()}.
  330.      */
  331.     @Deprecated
  332.     public long getDefaultMaxWaitMillis() {
  333.         return getDefaultMaxWait().toMillis();
  334.     }

  335.     /**
  336.      * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleDuration()} for each per user
  337.      * pool.
  338.      *
  339.      * @return The default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleDuration()} for each per
  340.      *         user pool.
  341.      * @since 2.10.0
  342.      */
  343.     public Duration getDefaultMinEvictableIdleDuration() {
  344.         return this.defaultMinEvictableIdleDuration;
  345.     }

  346.     /**
  347.      * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleDuration()} for each per user
  348.      * pool.
  349.      *
  350.      * @return The default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleDuration()} for each per
  351.      *         user pool.
  352.      * @deprecated Use {@link #getDefaultMinEvictableIdleDuration()}.
  353.      */
  354.     @Deprecated
  355.     public long getDefaultMinEvictableIdleTimeMillis() {
  356.         return this.defaultMinEvictableIdleDuration.toMillis();
  357.     }

  358.     /**
  359.      * Gets the default value for {@link GenericKeyedObjectPoolConfig#getMinIdlePerKey()} for each per user pool.
  360.      *
  361.      * @return The default value for {@link GenericKeyedObjectPoolConfig#getMinIdlePerKey()} for each per user pool.
  362.      */
  363.     public int getDefaultMinIdle() {
  364.         return this.defaultMinIdle;
  365.     }

  366.     /**
  367.      * Gets the default value for {@link GenericKeyedObjectPoolConfig#getNumTestsPerEvictionRun()} for each per user
  368.      * pool.
  369.      *
  370.      * @return The default value for {@link GenericKeyedObjectPoolConfig#getNumTestsPerEvictionRun()} for each per user
  371.      *         pool.
  372.      */
  373.     public int getDefaultNumTestsPerEvictionRun() {
  374.         return this.defaultNumTestsPerEvictionRun;
  375.     }

  376.     /**
  377.      * Gets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
  378.      * GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool.
  379.      *
  380.      * @return The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
  381.      *         GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool.
  382.      * @since 2.10.0
  383.      */
  384.     public Duration getDefaultSoftMinEvictableIdleDuration() {
  385.         return this.defaultSoftMinEvictableIdleDuration;
  386.     }

  387.     /**
  388.      * Gets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
  389.      * GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool.
  390.      *
  391.      * @return The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
  392.      *         GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool.
  393.      * @deprecated Use {@link #getDefaultSoftMinEvictableIdleDuration()}.
  394.      */
  395.     @Deprecated
  396.     public long getDefaultSoftMinEvictableIdleTimeMillis() {
  397.         return this.defaultSoftMinEvictableIdleDuration.toMillis();
  398.     }

  399.     /**
  400.      * Gets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
  401.      * GenericObjectPool#getTestOnBorrow()} for each per user pool.
  402.      *
  403.      * @return The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
  404.      *         GenericObjectPool#getTestOnBorrow()} for each per user pool.
  405.      */
  406.     public boolean getDefaultTestOnBorrow() {
  407.         return this.defaultTestOnBorrow;
  408.     }

  409.     /**
  410.      * Gets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
  411.      * GenericObjectPool#getTestOnCreate()} for each per user pool.
  412.      *
  413.      * @return The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
  414.      *         GenericObjectPool#getTestOnCreate()} for each per user pool.
  415.      */
  416.     public boolean getDefaultTestOnCreate() {
  417.         return this.defaultTestOnCreate;
  418.     }

  419.     /**
  420.      * Gets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
  421.      * GenericObjectPool#getTestOnReturn()} for each per user pool.
  422.      *
  423.      * @return The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
  424.      *         GenericObjectPool#getTestOnReturn()} for each per user pool.
  425.      */
  426.     public boolean getDefaultTestOnReturn() {
  427.         return this.defaultTestOnReturn;
  428.     }

  429.     /**
  430.      * Gets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
  431.      * GenericObjectPool#getTestWhileIdle()} for each per user pool.
  432.      *
  433.      * @return The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
  434.      *         GenericObjectPool#getTestWhileIdle()} for each per user pool.
  435.      */
  436.     public boolean getDefaultTestWhileIdle() {
  437.         return this.defaultTestWhileIdle;
  438.     }

  439.     /**
  440.      * Gets the default value for {@link GenericObjectPool#getDurationBetweenEvictionRuns ()} for each per user pool.
  441.      *
  442.      * @return The default value for {@link GenericObjectPool#getDurationBetweenEvictionRuns ()} for each per user pool.
  443.      * @deprecated Use {@link #getDefaultDurationBetweenEvictionRuns()}.
  444.      */
  445.     @Deprecated
  446.     public long getDefaultTimeBetweenEvictionRunsMillis() {
  447.         return this.defaultDurationBetweenEvictionRuns.toMillis();
  448.     }

  449.     /**
  450.      * Gets the value of defaultTransactionIsolation, which defines the state of connections handed out from this pool.
  451.      * The value can be changed on the Connection using Connection.setTransactionIsolation(int). If this method returns
  452.      * -1, the default is JDBC driver dependent.
  453.      *
  454.      * @return value of defaultTransactionIsolation.
  455.      */
  456.     public int getDefaultTransactionIsolation() {
  457.         return defaultTransactionIsolation;
  458.     }

  459.     /**
  460.      * Gets the description. This property is defined by JDBC as for use with GUI (or other) tools that might deploy the
  461.      * datasource. It serves no internal purpose.
  462.      *
  463.      * @return value of description.
  464.      */
  465.     public String getDescription() {
  466.         return description;
  467.     }

  468.     /**
  469.      * Gets the instance key.
  470.      *
  471.      * @return the instance key.
  472.      */
  473.     protected String getInstanceKey() {
  474.         return instanceKey;
  475.     }

  476.     /**
  477.      * Gets the value of jndiEnvironment which is used when instantiating a JNDI InitialContext. This InitialContext is
  478.      * used to locate the back end ConnectionPoolDataSource.
  479.      *
  480.      * @param key
  481.      *            JNDI environment key.
  482.      * @return value of jndiEnvironment.
  483.      */
  484.     public String getJndiEnvironment(final String key) {
  485.         String value = null;
  486.         if (jndiEnvironment != null) {
  487.             value = jndiEnvironment.getProperty(key);
  488.         }
  489.         return value;
  490.     }

  491.     /**
  492.      * Gets the value of loginTimeout.
  493.      *
  494.      * @return value of loginTimeout.
  495.      * @deprecated Use {@link #getLoginTimeoutDuration()}.
  496.      */
  497.     @Deprecated
  498.     @Override
  499.     public int getLoginTimeout() {
  500.         return (int) loginTimeoutDuration.getSeconds();
  501.     }

  502.     /**
  503.      * Gets the value of loginTimeout.
  504.      *
  505.      * @return value of loginTimeout.
  506.      * @since 2.10.0
  507.      */
  508.     public Duration getLoginTimeoutDuration() {
  509.         return loginTimeoutDuration;
  510.     }

  511.     /**
  512.      * Gets the value of logWriter.
  513.      *
  514.      * @return value of logWriter.
  515.      */
  516.     @Override
  517.     public PrintWriter getLogWriter() {
  518.         if (logWriter == null) {
  519.             logWriter = new PrintWriter(new OutputStreamWriter(System.out, StandardCharsets.UTF_8));
  520.         }
  521.         return logWriter;
  522.     }

  523.     /**
  524.      * Gets the maximum permitted lifetime of a connection. A value of zero or less indicates an
  525.      * infinite lifetime.
  526.      *
  527.      * @return The maximum permitted lifetime of a connection. A value of zero or less indicates an
  528.      *         infinite lifetime.
  529.      * @since 2.10.0
  530.      */
  531.     public Duration getMaxConnDuration() {
  532.         return maxConnDuration;
  533.     }

  534.     /**
  535.      * Gets the maximum permitted lifetime of a connection. A value of zero or less indicates an
  536.      * infinite lifetime.
  537.      *
  538.      * @return The maximum permitted lifetime of a connection. A value of zero or less indicates an
  539.      *         infinite lifetime.
  540.      * @deprecated Use {@link #getMaxConnDuration()}.
  541.      */
  542.     @Deprecated
  543.     public Duration getMaxConnLifetime() {
  544.         return maxConnDuration;
  545.     }

  546.     /**
  547.      * Gets the maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an
  548.      * infinite lifetime.
  549.      *
  550.      * @return The maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an
  551.      *         infinite lifetime.
  552.      * @deprecated Use {@link #getMaxConnLifetime()}.
  553.      */
  554.     @Deprecated
  555.     public long getMaxConnLifetimeMillis() {
  556.         return maxConnDuration.toMillis();
  557.     }

  558.     @Override
  559.     public Logger getParentLogger() throws SQLFeatureNotSupportedException {
  560.         throw new SQLFeatureNotSupportedException();
  561.     }

  562.     /**
  563.      * This method is protected but can only be implemented in this package because PooledConnectionAndInfo is a package
  564.      * private type.
  565.      *
  566.      * @param userName The user name.
  567.      * @param userPassword The user password.
  568.      * @return Matching PooledConnectionAndInfo.
  569.      * @throws SQLException Connection or registration failure.
  570.      */
  571.     protected abstract PooledConnectionAndInfo getPooledConnectionAndInfo(String userName, String userPassword)
  572.             throws SQLException;

  573.     /**
  574.      * Gets the SQL query that will be used to validate connections from this pool before returning them to the caller.
  575.      * If specified, this query <strong>MUST</strong> be an SQL SELECT statement that returns at least one row. If not
  576.      * specified, {@link Connection#isValid(int)} will be used to validate connections.
  577.      *
  578.      * @return The SQL query that will be used to validate connections from this pool before returning them to the
  579.      *         caller.
  580.      */
  581.     public String getValidationQuery() {
  582.         return this.validationQuery;
  583.     }

  584.     /**
  585.      * Returns the timeout in seconds before the validation query fails.
  586.      *
  587.      * @return The timeout in seconds before the validation query fails.
  588.      * @deprecated Use {@link #getValidationQueryTimeoutDuration()}.
  589.      */
  590.     @Deprecated
  591.     public int getValidationQueryTimeout() {
  592.         return (int) validationQueryTimeoutDuration.getSeconds();
  593.     }

  594.     /**
  595.      * Returns the timeout Duration before the validation query fails.
  596.      *
  597.      * @return The timeout Duration before the validation query fails.
  598.      */
  599.     public Duration getValidationQueryTimeoutDuration() {
  600.         return validationQueryTimeoutDuration;
  601.     }

  602.     /**
  603.      * Gets the value of defaultAutoCommit, which defines the state of connections handed out from this pool. The value
  604.      * can be changed on the Connection using Connection.setAutoCommit(boolean). The default is {@code null} which
  605.      * will use the default value for the drive.
  606.      *
  607.      * @return value of defaultAutoCommit.
  608.      */
  609.     public Boolean isDefaultAutoCommit() {
  610.         return defaultAutoCommit;
  611.     }

  612.     /**
  613.      * Gets the value of defaultReadOnly, which defines the state of connections handed out from this pool. The value
  614.      * can be changed on the Connection using Connection.setReadOnly(boolean). The default is {@code null} which
  615.      * will use the default value for the drive.
  616.      *
  617.      * @return value of defaultReadOnly.
  618.      */
  619.     public Boolean isDefaultReadOnly() {
  620.         return defaultReadOnly;
  621.     }

  622.     /**
  623.      * Whether a rollback will be issued after executing the SQL query that will be used to validate connections from
  624.      * this pool before returning them to the caller.
  625.      *
  626.      * @return true if a rollback will be issued after executing the validation query
  627.      */
  628.     public boolean isRollbackAfterValidation() {
  629.         return this.rollbackAfterValidation;
  630.     }

  631.     @Override
  632.     public boolean isWrapperFor(final Class<?> iface) throws SQLException {
  633.         return iface.isInstance(this);
  634.     }

  635.     /**
  636.      * Sets the back end ConnectionPoolDataSource. This property should not be set if using JNDI to access the
  637.      * data source.
  638.      *
  639.      * @param dataSource
  640.      *            Value to assign to connectionPoolDataSource.
  641.      */
  642.     public void setConnectionPoolDataSource(final ConnectionPoolDataSource dataSource) {
  643.         assertInitializationAllowed();
  644.         if (dataSourceName != null) {
  645.             throw new IllegalStateException("Cannot set the DataSource, if JNDI is used.");
  646.         }
  647.         if (this.dataSource != null) {
  648.             throw new IllegalStateException("The CPDS has already been set. It cannot be altered.");
  649.         }
  650.         this.dataSource = dataSource;
  651.         instanceKey = InstanceKeyDataSourceFactory.registerNewInstance(this);
  652.     }

  653.     /**
  654.      * Sets the name of the ConnectionPoolDataSource which backs this pool. This name is used to look up the data source
  655.      * from a JNDI service provider.
  656.      *
  657.      * @param dataSourceName
  658.      *            Value to assign to dataSourceName.
  659.      */
  660.     public void setDataSourceName(final String dataSourceName) {
  661.         assertInitializationAllowed();
  662.         if (dataSource != null) {
  663.             throw new IllegalStateException("Cannot set the JNDI name for the DataSource, if already "
  664.                     + "set using setConnectionPoolDataSource.");
  665.         }
  666.         if (this.dataSourceName != null) {
  667.             throw new IllegalStateException("The DataSourceName has already been set. " + "It cannot be altered.");
  668.         }
  669.         this.dataSourceName = dataSourceName;
  670.         instanceKey = InstanceKeyDataSourceFactory.registerNewInstance(this);
  671.     }

  672.     /**
  673.      * Sets the value of defaultAutoCommit, which defines the state of connections handed out from this pool. The value
  674.      * can be changed on the Connection using Connection.setAutoCommit(boolean). The default is {@code null} which
  675.      * will use the default value for the drive.
  676.      *
  677.      * @param defaultAutoCommit
  678.      *            Value to assign to defaultAutoCommit.
  679.      */
  680.     public void setDefaultAutoCommit(final Boolean defaultAutoCommit) {
  681.         assertInitializationAllowed();
  682.         this.defaultAutoCommit = defaultAutoCommit;
  683.     }

  684.     /**
  685.      * Sets the default value for {@link GenericKeyedObjectPoolConfig#getBlockWhenExhausted()} for each per user pool.
  686.      *
  687.      * @param blockWhenExhausted
  688.      *            The default value for {@link GenericKeyedObjectPoolConfig#getBlockWhenExhausted()} for each per user
  689.      *            pool.
  690.      */
  691.     public void setDefaultBlockWhenExhausted(final boolean blockWhenExhausted) {
  692.         assertInitializationAllowed();
  693.         this.defaultBlockWhenExhausted = blockWhenExhausted;
  694.     }

  695.     /**
  696.      * Sets the default value for {@link GenericObjectPool#getDurationBetweenEvictionRuns ()} for each per user pool.
  697.      *
  698.      * @param defaultDurationBetweenEvictionRuns The default value for
  699.      *        {@link GenericObjectPool#getDurationBetweenEvictionRuns ()} for each per user pool.
  700.      * @since 2.10.0
  701.      */
  702.     public void setDefaultDurationBetweenEvictionRuns(final Duration defaultDurationBetweenEvictionRuns) {
  703.         assertInitializationAllowed();
  704.         this.defaultDurationBetweenEvictionRuns = defaultDurationBetweenEvictionRuns;
  705.     }

  706.     /**
  707.      * Sets the default value for {@link GenericKeyedObjectPoolConfig#getEvictionPolicyClassName()} for each per user
  708.      * pool.
  709.      *
  710.      * @param evictionPolicyClassName
  711.      *            The default value for {@link GenericKeyedObjectPoolConfig#getEvictionPolicyClassName()} for each per
  712.      *            user pool.
  713.      */
  714.     public void setDefaultEvictionPolicyClassName(final String evictionPolicyClassName) {
  715.         assertInitializationAllowed();
  716.         this.defaultEvictionPolicyClassName = evictionPolicyClassName;
  717.     }

  718.     /**
  719.      * Sets the default value for {@link GenericKeyedObjectPoolConfig#getLifo()} for each per user pool.
  720.      *
  721.      * @param lifo
  722.      *            The default value for {@link GenericKeyedObjectPoolConfig#getLifo()} for each per user pool.
  723.      */
  724.     public void setDefaultLifo(final boolean lifo) {
  725.         assertInitializationAllowed();
  726.         this.defaultLifo = lifo;
  727.     }

  728.     /**
  729.      * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMaxIdlePerKey()} for each per user pool.
  730.      *
  731.      * @param maxIdle
  732.      *            The default value for {@link GenericKeyedObjectPoolConfig#getMaxIdlePerKey()} for each per user pool.
  733.      */
  734.     public void setDefaultMaxIdle(final int maxIdle) {
  735.         assertInitializationAllowed();
  736.         this.defaultMaxIdle = maxIdle;
  737.     }

  738.     /**
  739.      * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMaxTotalPerKey()} for each per user pool.
  740.      *
  741.      * @param maxTotal
  742.      *            The default value for {@link GenericKeyedObjectPoolConfig#getMaxTotalPerKey()} for each per user pool.
  743.      */
  744.     public void setDefaultMaxTotal(final int maxTotal) {
  745.         assertInitializationAllowed();
  746.         this.defaultMaxTotal = maxTotal;
  747.     }

  748.     /**
  749.      * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitDuration()} for each per user pool.
  750.      *
  751.      * @param maxWaitMillis
  752.      *            The default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitDuration()} for each per user pool.
  753.      * @since 2.9.0
  754.      */
  755.     public void setDefaultMaxWait(final Duration maxWaitMillis) {
  756.         assertInitializationAllowed();
  757.         this.defaultMaxWaitDuration = maxWaitMillis;
  758.     }

  759.     /**
  760.      * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitMillis()} for each per user pool.
  761.      *
  762.      * @param maxWaitMillis
  763.      *            The default value for {@link GenericKeyedObjectPoolConfig#getMaxWaitMillis()} for each per user pool.
  764.      * @deprecated Use {@link #setDefaultMaxWait(Duration)}.
  765.      */
  766.     @Deprecated
  767.     public void setDefaultMaxWaitMillis(final long maxWaitMillis) {
  768.         setDefaultMaxWait(Duration.ofMillis(maxWaitMillis));
  769.     }

  770.     /**
  771.      * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleDuration()} for each per user
  772.      * pool.
  773.      *
  774.      * @param defaultMinEvictableIdleDuration
  775.      *            The default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleDuration()} for each
  776.      *            per user pool.
  777.      * @since 2.10.0
  778.      */
  779.     public void setDefaultMinEvictableIdle(final Duration defaultMinEvictableIdleDuration) {
  780.         assertInitializationAllowed();
  781.         this.defaultMinEvictableIdleDuration = defaultMinEvictableIdleDuration;
  782.     }

  783.     /**
  784.      * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleDuration()} for each per user
  785.      * pool.
  786.      *
  787.      * @param minEvictableIdleTimeMillis
  788.      *            The default value for {@link GenericKeyedObjectPoolConfig#getMinEvictableIdleDuration()} for each
  789.      *            per user pool.
  790.      * @deprecated Use {@link #setDefaultMinEvictableIdle(Duration)}.
  791.      */
  792.     @Deprecated
  793.     public void setDefaultMinEvictableIdleTimeMillis(final long minEvictableIdleTimeMillis) {
  794.         assertInitializationAllowed();
  795.         this.defaultMinEvictableIdleDuration = Duration.ofMillis(minEvictableIdleTimeMillis);
  796.     }

  797.     /**
  798.      * Sets the default value for {@link GenericKeyedObjectPoolConfig#getMinIdlePerKey()} for each per user pool.
  799.      *
  800.      * @param minIdle
  801.      *            The default value for {@link GenericKeyedObjectPoolConfig#getMinIdlePerKey()} for each per user pool.
  802.      */
  803.     public void setDefaultMinIdle(final int minIdle) {
  804.         assertInitializationAllowed();
  805.         this.defaultMinIdle = minIdle;
  806.     }

  807.     /**
  808.      * Sets the default value for {@link GenericKeyedObjectPoolConfig#getNumTestsPerEvictionRun()} for each per user
  809.      * pool.
  810.      *
  811.      * @param numTestsPerEvictionRun
  812.      *            The default value for {@link GenericKeyedObjectPoolConfig#getNumTestsPerEvictionRun()} for each per
  813.      *            user pool.
  814.      */
  815.     public void setDefaultNumTestsPerEvictionRun(final int numTestsPerEvictionRun) {
  816.         assertInitializationAllowed();
  817.         this.defaultNumTestsPerEvictionRun = numTestsPerEvictionRun;
  818.     }

  819.     /**
  820.      * Sets the value of defaultReadOnly, which defines the state of connections handed out from this pool. The value
  821.      * can be changed on the Connection using Connection.setReadOnly(boolean). The default is {@code null} which
  822.      * will use the default value for the drive.
  823.      *
  824.      * @param defaultReadOnly
  825.      *            Value to assign to defaultReadOnly.
  826.      */
  827.     public void setDefaultReadOnly(final Boolean defaultReadOnly) {
  828.         assertInitializationAllowed();
  829.         this.defaultReadOnly = defaultReadOnly;
  830.     }

  831.     /**
  832.      * Sets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
  833.      * GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool.
  834.      *
  835.      * @param defaultSoftMinEvictableIdleDuration
  836.      *            The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
  837.      *            GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool.
  838.      * @since 2.10.0
  839.      */
  840.     public void setDefaultSoftMinEvictableIdle(final Duration defaultSoftMinEvictableIdleDuration) {
  841.         assertInitializationAllowed();
  842.         this.defaultSoftMinEvictableIdleDuration = defaultSoftMinEvictableIdleDuration;
  843.     }

  844.     /**
  845.      * Sets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
  846.      * GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool.
  847.      *
  848.      * @param softMinEvictableIdleTimeMillis
  849.      *            The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
  850.      *            GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for each per user pool.
  851.      * @deprecated Use {@link #setDefaultSoftMinEvictableIdle(Duration)}.
  852.      */
  853.     @Deprecated
  854.     public void setDefaultSoftMinEvictableIdleTimeMillis(final long softMinEvictableIdleTimeMillis) {
  855.         assertInitializationAllowed();
  856.         this.defaultSoftMinEvictableIdleDuration = Duration.ofMillis(softMinEvictableIdleTimeMillis);
  857.     }

  858.     /**
  859.      * Sets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
  860.      * GenericObjectPool#getTestOnBorrow()} for each per user pool.
  861.      *
  862.      * @param testOnBorrow
  863.      *            The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
  864.      *            GenericObjectPool#getTestOnBorrow()} for each per user pool.
  865.      */
  866.     public void setDefaultTestOnBorrow(final boolean testOnBorrow) {
  867.         assertInitializationAllowed();
  868.         this.defaultTestOnBorrow = testOnBorrow;
  869.     }

  870.     /**
  871.      * Sets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
  872.      * GenericObjectPool#getTestOnCreate()} for each per user pool.
  873.      *
  874.      * @param testOnCreate
  875.      *            The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
  876.      *            GenericObjectPool#getTestOnCreate()} for each per user pool.
  877.      */
  878.     public void setDefaultTestOnCreate(final boolean testOnCreate) {
  879.         assertInitializationAllowed();
  880.         this.defaultTestOnCreate = testOnCreate;
  881.     }

  882.     /**
  883.      * Sets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
  884.      * GenericObjectPool#getTestOnReturn()} for each per user pool.
  885.      *
  886.      * @param testOnReturn
  887.      *            The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
  888.      *            GenericObjectPool#getTestOnReturn()} for each per user pool.
  889.      */
  890.     public void setDefaultTestOnReturn(final boolean testOnReturn) {
  891.         assertInitializationAllowed();
  892.         this.defaultTestOnReturn = testOnReturn;
  893.     }

  894.     /**
  895.      * Sets the default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
  896.      * GenericObjectPool#getTestWhileIdle()} for each per user pool.
  897.      *
  898.      * @param testWhileIdle
  899.      *            The default value for {@link org.apache.commons.pool2.impl.GenericObjectPool
  900.      *            GenericObjectPool#getTestWhileIdle()} for each per user pool.
  901.      */
  902.     public void setDefaultTestWhileIdle(final boolean testWhileIdle) {
  903.         assertInitializationAllowed();
  904.         this.defaultTestWhileIdle = testWhileIdle;
  905.     }

  906.     /**
  907.      * Sets the default value for {@link GenericObjectPool#getDurationBetweenEvictionRuns()} for each per user pool.
  908.      *
  909.      * @param timeBetweenEvictionRunsMillis The default value for
  910.      *        {@link GenericObjectPool#getDurationBetweenEvictionRuns()} for each per user pool.
  911.      * @deprecated Use {@link #setDefaultDurationBetweenEvictionRuns(Duration)}.
  912.      */
  913.     @Deprecated
  914.     public void setDefaultTimeBetweenEvictionRunsMillis(final long timeBetweenEvictionRunsMillis) {
  915.         assertInitializationAllowed();
  916.         this.defaultDurationBetweenEvictionRuns = Duration.ofMillis(timeBetweenEvictionRunsMillis);
  917.     }

  918.     /**
  919.      * Sets the value of defaultTransactionIsolation, which defines the state of connections handed out from this pool.
  920.      * The value can be changed on the Connection using Connection.setTransactionIsolation(int). The default is JDBC
  921.      * driver dependent.
  922.      *
  923.      * @param defaultTransactionIsolation
  924.      *            Value to assign to defaultTransactionIsolation
  925.      */
  926.     public void setDefaultTransactionIsolation(final int defaultTransactionIsolation) {
  927.         assertInitializationAllowed();
  928.         switch (defaultTransactionIsolation) {
  929.         case Connection.TRANSACTION_NONE:
  930.         case Connection.TRANSACTION_READ_COMMITTED:
  931.         case Connection.TRANSACTION_READ_UNCOMMITTED:
  932.         case Connection.TRANSACTION_REPEATABLE_READ:
  933.         case Connection.TRANSACTION_SERIALIZABLE:
  934.             break;
  935.         default:
  936.             throw new IllegalArgumentException(BAD_TRANSACTION_ISOLATION);
  937.         }
  938.         this.defaultTransactionIsolation = defaultTransactionIsolation;
  939.     }

  940.     /**
  941.      * Sets the description. This property is defined by JDBC as for use with GUI (or other) tools that might deploy the
  942.      * datasource. It serves no internal purpose.
  943.      *
  944.      * @param description
  945.      *            Value to assign to description.
  946.      */
  947.     public void setDescription(final String description) {
  948.         this.description = description;
  949.     }

  950.     /**
  951.      * Sets the JNDI environment to be used when instantiating a JNDI InitialContext. This InitialContext is used to
  952.      * locate the back end ConnectionPoolDataSource.
  953.      *
  954.      * @param properties
  955.      *            the JNDI environment property to set which will overwrite any current settings
  956.      */
  957.     void setJndiEnvironment(final Properties properties) {
  958.         if (jndiEnvironment == null) {
  959.             jndiEnvironment = new Properties();
  960.         } else {
  961.             jndiEnvironment.clear();
  962.         }
  963.         jndiEnvironment.putAll(properties);
  964.     }

  965.     /**
  966.      * Sets the value of the given JNDI environment property to be used when instantiating a JNDI InitialContext. This
  967.      * InitialContext is used to locate the back end ConnectionPoolDataSource.
  968.      *
  969.      * @param key
  970.      *            the JNDI environment property to set.
  971.      * @param value
  972.      *            the value assigned to specified JNDI environment property.
  973.      */
  974.     public void setJndiEnvironment(final String key, final String value) {
  975.         if (jndiEnvironment == null) {
  976.             jndiEnvironment = new Properties();
  977.         }
  978.         jndiEnvironment.setProperty(key, value);
  979.     }

  980.     /**
  981.      * Sets the value of loginTimeout.
  982.      *
  983.      * @param loginTimeout
  984.      *            Value to assign to loginTimeout.
  985.      * @since 2.10.0
  986.      */
  987.     public void setLoginTimeout(final Duration loginTimeout) {
  988.         this.loginTimeoutDuration = loginTimeout;
  989.     }

  990.     /**
  991.      * Sets the value of loginTimeout.
  992.      *
  993.      * @param loginTimeout
  994.      *            Value to assign to loginTimeout.
  995.      * @deprecated Use {@link #setLoginTimeout(Duration)}.
  996.      */
  997.     @Deprecated
  998.     @Override
  999.     public void setLoginTimeout(final int loginTimeout) {
  1000.         this.loginTimeoutDuration = Duration.ofSeconds(loginTimeout);
  1001.     }

  1002.     /**
  1003.      * Sets the value of logWriter.
  1004.      *
  1005.      * @param logWriter
  1006.      *            Value to assign to logWriter.
  1007.      */
  1008.     @Override
  1009.     public void setLogWriter(final PrintWriter logWriter) {
  1010.         this.logWriter = logWriter;
  1011.     }

  1012.     /**
  1013.      * <p>
  1014.      * Sets the maximum permitted lifetime of a connection. A value of zero or less indicates an infinite lifetime.
  1015.      * </p>
  1016.      * <p>
  1017.      * 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
  1018.      * invoked: {@link #getConnection()}, {@link #setLogWriter(PrintWriter)}, {@link #setLoginTimeout(Duration)}, {@link #getLoginTimeoutDuration()},
  1019.      * {@link #getLogWriter()}.
  1020.      * </p>
  1021.      *
  1022.      * @param maxConnLifetimeMillis The maximum permitted lifetime of a connection. A value of zero or less indicates an infinite lifetime.
  1023.      * @since 2.9.0
  1024.      */
  1025.     public void setMaxConnLifetime(final Duration maxConnLifetimeMillis) {
  1026.         this.maxConnDuration = maxConnLifetimeMillis;
  1027.     }

  1028.     /**
  1029.      * <p>
  1030.      * Sets the maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an infinite lifetime.
  1031.      * </p>
  1032.      * <p>
  1033.      * 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
  1034.      * invoked: {@link #getConnection()}, {@link #setLogWriter(PrintWriter)}, {@link #setLoginTimeout(Duration)}, {@link #getLoginTimeoutDuration()},
  1035.      * {@link #getLogWriter()}.
  1036.      * </p>
  1037.      *
  1038.      * @param maxConnLifetimeMillis The maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an infinite lifetime.
  1039.      * @deprecated Use {@link #setMaxConnLifetime(Duration)}.
  1040.      */
  1041.     @Deprecated
  1042.     public void setMaxConnLifetimeMillis(final long maxConnLifetimeMillis) {
  1043.         setMaxConnLifetime(Duration.ofMillis(maxConnLifetimeMillis));
  1044.     }

  1045.     /**
  1046.      * Whether a rollback will be issued after executing the SQL query that will be used to validate connections from
  1047.      * this pool before returning them to the caller. Default behavior is NOT to issue a rollback. The setting will only
  1048.      * have an effect if a validation query is set
  1049.      *
  1050.      * @param rollbackAfterValidation
  1051.      *            new property value
  1052.      */
  1053.     public void setRollbackAfterValidation(final boolean rollbackAfterValidation) {
  1054.         assertInitializationAllowed();
  1055.         this.rollbackAfterValidation = rollbackAfterValidation;
  1056.     }

  1057.     protected abstract void setupDefaults(Connection connection, String userName) throws SQLException;

  1058.     /**
  1059.      * Sets the SQL query that will be used to validate connections from this pool before returning them to the caller.
  1060.      * If specified, this query <strong>MUST</strong> be an SQL SELECT statement that returns at least one row. If not
  1061.      * specified, connections will be validated using {@link Connection#isValid(int)}.
  1062.      *
  1063.      * @param validationQuery
  1064.      *            The SQL query that will be used to validate connections from this pool before returning them to the
  1065.      *            caller.
  1066.      */
  1067.     public void setValidationQuery(final String validationQuery) {
  1068.         assertInitializationAllowed();
  1069.         this.validationQuery = validationQuery;
  1070.     }

  1071.     /**
  1072.      * Sets the timeout duration before the validation query fails.
  1073.      *
  1074.      * @param validationQueryTimeoutDuration
  1075.      *            The new timeout duration.
  1076.      */
  1077.     public void setValidationQueryTimeout(final Duration validationQueryTimeoutDuration) {
  1078.         this.validationQueryTimeoutDuration = validationQueryTimeoutDuration;
  1079.     }

  1080.     /**
  1081.      * Sets the timeout in seconds before the validation query fails.
  1082.      *
  1083.      * @param validationQueryTimeoutSeconds
  1084.      *            The new timeout in seconds
  1085.      * @deprecated Use {@link #setValidationQueryTimeout(Duration)}.
  1086.      */
  1087.     @Deprecated
  1088.     public void setValidationQueryTimeout(final int validationQueryTimeoutSeconds) {
  1089.         this.validationQueryTimeoutDuration = Duration.ofSeconds(validationQueryTimeoutSeconds);
  1090.     }

  1091.     protected ConnectionPoolDataSource testCPDS(final String userName, final String userPassword)
  1092.             throws javax.naming.NamingException, SQLException {
  1093.         // The source of physical db connections
  1094.         ConnectionPoolDataSource cpds = this.dataSource;
  1095.         if (cpds == null) {
  1096.             Context ctx = null;
  1097.             if (jndiEnvironment == null) {
  1098.                 ctx = new InitialContext();
  1099.             } else {
  1100.                 ctx = new InitialContext(jndiEnvironment);
  1101.             }
  1102.             final Object ds = ctx.lookup(dataSourceName);
  1103.             if (!(ds instanceof ConnectionPoolDataSource)) {
  1104.                 throw new SQLException("Illegal configuration: " + "DataSource " + dataSourceName + " ("
  1105.                         + ds.getClass().getName() + ")" + " doesn't implement javax.sql.ConnectionPoolDataSource");
  1106.             }
  1107.             cpds = (ConnectionPoolDataSource) ds;
  1108.         }

  1109.         // try to get a connection with the supplied userName/password
  1110.         PooledConnection conn = null;
  1111.         try {
  1112.             if (userName != null) {
  1113.                 conn = cpds.getPooledConnection(userName, userPassword);
  1114.             } else {
  1115.                 conn = cpds.getPooledConnection();
  1116.             }
  1117.             if (conn == null) {
  1118.                 throw new SQLException("Cannot connect using the supplied userName/password");
  1119.             }
  1120.         } finally {
  1121.             if (conn != null) {
  1122.                 try {
  1123.                     conn.close();
  1124.                 } catch (final SQLException ignored) {
  1125.                     // at least we could connect
  1126.                 }
  1127.             }
  1128.         }
  1129.         return cpds;
  1130.     }

  1131.     /**
  1132.      * @since 2.6.0
  1133.      */
  1134.     @Override
  1135.     public synchronized String toString() {
  1136.         final StringBuilder builder = new StringBuilder(super.toString());
  1137.         builder.append('[');
  1138.         toStringFields(builder);
  1139.         builder.append(']');
  1140.         return builder.toString();
  1141.     }

  1142.     protected void toStringFields(final StringBuilder builder) {
  1143.         builder.append("getConnectionCalled=");
  1144.         builder.append(getConnectionCalled);
  1145.         builder.append(", dataSource=");
  1146.         builder.append(dataSource);
  1147.         builder.append(", dataSourceName=");
  1148.         builder.append(dataSourceName);
  1149.         builder.append(", description=");
  1150.         builder.append(description);
  1151.         builder.append(", jndiEnvironment=");
  1152.         builder.append(jndiEnvironment);
  1153.         builder.append(", loginTimeoutDuration=");
  1154.         builder.append(loginTimeoutDuration);
  1155.         builder.append(", logWriter=");
  1156.         builder.append(logWriter);
  1157.         builder.append(", instanceKey=");
  1158.         builder.append(instanceKey);
  1159.         builder.append(", defaultBlockWhenExhausted=");
  1160.         builder.append(defaultBlockWhenExhausted);
  1161.         builder.append(", defaultEvictionPolicyClassName=");
  1162.         builder.append(defaultEvictionPolicyClassName);
  1163.         builder.append(", defaultLifo=");
  1164.         builder.append(defaultLifo);
  1165.         builder.append(", defaultMaxIdle=");
  1166.         builder.append(defaultMaxIdle);
  1167.         builder.append(", defaultMaxTotal=");
  1168.         builder.append(defaultMaxTotal);
  1169.         builder.append(", defaultMaxWaitDuration=");
  1170.         builder.append(defaultMaxWaitDuration);
  1171.         builder.append(", defaultMinEvictableIdleDuration=");
  1172.         builder.append(defaultMinEvictableIdleDuration);
  1173.         builder.append(", defaultMinIdle=");
  1174.         builder.append(defaultMinIdle);
  1175.         builder.append(", defaultNumTestsPerEvictionRun=");
  1176.         builder.append(defaultNumTestsPerEvictionRun);
  1177.         builder.append(", defaultSoftMinEvictableIdleDuration=");
  1178.         builder.append(defaultSoftMinEvictableIdleDuration);
  1179.         builder.append(", defaultTestOnCreate=");
  1180.         builder.append(defaultTestOnCreate);
  1181.         builder.append(", defaultTestOnBorrow=");
  1182.         builder.append(defaultTestOnBorrow);
  1183.         builder.append(", defaultTestOnReturn=");
  1184.         builder.append(defaultTestOnReturn);
  1185.         builder.append(", defaultTestWhileIdle=");
  1186.         builder.append(defaultTestWhileIdle);
  1187.         builder.append(", defaultDurationBetweenEvictionRuns=");
  1188.         builder.append(defaultDurationBetweenEvictionRuns);
  1189.         builder.append(", validationQuery=");
  1190.         builder.append(validationQuery);
  1191.         builder.append(", validationQueryTimeoutDuration=");
  1192.         builder.append(validationQueryTimeoutDuration);
  1193.         builder.append(", rollbackAfterValidation=");
  1194.         builder.append(rollbackAfterValidation);
  1195.         builder.append(", maxConnDuration=");
  1196.         builder.append(maxConnDuration);
  1197.         builder.append(", defaultAutoCommit=");
  1198.         builder.append(defaultAutoCommit);
  1199.         builder.append(", defaultTransactionIsolation=");
  1200.         builder.append(defaultTransactionIsolation);
  1201.         builder.append(", defaultReadOnly=");
  1202.         builder.append(defaultReadOnly);
  1203.     }

  1204.     @Override
  1205.     @SuppressWarnings("unchecked")
  1206.     public <T> T unwrap(final Class<T> iface) throws SQLException {
  1207.         if (isWrapperFor(iface)) {
  1208.             return (T) this;
  1209.         }
  1210.         throw new SQLException(this + " is not a wrapper for " + iface);
  1211.     }
  1212. }