001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.dbcp2;
018
019import java.io.OutputStreamWriter;
020import java.io.PrintWriter;
021import java.nio.charset.StandardCharsets;
022import java.security.AccessController;
023import java.security.PrivilegedActionException;
024import java.security.PrivilegedExceptionAction;
025import java.sql.Connection;
026import java.sql.Driver;
027import java.sql.DriverManager;
028import java.sql.SQLException;
029import java.sql.SQLFeatureNotSupportedException;
030import java.util.ArrayList;
031import java.util.Collection;
032import java.util.Collections;
033import java.util.HashSet;
034import java.util.List;
035import java.util.Objects;
036import java.util.Properties;
037import java.util.Set;
038import java.util.logging.Logger;
039
040import javax.management.MBeanRegistration;
041import javax.management.MBeanServer;
042import javax.management.MalformedObjectNameException;
043import javax.management.ObjectName;
044import javax.sql.DataSource;
045
046import org.apache.commons.logging.Log;
047import org.apache.commons.logging.LogFactory;
048import org.apache.commons.pool2.PooledObject;
049import org.apache.commons.pool2.impl.AbandonedConfig;
050import org.apache.commons.pool2.impl.BaseObjectPoolConfig;
051import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;
052import org.apache.commons.pool2.impl.GenericObjectPool;
053import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
054
055/**
056 * <p>
057 * Basic implementation of <code>javax.sql.DataSource</code> that is configured via JavaBeans properties. This is not
058 * the only way to combine the <em>commons-dbcp2</em> and <em>commons-pool2</em> packages, but provides a "one stop
059 * shopping" solution for basic requirements.
060 * </p>
061 *
062 * @since 2.0
063 */
064public class BasicDataSource implements DataSource, BasicDataSourceMXBean, MBeanRegistration, AutoCloseable {
065
066    /**
067     * @since 2.0
068     */
069    private class PaGetConnection implements PrivilegedExceptionAction<Connection> {
070
071        @Override
072        public Connection run() throws SQLException {
073            return createDataSource().getConnection();
074        }
075    }
076
077    private static final Log log = LogFactory.getLog(BasicDataSource.class);
078
079    // ------------------------------------------------------------- Properties
080
081    static {
082        // Attempt to prevent deadlocks - see DBCP - 272
083        DriverManager.getDrivers();
084        try {
085            // Load classes now to prevent AccessControlExceptions later
086            // A number of classes are loaded when getConnection() is called
087            // but the following classes are not loaded and therefore require
088            // explicit loading.
089            if (Utils.IS_SECURITY_ENABLED) {
090                final ClassLoader loader = BasicDataSource.class.getClassLoader();
091                final String dbcpPackageName = BasicDataSource.class.getPackage().getName();
092                loader.loadClass(dbcpPackageName + ".BasicDataSource$PaGetConnection");
093                loader.loadClass(dbcpPackageName + ".DelegatingCallableStatement");
094                loader.loadClass(dbcpPackageName + ".DelegatingDatabaseMetaData");
095                loader.loadClass(dbcpPackageName + ".DelegatingPreparedStatement");
096                loader.loadClass(dbcpPackageName + ".DelegatingResultSet");
097                loader.loadClass(dbcpPackageName + ".PoolableCallableStatement");
098                loader.loadClass(dbcpPackageName + ".PoolablePreparedStatement");
099                loader.loadClass(dbcpPackageName + ".PoolingConnection$StatementType");
100                loader.loadClass(dbcpPackageName + ".PStmtKey");
101
102                final String poolPackageName = PooledObject.class.getPackage().getName();
103                loader.loadClass(poolPackageName + ".impl.LinkedBlockingDeque$Node");
104                loader.loadClass(poolPackageName + ".impl.GenericKeyedObjectPool$ObjectDeque");
105            }
106        } catch (final ClassNotFoundException cnfe) {
107            throw new IllegalStateException("Unable to pre-load classes", cnfe);
108        }
109    }
110
111    protected static void validateConnectionFactory(final PoolableConnectionFactory connectionFactory)
112            throws Exception {
113        PoolableConnection conn = null;
114        PooledObject<PoolableConnection> p = null;
115        try {
116            p = connectionFactory.makeObject();
117            conn = p.getObject();
118            connectionFactory.activateObject(p);
119            connectionFactory.validateConnection(conn);
120            connectionFactory.passivateObject(p);
121        } finally {
122            if (p != null) {
123                connectionFactory.destroyObject(p);
124            }
125        }
126    }
127
128    /**
129     * The default auto-commit state of connections created by this pool.
130     */
131    private volatile Boolean defaultAutoCommit;
132
133    /**
134     * The default read-only state of connections created by this pool.
135     */
136    private transient Boolean defaultReadOnly;
137
138    /**
139     * The default TransactionIsolation state of connections created by this pool.
140     */
141    private volatile int defaultTransactionIsolation = PoolableConnectionFactory.UNKNOWN_TRANSACTION_ISOLATION;
142
143    private Integer defaultQueryTimeoutSeconds;
144
145    /**
146     * The default "catalog" of connections created by this pool.
147     */
148    private volatile String defaultCatalog;
149
150    /**
151     * The default "schema" of connections created by this pool.
152     */
153    private volatile String defaultSchema;
154
155    /**
156     * The property that controls if the pooled connections cache some state rather than query the database for current
157     * state to improve performance.
158     */
159    private boolean cacheState = true;
160
161    /**
162     * The instance of the JDBC Driver to use.
163     */
164    private Driver driver;
165
166    /**
167     * The fully qualified Java class name of the JDBC driver to be used.
168     */
169    private String driverClassName;
170
171    /**
172     * The class loader instance to use to load the JDBC driver. If not specified, {@link Class#forName(String)} is used
173     * to load the JDBC driver. If specified, {@link Class#forName(String, boolean, ClassLoader)} is used.
174     */
175    private ClassLoader driverClassLoader;
176
177    /**
178     * True means that borrowObject returns the most recently used ("last in") connection in the pool (if there are idle
179     * connections available). False means that the pool behaves as a FIFO queue - connections are taken from the idle
180     * instance pool in the order that they are returned to the pool.
181     */
182    private boolean lifo = BaseObjectPoolConfig.DEFAULT_LIFO;
183
184    /**
185     * The maximum number of active connections that can be allocated from this pool at the same time, or negative for
186     * no limit.
187     */
188    private int maxTotal = GenericObjectPoolConfig.DEFAULT_MAX_TOTAL;
189
190    /**
191     * The maximum number of connections that can remain idle in the pool, without extra ones being destroyed, or
192     * negative for no limit. If maxIdle is set too low on heavily loaded systems it is possible you will see
193     * connections being closed and almost immediately new connections being opened. This is a result of the active
194     * threads momentarily closing connections faster than they are opening them, causing the number of idle connections
195     * to rise above maxIdle. The best value for maxIdle for heavily loaded system will vary but the default is a good
196     * starting point.
197     */
198    private int maxIdle = GenericObjectPoolConfig.DEFAULT_MAX_IDLE;
199
200    /**
201     * The minimum number of active connections that can remain idle in the pool, without extra ones being created when
202     * the evictor runs, or 0 to create none. The pool attempts to ensure that minIdle connections are available when
203     * the idle object evictor runs. The value of this property has no effect unless
204     * {@link #timeBetweenEvictionRunsMillis} has a positive value.
205     */
206    private int minIdle = GenericObjectPoolConfig.DEFAULT_MIN_IDLE;
207
208    /**
209     * The initial number of connections that are created when the pool is started.
210     */
211    private int initialSize = 0;
212
213    /**
214     * The maximum number of milliseconds that the pool will wait (when there are no available connections) for a
215     * connection to be returned before throwing an exception, or <= 0 to wait indefinitely.
216     */
217    private long maxWaitMillis = BaseObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS;
218
219    /**
220     * Prepared statement pooling for this pool. When this property is set to <code>true</code> both PreparedStatements
221     * and CallableStatements are pooled.
222     */
223    private boolean poolPreparedStatements = false;
224
225    /**
226     * <p>
227     * The maximum number of open statements that can be allocated from the statement pool at the same time, or negative
228     * for no limit. Since a connection usually only uses one or two statements at a time, this is mostly used to help
229     * detect resource leaks.
230     * </p>
231     * <p>
232     * Note: As of version 1.3, CallableStatements (those produced by {@link Connection#prepareCall}) are pooled along
233     * with PreparedStatements (produced by {@link Connection#prepareStatement}) and
234     * <code>maxOpenPreparedStatements</code> limits the total number of prepared or callable statements that may be in
235     * use at a given time.
236     * </p>
237     */
238    private int maxOpenPreparedStatements = GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL;
239
240    /**
241     * The indication of whether objects will be validated as soon as they have been created by the pool. If the object
242     * fails to validate, the borrow operation that triggered the creation will fail.
243     */
244    private boolean testOnCreate = false;
245
246    /**
247     * The indication of whether objects will be validated before being borrowed from the pool. If the object fails to
248     * validate, it will be dropped from the pool, and we will attempt to borrow another.
249     */
250    private boolean testOnBorrow = true;
251
252    /**
253     * The indication of whether objects will be validated before being returned to the pool.
254     */
255    private boolean testOnReturn = false;
256
257    /**
258     * The number of milliseconds to sleep between runs of the idle object evictor thread. When non-positive, no idle
259     * object evictor thread will be run.
260     */
261    private long timeBetweenEvictionRunsMillis = BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
262
263    /**
264     * The number of objects to examine during each run of the idle object evictor thread (if any).
265     */
266    private int numTestsPerEvictionRun = BaseObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
267
268    /**
269     * The minimum amount of time an object may sit idle in the pool before it is eligible for eviction by the idle
270     * object evictor (if any).
271     */
272    private long minEvictableIdleTimeMillis = BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
273
274    /**
275     * The minimum amount of time a connection may sit idle in the pool before it is eligible for eviction by the idle
276     * object evictor, with the extra condition that at least "minIdle" connections remain in the pool. Note that
277     * {@code minEvictableIdleTimeMillis} takes precedence over this parameter. See
278     * {@link #getSoftMinEvictableIdleTimeMillis()}.
279     */
280    private long softMinEvictableIdleTimeMillis = BaseObjectPoolConfig.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
281
282    private String evictionPolicyClassName = BaseObjectPoolConfig.DEFAULT_EVICTION_POLICY_CLASS_NAME;
283
284    /**
285     * The indication of whether objects will be validated by the idle object evictor (if any). If an object fails to
286     * validate, it will be dropped from the pool.
287     */
288    private boolean testWhileIdle = false;
289
290    /**
291     * The connection password to be passed to our JDBC driver to establish a connection.
292     */
293    private volatile String password;
294
295    /**
296     * The connection URL to be passed to our JDBC driver to establish a connection.
297     */
298    private String url;
299
300    /**
301     * The connection user name to be passed to our JDBC driver to establish a connection.
302     */
303    private String userName;
304
305    /**
306     * The SQL query that will be used to validate connections from this pool before returning them to the caller. If
307     * specified, this query <strong>MUST</strong> be an SQL SELECT statement that returns at least one row. If not
308     * specified, {@link Connection#isValid(int)} will be used to validate connections.
309     */
310    private volatile String validationQuery;
311
312    /**
313     * Timeout in seconds before connection validation queries fail.
314     */
315    private volatile int validationQueryTimeoutSeconds = -1;
316
317    /**
318     * These SQL statements run once after a Connection is created.
319     * <p>
320     * This property can be used for example to run ALTER SESSION SET NLS_SORT=XCYECH in an Oracle Database only once
321     * after connection creation.
322     * </p>
323     */
324    private volatile List<String> connectionInitSqls;
325
326    /**
327     * Controls access to the underlying connection.
328     */
329    private boolean accessToUnderlyingConnectionAllowed = false;
330
331    private long maxConnLifetimeMillis = -1;
332
333    private boolean logExpiredConnections = true;
334
335    private String jmxName;
336
337    private boolean autoCommitOnReturn = true;
338
339    private boolean rollbackOnReturn = true;
340
341    private volatile Set<String> disconnectionSqlCodes;
342
343    private boolean fastFailValidation;
344
345    /**
346     * The object pool that internally manages our connections.
347     */
348    private volatile GenericObjectPool<PoolableConnection> connectionPool;
349
350    /**
351     * The connection properties that will be sent to our JDBC driver when establishing new connections.
352     * <strong>NOTE</strong> - The "user" and "password" properties will be passed explicitly, so they do not need to be
353     * included here.
354     */
355    private Properties connectionProperties = new Properties();
356
357    /**
358     * The data source we will use to manage connections. This object should be acquired <strong>ONLY</strong> by calls
359     * to the <code>createDataSource()</code> method.
360     */
361    private volatile DataSource dataSource;
362
363    /**
364     * The PrintWriter to which log messages should be directed.
365     */
366    private volatile PrintWriter logWriter = new PrintWriter(
367            new OutputStreamWriter(System.out, StandardCharsets.UTF_8));
368
369    private AbandonedConfig abandonedConfig;
370
371    private boolean closed;
372
373    /**
374     * Actual name under which this component has been registered.
375     */
376    private ObjectNameWrapper registeredJmxObjectName;
377
378    /**
379     * Adds a custom connection property to the set that will be passed to our JDBC driver. This <strong>MUST</strong>
380     * be called before the first connection is retrieved (along with all the other configuration property setters).
381     * Calls to this method after the connection pool has been initialized have no effect.
382     *
383     * @param name
384     *            Name of the custom connection property
385     * @param value
386     *            Value of the custom connection property
387     */
388    public void addConnectionProperty(final String name, final String value) {
389        connectionProperties.put(name, value);
390    }
391
392    /**
393     * <p>
394     * Closes and releases all idle connections that are currently stored in the connection pool associated with this
395     * data source.
396     * </p>
397     * <p>
398     * Connections that are checked out to clients when this method is invoked are not affected. When client
399     * applications subsequently invoke {@link Connection#close()} to return these connections to the pool, the
400     * underlying JDBC connections are closed.
401     * </p>
402     * <p>
403     * Attempts to acquire connections using {@link #getConnection()} after this method has been invoked result in
404     * SQLExceptions.
405     * </p>
406     * <p>
407     * This method is idempotent - i.e., closing an already closed BasicDataSource has no effect and does not generate
408     * exceptions.
409     * </p>
410     *
411     * @throws SQLException
412     *             if an error occurs closing idle connections
413     */
414    @Override
415    public synchronized void close() throws SQLException {
416        if (registeredJmxObjectName != null) {
417            registeredJmxObjectName.unregisterMBean();
418            registeredJmxObjectName = null;
419        }
420        closed = true;
421        final GenericObjectPool<?> oldpool = connectionPool;
422        connectionPool = null;
423        dataSource = null;
424        try {
425            if (oldpool != null) {
426                oldpool.close();
427            }
428        } catch (final RuntimeException e) {
429            throw e;
430        } catch (final Exception e) {
431            throw new SQLException(Utils.getMessage("pool.close.fail"), e);
432        }
433    }
434
435    /**
436     * Closes the connection pool, silently swallowing any exception that occurs.
437     */
438    private void closeConnectionPool() {
439        final GenericObjectPool<?> oldPool = connectionPool;
440        connectionPool = null;
441        try {
442            if (oldPool != null) {
443                oldPool.close();
444            }
445        } catch (final Exception e) {
446            /* Ignore */
447        }
448    }
449
450    /**
451     * Creates a JDBC connection factory for this datasource. The JDBC driver is loaded using the following algorithm:
452     * <ol>
453     * <li>If a Driver instance has been specified via {@link #setDriver(Driver)} use it</li>
454     * <li>If no Driver instance was specified and {@link #driverClassName} is specified that class is loaded using the
455     * {@link ClassLoader} of this class or, if {@link #driverClassLoader} is set, {@link #driverClassName} is loaded
456     * with the specified {@link ClassLoader}.</li>
457     * <li>If {@link #driverClassName} is specified and the previous attempt fails, the class is loaded using the
458     * context class loader of the current thread.</li>
459     * <li>If a driver still isn't loaded one is loaded via the {@link DriverManager} using the specified {@link #url}.
460     * </ol>
461     * This method exists so subclasses can replace the implementation class.
462     *
463     * @return A new connection factory.
464     *
465     * @throws SQLException
466     *            If the connection factort cannot be created
467     */
468    protected ConnectionFactory createConnectionFactory() throws SQLException {
469        // Load the JDBC driver class
470        Driver driverToUse = this.driver;
471
472        if (driverToUse == null) {
473            Class<?> driverFromCCL = null;
474            if (driverClassName != null) {
475                try {
476                    try {
477                        if (driverClassLoader == null) {
478                            driverFromCCL = Class.forName(driverClassName);
479                        } else {
480                            driverFromCCL = Class.forName(driverClassName, true, driverClassLoader);
481                        }
482                    } catch (final ClassNotFoundException cnfe) {
483                        driverFromCCL = Thread.currentThread().getContextClassLoader().loadClass(driverClassName);
484                    }
485                } catch (final Exception t) {
486                    final String message = "Cannot load JDBC driver class '" + driverClassName + "'";
487                    logWriter.println(message);
488                    t.printStackTrace(logWriter);
489                    throw new SQLException(message, t);
490                }
491            }
492
493            try {
494                if (driverFromCCL == null) {
495                    driverToUse = DriverManager.getDriver(url);
496                } else {
497                    // Usage of DriverManager is not possible, as it does not
498                    // respect the ContextClassLoader
499                    // N.B. This cast may cause ClassCastException which is handled below
500                    driverToUse = (Driver) driverFromCCL.getConstructor().newInstance();
501                    if (!driverToUse.acceptsURL(url)) {
502                        throw new SQLException("No suitable driver", "08001");
503                    }
504                }
505            } catch (final Exception t) {
506                final String message = "Cannot create JDBC driver of class '"
507                        + (driverClassName != null ? driverClassName : "") + "' for connect URL '" + url + "'";
508                logWriter.println(message);
509                t.printStackTrace(logWriter);
510                throw new SQLException(message, t);
511            }
512        }
513
514        // Set up the driver connection factory we will use
515        final String user = userName;
516        if (user != null) {
517            connectionProperties.put("user", user);
518        } else {
519            log("DBCP DataSource configured without a 'username'");
520        }
521
522        final String pwd = password;
523        if (pwd != null) {
524            connectionProperties.put("password", pwd);
525        } else {
526            log("DBCP DataSource configured without a 'password'");
527        }
528
529        final ConnectionFactory driverConnectionFactory = new DriverConnectionFactory(driverToUse, url,
530                connectionProperties);
531        return driverConnectionFactory;
532    }
533
534    /**
535     * Creates a connection pool for this datasource. This method only exists so subclasses can replace the
536     * implementation class.
537     * <p>
538     * This implementation configures all pool properties other than timeBetweenEvictionRunsMillis. Setting that
539     * property is deferred to {@link #startPoolMaintenance()}, since setting timeBetweenEvictionRunsMillis to a
540     * positive value causes {@link GenericObjectPool}'s eviction timer to be started.
541     * </p>
542     *
543     * @param factory
544     *            The factory to use to create new connections for this pool.
545     */
546    protected void createConnectionPool(final PoolableConnectionFactory factory) {
547        // Create an object pool to contain our active connections
548        final GenericObjectPoolConfig<PoolableConnection> config = new GenericObjectPoolConfig<>();
549        updateJmxName(config);
550        // Disable JMX on the underlying pool if the DS is not registered:
551        config.setJmxEnabled(registeredJmxObjectName != null);
552        final GenericObjectPool<PoolableConnection> gop = createObjectPool(factory, config, abandonedConfig);
553        gop.setMaxTotal(maxTotal);
554        gop.setMaxIdle(maxIdle);
555        gop.setMinIdle(minIdle);
556        gop.setMaxWaitMillis(maxWaitMillis);
557        gop.setTestOnCreate(testOnCreate);
558        gop.setTestOnBorrow(testOnBorrow);
559        gop.setTestOnReturn(testOnReturn);
560        gop.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
561        gop.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
562        gop.setSoftMinEvictableIdleTimeMillis(softMinEvictableIdleTimeMillis);
563        gop.setTestWhileIdle(testWhileIdle);
564        gop.setLifo(lifo);
565        gop.setSwallowedExceptionListener(new SwallowedExceptionLogger(log, logExpiredConnections));
566        gop.setEvictionPolicyClassName(evictionPolicyClassName);
567        factory.setPool(gop);
568        connectionPool = gop;
569    }
570
571    /**
572     * <p>
573     * Creates (if necessary) and return the internal data source we are using to manage our connections.
574     * </p>
575     *
576     * @return The current internal DataSource or a newly created instance if it has not yet been created.
577     * @throws SQLException
578     *             if the object pool cannot be created.
579     */
580    protected DataSource createDataSource() throws SQLException {
581        if (closed) {
582            throw new SQLException("Data source is closed");
583        }
584
585        // Return the pool if we have already created it
586        // This is double-checked locking. This is safe since dataSource is
587        // volatile and the code is targeted at Java 5 onwards.
588        if (dataSource != null) {
589            return dataSource;
590        }
591        synchronized (this) {
592            if (dataSource != null) {
593                return dataSource;
594            }
595
596            jmxRegister();
597
598            // create factory which returns raw physical connections
599            final ConnectionFactory driverConnectionFactory = createConnectionFactory();
600
601            // Set up the poolable connection factory
602            boolean success = false;
603            PoolableConnectionFactory poolableConnectionFactory;
604            try {
605                poolableConnectionFactory = createPoolableConnectionFactory(driverConnectionFactory);
606                poolableConnectionFactory.setPoolStatements(poolPreparedStatements);
607                poolableConnectionFactory.setMaxOpenPreparedStatements(maxOpenPreparedStatements);
608                success = true;
609            } catch (final SQLException se) {
610                throw se;
611            } catch (final RuntimeException rte) {
612                throw rte;
613            } catch (final Exception ex) {
614                throw new SQLException("Error creating connection factory", ex);
615            }
616
617            if (success) {
618                // create a pool for our connections
619                createConnectionPool(poolableConnectionFactory);
620            }
621
622            // Create the pooling data source to manage connections
623            DataSource newDataSource;
624            success = false;
625            try {
626                newDataSource = createDataSourceInstance();
627                newDataSource.setLogWriter(logWriter);
628                success = true;
629            } catch (final SQLException se) {
630                throw se;
631            } catch (final RuntimeException rte) {
632                throw rte;
633            } catch (final Exception ex) {
634                throw new SQLException("Error creating datasource", ex);
635            } finally {
636                if (!success) {
637                    closeConnectionPool();
638                }
639            }
640
641            // If initialSize > 0, preload the pool
642            try {
643                for (int i = 0; i < initialSize; i++) {
644                    connectionPool.addObject();
645                }
646            } catch (final Exception e) {
647                closeConnectionPool();
648                throw new SQLException("Error preloading the connection pool", e);
649            }
650
651            // If timeBetweenEvictionRunsMillis > 0, start the pool's evictor task
652            startPoolMaintenance();
653
654            dataSource = newDataSource;
655            return dataSource;
656        }
657    }
658
659    /**
660     * Creates the actual data source instance. This method only exists so that subclasses can replace the
661     * implementation class.
662     *
663     * @throws SQLException
664     *             if unable to create a datasource instance
665     *
666     * @return A new DataSource instance
667     */
668    protected DataSource createDataSourceInstance() throws SQLException {
669        final PoolingDataSource<PoolableConnection> pds = new PoolingDataSource<>(connectionPool);
670        pds.setAccessToUnderlyingConnectionAllowed(isAccessToUnderlyingConnectionAllowed());
671        return pds;
672    }
673
674    /**
675     * Creates an object pool used to provide pooling support for {@link Connection JDBC connections}.
676     *
677     * @param factory
678     *            the object factory
679     * @param poolConfig
680     *            the object pool configuration
681     * @param abandonedConfig
682     *            the abandoned objects configuration
683     * @return a non-null instance
684     */
685    protected GenericObjectPool<PoolableConnection> createObjectPool(final PoolableConnectionFactory factory,
686            final GenericObjectPoolConfig<PoolableConnection> poolConfig, final AbandonedConfig abandonedConfig) {
687        GenericObjectPool<PoolableConnection> gop;
688        if (abandonedConfig != null && (abandonedConfig.getRemoveAbandonedOnBorrow()
689                || abandonedConfig.getRemoveAbandonedOnMaintenance())) {
690            gop = new GenericObjectPool<>(factory, poolConfig, abandonedConfig);
691        } else {
692            gop = new GenericObjectPool<>(factory, poolConfig);
693        }
694        return gop;
695    }
696
697    /**
698     * Creates the PoolableConnectionFactory and attaches it to the connection pool. This method only exists so
699     * subclasses can replace the default implementation.
700     *
701     * @param driverConnectionFactory
702     *            JDBC connection factory
703     * @throws SQLException
704     *             if an error occurs creating the PoolableConnectionFactory
705     *
706     * @return A new PoolableConnectionFactory configured with the current configuration of this BasicDataSource
707     */
708    protected PoolableConnectionFactory createPoolableConnectionFactory(final ConnectionFactory driverConnectionFactory)
709            throws SQLException {
710        PoolableConnectionFactory connectionFactory = null;
711        try {
712            connectionFactory = new PoolableConnectionFactory(driverConnectionFactory,
713                    ObjectNameWrapper.unwrap(registeredJmxObjectName));
714            connectionFactory.setValidationQuery(validationQuery);
715            connectionFactory.setValidationQueryTimeout(validationQueryTimeoutSeconds);
716            connectionFactory.setConnectionInitSql(connectionInitSqls);
717            connectionFactory.setDefaultReadOnly(defaultReadOnly);
718            connectionFactory.setDefaultAutoCommit(defaultAutoCommit);
719            connectionFactory.setDefaultTransactionIsolation(defaultTransactionIsolation);
720            connectionFactory.setDefaultCatalog(defaultCatalog);
721            connectionFactory.setDefaultSchema(defaultSchema);
722            connectionFactory.setCacheState(cacheState);
723            connectionFactory.setPoolStatements(poolPreparedStatements);
724            connectionFactory.setMaxOpenPreparedStatements(maxOpenPreparedStatements);
725            connectionFactory.setMaxConnLifetimeMillis(maxConnLifetimeMillis);
726            connectionFactory.setRollbackOnReturn(getRollbackOnReturn());
727            connectionFactory.setAutoCommitOnReturn(getAutoCommitOnReturn());
728            connectionFactory.setDefaultQueryTimeout(getDefaultQueryTimeout());
729            connectionFactory.setFastFailValidation(fastFailValidation);
730            connectionFactory.setDisconnectionSqlCodes(disconnectionSqlCodes);
731            validateConnectionFactory(connectionFactory);
732        } catch (final RuntimeException e) {
733            throw e;
734        } catch (final Exception e) {
735            throw new SQLException("Cannot create PoolableConnectionFactory (" + e.getMessage() + ")", e);
736        }
737        return connectionFactory;
738    }
739
740    /**
741     * Gets the print writer used by this configuration to log information on abandoned objects.
742     *
743     * @return The print writer used by this configuration to log information on abandoned objects.
744     */
745    public PrintWriter getAbandonedLogWriter() {
746        if (abandonedConfig != null) {
747            return abandonedConfig.getLogWriter();
748        }
749        return null;
750    }
751
752    /**
753     * If the connection pool implements {@link org.apache.commons.pool2.UsageTracking UsageTracking}, should the
754     * connection pool record a stack trace every time a method is called on a pooled connection and retain the most
755     * recent stack trace to aid debugging of abandoned connections?
756     *
757     * @return <code>true</code> if usage tracking is enabled
758     */
759    @Override
760    public boolean getAbandonedUsageTracking() {
761        if (abandonedConfig != null) {
762            return abandonedConfig.getUseUsageTracking();
763        }
764        return false;
765    }
766
767    /**
768     * Returns the value of the flag that controls whether or not connections being returned to the pool will be checked
769     * and configured with {@link Connection#setAutoCommit(boolean) Connection.setAutoCommit(true)} if the auto commit
770     * setting is {@code false} when the connection is returned. It is <code>true</code> by default.
771     *
772     * @return Whether or not connections being returned to the pool will be checked and configured with auto-commit.
773     */
774    public boolean getAutoCommitOnReturn() {
775        return autoCommitOnReturn;
776    }
777
778    /**
779     * Returns the state caching flag.
780     *
781     * @return the state caching flag
782     */
783    @Override
784    public boolean getCacheState() {
785        return cacheState;
786    }
787
788    /**
789     * Creates (if necessary) and return a connection to the database.
790     *
791     * @throws SQLException
792     *             if a database access error occurs
793     * @return a database connection
794     */
795    @Override
796    public Connection getConnection() throws SQLException {
797        if (Utils.IS_SECURITY_ENABLED) {
798            final PrivilegedExceptionAction<Connection> action = new PaGetConnection();
799            try {
800                return AccessController.doPrivileged(action);
801            } catch (final PrivilegedActionException e) {
802                final Throwable cause = e.getCause();
803                if (cause instanceof SQLException) {
804                    throw (SQLException) cause;
805                }
806                throw new SQLException(e);
807            }
808        }
809        return createDataSource().getConnection();
810    }
811
812    /**
813     * <strong>BasicDataSource does NOT support this method.</strong>
814     *
815     * @param user
816     *            Database user on whose behalf the Connection is being made
817     * @param pass
818     *            The database user's password
819     *
820     * @throws UnsupportedOperationException
821     *             always thrown.
822     * @throws SQLException
823     *             if a database access error occurs
824     * @return nothing - always throws UnsupportedOperationException
825     */
826    @Override
827    public Connection getConnection(final String user, final String pass) throws SQLException {
828        // This method isn't supported by the PoolingDataSource returned by the createDataSource
829        throw new UnsupportedOperationException("Not supported by BasicDataSource");
830    }
831
832    /**
833     * Returns the list of SQL statements executed when a physical connection is first created. Returns an empty list if
834     * there are no initialization statements configured.
835     *
836     * @return initialization SQL statements
837     */
838    public List<String> getConnectionInitSqls() {
839        final List<String> result = connectionInitSqls;
840        if (result == null) {
841            return Collections.emptyList();
842        }
843        return result;
844    }
845
846    /**
847     * Provides the same data as {@link #getConnectionInitSqls()} but in an array so it is accessible via JMX.
848     */
849    @Override
850    public String[] getConnectionInitSqlsAsArray() {
851        final Collection<String> result = getConnectionInitSqls();
852        return result.toArray(new String[result.size()]);
853    }
854
855    protected GenericObjectPool<PoolableConnection> getConnectionPool() {
856        return connectionPool;
857    }
858
859    // For unit testing
860    Properties getConnectionProperties() {
861        return connectionProperties;
862    }
863
864    /**
865     * Returns the default auto-commit property.
866     *
867     * @return true if default auto-commit is enabled
868     */
869    @Override
870    public Boolean getDefaultAutoCommit() {
871        return defaultAutoCommit;
872    }
873
874    /**
875     * Returns the default catalog.
876     *
877     * @return the default catalog
878     */
879    @Override
880    public String getDefaultCatalog() {
881        return this.defaultCatalog;
882    }
883
884    /**
885     * Gets the default query timeout that will be used for {@link java.sql.Statement Statement}s created from this
886     * connection. <code>null</code> means that the driver default will be used.
887     *
888     * @return The default query timeout in seconds.
889     */
890    public Integer getDefaultQueryTimeout() {
891        return defaultQueryTimeoutSeconds;
892    }
893
894    /**
895     * Returns the default readOnly property.
896     *
897     * @return true if connections are readOnly by default
898     */
899    @Override
900    public Boolean getDefaultReadOnly() {
901        return defaultReadOnly;
902    }
903
904    /**
905     * Returns the default schema.
906     *
907     * @return the default schema.
908     * @since 2.5.0
909     */
910    @Override
911    public String getDefaultSchema() {
912        return this.defaultSchema;
913    }
914
915    /**
916     * Returns the default transaction isolation state of returned connections.
917     *
918     * @return the default value for transaction isolation state
919     * @see Connection#getTransactionIsolation
920     */
921    @Override
922    public int getDefaultTransactionIsolation() {
923        return this.defaultTransactionIsolation;
924    }
925
926    /**
927     * Returns the set of SQL_STATE codes considered to signal fatal conditions.
928     *
929     * @return fatal disconnection state codes
930     * @see #setDisconnectionSqlCodes(Collection)
931     * @since 2.1
932     */
933    public Set<String> getDisconnectionSqlCodes() {
934        final Set<String> result = disconnectionSqlCodes;
935        if (result == null) {
936            return Collections.emptySet();
937        }
938        return result;
939    }
940
941    /**
942     * Provides the same data as {@link #getDisconnectionSqlCodes} but in an array so it is accessible via JMX.
943     *
944     * @since 2.1
945     */
946    @Override
947    public String[] getDisconnectionSqlCodesAsArray() {
948        final Collection<String> result = getDisconnectionSqlCodes();
949        return result.toArray(new String[result.size()]);
950    }
951
952    /**
953     * Returns the JDBC Driver that has been configured for use by this pool.
954     * <p>
955     * Note: This getter only returns the last value set by a call to {@link #setDriver(Driver)}. It does not return any
956     * driver instance that may have been created from the value set via {@link #setDriverClassName(String)}.
957     * </p>
958     *
959     * @return the JDBC Driver that has been configured for use by this pool
960     */
961    public synchronized Driver getDriver() {
962        return driver;
963    }
964
965    /**
966     * Returns the class loader specified for loading the JDBC driver. Returns <code>null</code> if no class loader has
967     * been explicitly specified.
968     * <p>
969     * Note: This getter only returns the last value set by a call to {@link #setDriverClassLoader(ClassLoader)}. It
970     * does not return the class loader of any driver that may have been set via {@link #setDriver(Driver)}.
971     * </p>
972     *
973     * @return The class loader specified for loading the JDBC driver.
974     */
975    public synchronized ClassLoader getDriverClassLoader() {
976        return this.driverClassLoader;
977    }
978
979    /**
980     * Returns the JDBC driver class name.
981     * <p>
982     * Note: This getter only returns the last value set by a call to {@link #setDriverClassName(String)}. It does not
983     * return the class name of any driver that may have been set via {@link #setDriver(Driver)}.
984     * </p>
985     *
986     * @return the JDBC driver class name
987     */
988    @Override
989    public synchronized String getDriverClassName() {
990        return this.driverClassName;
991    }
992
993    /**
994     * Returns the value of the flag that controls whether or not connections being returned to the pool will be checked
995     * and configured with {@link Connection#setAutoCommit(boolean) Connection.setAutoCommit(true)} if the auto commit
996     * setting is {@code false} when the connection is returned. It is <code>true</code> by default.
997     *
998     * @return Whether or not connections being returned to the pool will be checked and configured with auto-commit.
999     * @deprecated Use {@link #getAutoCommitOnReturn()}.
1000     */
1001    @Deprecated
1002    public boolean getEnableAutoCommitOnReturn() {
1003        return autoCommitOnReturn;
1004    }
1005
1006    /**
1007     * Gets the EvictionPolicy implementation in use with this connection pool.
1008     *
1009     * @return The EvictionPolicy implementation in use with this connection pool.
1010     */
1011    public synchronized String getEvictionPolicyClassName() {
1012        return evictionPolicyClassName;
1013    }
1014
1015    /**
1016     * True means that validation will fail immediately for connections that have previously thrown SQLExceptions with
1017     * SQL_STATE indicating fatal disconnection errors.
1018     *
1019     * @return true if connections created by this datasource will fast fail validation.
1020     * @see #setDisconnectionSqlCodes(Collection)
1021     * @since 2.1
1022     */
1023    @Override
1024    public boolean getFastFailValidation() {
1025        return fastFailValidation;
1026    }
1027
1028    /**
1029     * Returns the initial size of the connection pool.
1030     *
1031     * @return the number of connections created when the pool is initialized
1032     */
1033    @Override
1034    public synchronized int getInitialSize() {
1035        return this.initialSize;
1036    }
1037
1038    /**
1039     * Returns the JMX name that has been requested for this DataSource. If the requested name is not valid, an
1040     * alternative may be chosen.
1041     *
1042     * @return The JMX name that has been requested for this DataSource.
1043     */
1044    public String getJmxName() {
1045        return jmxName;
1046    }
1047
1048    /**
1049     * Returns the LIFO property.
1050     *
1051     * @return true if connection pool behaves as a LIFO queue.
1052     */
1053    @Override
1054    public synchronized boolean getLifo() {
1055        return this.lifo;
1056    }
1057
1058    /**
1059     * <p>
1060     * Flag to log stack traces for application code which abandoned a Statement or Connection.
1061     * </p>
1062     * <p>
1063     * Defaults to false.
1064     * </p>
1065     * <p>
1066     * Logging of abandoned Statements and Connections adds overhead for every Connection open or new Statement because
1067     * a stack trace has to be generated.
1068     * </p>
1069     */
1070    @Override
1071    public boolean getLogAbandoned() {
1072        if (abandonedConfig != null) {
1073            return abandonedConfig.getLogAbandoned();
1074        }
1075        return false;
1076    }
1077
1078    /**
1079     * When {@link #getMaxConnLifetimeMillis()} is set to limit connection lifetime, this property determines whether or
1080     * not log messages are generated when the pool closes connections due to maximum lifetime exceeded.
1081     *
1082     * @since 2.1
1083     */
1084    @Override
1085    public boolean getLogExpiredConnections() {
1086        return logExpiredConnections;
1087    }
1088
1089    /**
1090     * <strong>BasicDataSource does NOT support this method.</strong>
1091     *
1092     * <p>
1093     * Returns the login timeout (in seconds) for connecting to the database.
1094     * </p>
1095     * <p>
1096     * Calls {@link #createDataSource()}, so has the side effect of initializing the connection pool.
1097     * </p>
1098     *
1099     * @throws SQLException
1100     *             if a database access error occurs
1101     * @throws UnsupportedOperationException
1102     *             If the DataSource implementation does not support the login timeout feature.
1103     * @return login timeout in seconds
1104     */
1105    @Override
1106    public int getLoginTimeout() throws SQLException {
1107        // This method isn't supported by the PoolingDataSource returned by the createDataSource
1108        throw new UnsupportedOperationException("Not supported by BasicDataSource");
1109    }
1110
1111    /**
1112     * <p>
1113     * Returns the log writer being used by this data source.
1114     * </p>
1115     * <p>
1116     * Calls {@link #createDataSource()}, so has the side effect of initializing the connection pool.
1117     * </p>
1118     *
1119     * @throws SQLException
1120     *             if a database access error occurs
1121     * @return log writer in use
1122     */
1123    @Override
1124    public PrintWriter getLogWriter() throws SQLException {
1125        return createDataSource().getLogWriter();
1126    }
1127
1128    /**
1129     * Returns the maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an
1130     * infinite lifetime.
1131     */
1132    @Override
1133    public long getMaxConnLifetimeMillis() {
1134        return maxConnLifetimeMillis;
1135    }
1136
1137    /**
1138     * <p>
1139     * Returns the maximum number of connections that can remain idle in the pool. Excess idle connections are destroyed
1140     * on return to the pool.
1141     * </p>
1142     * <p>
1143     * A negative value indicates that there is no limit
1144     * </p>
1145     *
1146     * @return the maximum number of idle connections
1147     */
1148    @Override
1149    public synchronized int getMaxIdle() {
1150        return this.maxIdle;
1151    }
1152
1153    /**
1154     * Gets the value of the <code>maxOpenPreparedStatements</code> property.
1155     *
1156     * @return the maximum number of open statements
1157     */
1158    @Override
1159    public synchronized int getMaxOpenPreparedStatements() {
1160        return this.maxOpenPreparedStatements;
1161    }
1162
1163    /**
1164     * <p>
1165     * Returns the maximum number of active connections that can be allocated at the same time.
1166     * </p>
1167     * <p>
1168     * A negative number means that there is no limit.
1169     * </p>
1170     *
1171     * @return the maximum number of active connections
1172     */
1173    @Override
1174    public synchronized int getMaxTotal() {
1175        return this.maxTotal;
1176    }
1177
1178    /**
1179     * Returns the maximum number of milliseconds that the pool will wait for a connection to be returned before
1180     * throwing an exception. A value less than or equal to zero means the pool is set to wait indefinitely.
1181     *
1182     * @return the maxWaitMillis property value
1183     */
1184    @Override
1185    public synchronized long getMaxWaitMillis() {
1186        return this.maxWaitMillis;
1187    }
1188
1189    /**
1190     * Returns the {@link #minEvictableIdleTimeMillis} property.
1191     *
1192     * @return the value of the {@link #minEvictableIdleTimeMillis} property
1193     * @see #minEvictableIdleTimeMillis
1194     */
1195    @Override
1196    public synchronized long getMinEvictableIdleTimeMillis() {
1197        return this.minEvictableIdleTimeMillis;
1198    }
1199
1200    /**
1201     * Returns the minimum number of idle connections in the pool. The pool attempts to ensure that minIdle connections
1202     * are available when the idle object evictor runs. The value of this property has no effect unless
1203     * {@link #timeBetweenEvictionRunsMillis} has a positive value.
1204     *
1205     * @return the minimum number of idle connections
1206     * @see GenericObjectPool#getMinIdle()
1207     */
1208    @Override
1209    public synchronized int getMinIdle() {
1210        return this.minIdle;
1211    }
1212
1213    /**
1214     * [Read Only] The current number of active connections that have been allocated from this data source.
1215     *
1216     * @return the current number of active connections
1217     */
1218    @Override
1219    public int getNumActive() {
1220        // Copy reference to avoid NPE if close happens after null check
1221        final GenericObjectPool<PoolableConnection> pool = connectionPool;
1222        if (pool != null) {
1223            return pool.getNumActive();
1224        }
1225        return 0;
1226    }
1227
1228    /**
1229     * [Read Only] The current number of idle connections that are waiting to be allocated from this data source.
1230     *
1231     * @return the current number of idle connections
1232     */
1233    @Override
1234    public int getNumIdle() {
1235        // Copy reference to avoid NPE if close happens after null check
1236        final GenericObjectPool<PoolableConnection> pool = connectionPool;
1237        if (pool != null) {
1238            return pool.getNumIdle();
1239        }
1240        return 0;
1241    }
1242
1243    /**
1244     * Returns the value of the {@link #numTestsPerEvictionRun} property.
1245     *
1246     * @return the number of objects to examine during idle object evictor runs
1247     * @see #numTestsPerEvictionRun
1248     */
1249    @Override
1250    public synchronized int getNumTestsPerEvictionRun() {
1251        return this.numTestsPerEvictionRun;
1252    }
1253
1254    @Override
1255    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
1256        throw new SQLFeatureNotSupportedException();
1257    }
1258
1259    /**
1260     * Returns the password passed to the JDBC driver to establish connections.
1261     *
1262     * @return the connection password
1263     */
1264    @Override
1265    public String getPassword() {
1266        return this.password;
1267    }
1268
1269    protected ObjectName getRegisteredJmxName() {
1270        return ObjectNameWrapper.unwrap(registeredJmxObjectName);
1271    }
1272
1273    /**
1274     * <p>
1275     * Flag to remove abandoned connections if they exceed the removeAbandonedTimeout when borrowObject is invoked.
1276     * </p>
1277     * <p>
1278     * The default value is false.
1279     * </p>
1280     * <p>
1281     * If set to true a connection is considered abandoned and eligible for removal if it has not been used for more
1282     * than {@link #getRemoveAbandonedTimeout() removeAbandonedTimeout} seconds.
1283     * </p>
1284     * <p>
1285     * Abandoned connections are identified and removed when {@link #getConnection()} is invoked and all of the
1286     * following conditions hold:
1287     * </p>
1288     * <ul>
1289     * <li>{@link #getRemoveAbandonedOnBorrow()}</li>
1290     * <li>{@link #getNumActive()} &gt; {@link #getMaxTotal()} - 3</li>
1291     * <li>{@link #getNumIdle()} &lt; 2</li>
1292     * </ul>
1293     *
1294     * @see #getRemoveAbandonedTimeout()
1295     */
1296    @Override
1297    public boolean getRemoveAbandonedOnBorrow() {
1298        if (abandonedConfig != null) {
1299            return abandonedConfig.getRemoveAbandonedOnBorrow();
1300        }
1301        return false;
1302    }
1303
1304    /**
1305     * <p>
1306     * Flag to remove abandoned connections if they exceed the removeAbandonedTimeout during pool maintenance.
1307     * </p>
1308     *
1309     * <p>
1310     * The default value is false.
1311     * </p>
1312     *
1313     * <p>
1314     * If set to true a connection is considered abandoned and eligible for removal if it has not been used for more
1315     * than {@link #getRemoveAbandonedTimeout() removeAbandonedTimeout} seconds.
1316     * </p>
1317     *
1318     * @see #getRemoveAbandonedTimeout()
1319     */
1320    @Override
1321    public boolean getRemoveAbandonedOnMaintenance() {
1322        if (abandonedConfig != null) {
1323            return abandonedConfig.getRemoveAbandonedOnMaintenance();
1324        }
1325        return false;
1326    }
1327
1328    /**
1329     * <p>
1330     * Timeout in seconds before an abandoned connection can be removed.
1331     * </p>
1332     * <p>
1333     * Creating a Statement, PreparedStatement or CallableStatement or using one of these to execute a query (using one
1334     * of the execute methods) resets the lastUsed property of the parent connection.
1335     * </p>
1336     * <p>
1337     * Abandoned connection cleanup happens when:
1338     * </p>
1339     * <ul>
1340     * <li>{@link #getRemoveAbandonedOnBorrow()} or {@link #getRemoveAbandonedOnMaintenance()} = true</li>
1341     * <li>{@link #getNumIdle() numIdle} &lt; 2</li>
1342     * <li>{@link #getNumActive() numActive} &gt; {@link #getMaxTotal() maxTotal} - 3</li>
1343     * </ul>
1344     * <p>
1345     * The default value is 300 seconds.
1346     * </p>
1347     */
1348    @Override
1349    public int getRemoveAbandonedTimeout() {
1350        if (abandonedConfig != null) {
1351            return abandonedConfig.getRemoveAbandonedTimeout();
1352        }
1353        return 300;
1354    }
1355
1356    /**
1357     * Gets the current value of the flag that controls whether a connection will be rolled back when it is returned to
1358     * the pool if auto commit is not enabled and the connection is not read only.
1359     *
1360     * @return whether a connection will be rolled back when it is returned to the pool.
1361     */
1362    public boolean getRollbackOnReturn() {
1363        return rollbackOnReturn;
1364    }
1365
1366    /**
1367     * <p>
1368     * Returns the minimum amount of time a connection may sit idle in the pool before it is eligible for eviction by
1369     * the idle object evictor, with the extra condition that at least "minIdle" connections remain in the pool.
1370     * </p>
1371     *
1372     * <p>
1373     * When {@link #getMinEvictableIdleTimeMillis() minEvictableIdleTimeMillis} is set to a positive value,
1374     * minEvictableIdleTimeMillis is examined first by the idle connection evictor - i.e. when idle connections are
1375     * visited by the evictor, idle time is first compared against {@code minEvictableIdleTimeMillis} (without
1376     * considering the number of idle connections in the pool) and then against {@code softMinEvictableIdleTimeMillis},
1377     * including the {@code minIdle}, constraint.
1378     * </p>
1379     *
1380     * @return minimum amount of time a connection may sit idle in the pool before it is eligible for eviction, assuming
1381     *         there are minIdle idle connections in the pool
1382     */
1383    @Override
1384    public synchronized long getSoftMinEvictableIdleTimeMillis() {
1385        return softMinEvictableIdleTimeMillis;
1386    }
1387
1388    /**
1389     * Returns the {@link #testOnBorrow} property.
1390     *
1391     * @return true if objects are validated before being borrowed from the pool
1392     *
1393     * @see #testOnBorrow
1394     */
1395    @Override
1396    public synchronized boolean getTestOnBorrow() {
1397        return this.testOnBorrow;
1398    }
1399
1400    /**
1401     * Returns the {@link #testOnCreate} property.
1402     *
1403     * @return true if objects are validated immediately after they are created by the pool
1404     * @see #testOnCreate
1405     */
1406    @Override
1407    public synchronized boolean getTestOnCreate() {
1408        return this.testOnCreate;
1409    }
1410
1411    /**
1412     * Returns the value of the {@link #testOnReturn} property.
1413     *
1414     * @return true if objects are validated before being returned to the pool
1415     * @see #testOnReturn
1416     */
1417    public synchronized boolean getTestOnReturn() {
1418        return this.testOnReturn;
1419    }
1420
1421    /**
1422     * Returns the value of the {@link #testWhileIdle} property.
1423     *
1424     * @return true if objects examined by the idle object evictor are validated
1425     * @see #testWhileIdle
1426     */
1427    @Override
1428    public synchronized boolean getTestWhileIdle() {
1429        return this.testWhileIdle;
1430    }
1431
1432    /**
1433     * Returns the value of the {@link #timeBetweenEvictionRunsMillis} property.
1434     *
1435     * @return the time (in milliseconds) between evictor runs
1436     * @see #timeBetweenEvictionRunsMillis
1437     */
1438    @Override
1439    public synchronized long getTimeBetweenEvictionRunsMillis() {
1440        return this.timeBetweenEvictionRunsMillis;
1441    }
1442
1443    /**
1444     * Returns the JDBC connection {@link #url} property.
1445     *
1446     * @return the {@link #url} passed to the JDBC driver to establish connections
1447     */
1448    @Override
1449    public synchronized String getUrl() {
1450        return this.url;
1451    }
1452
1453    /**
1454     * Returns the JDBC connection {@link #userName} property.
1455     *
1456     * @return the {@link #userName} passed to the JDBC driver to establish connections
1457     */
1458    @Override
1459    public String getUsername() {
1460        return this.userName;
1461    }
1462
1463    /**
1464     * Returns the validation query used to validate connections before returning them.
1465     *
1466     * @return the SQL validation query
1467     * @see #validationQuery
1468     */
1469    @Override
1470    public String getValidationQuery() {
1471        return this.validationQuery;
1472    }
1473
1474    /**
1475     * Returns the validation query timeout.
1476     *
1477     * @return the timeout in seconds before connection validation queries fail.
1478     */
1479    @Override
1480    public int getValidationQueryTimeout() {
1481        return validationQueryTimeoutSeconds;
1482    }
1483
1484    /**
1485     * Manually invalidates a connection, effectively requesting the pool to try to close it, remove it from the pool
1486     * and reclaim pool capacity.
1487     *
1488     * @param connection
1489     *            The Connection to invalidate.
1490     *
1491     * @throws IllegalStateException
1492     *             if invalidating the connection failed.
1493     * @since 2.1
1494     */
1495    public void invalidateConnection(final Connection connection) throws IllegalStateException {
1496        if (connection == null) {
1497            return;
1498        }
1499        if (connectionPool == null) {
1500            throw new IllegalStateException("Cannot invalidate connection: ConnectionPool is null.");
1501        }
1502
1503        final PoolableConnection poolableConnection;
1504        try {
1505            poolableConnection = connection.unwrap(PoolableConnection.class);
1506            if (poolableConnection == null) {
1507                throw new IllegalStateException(
1508                        "Cannot invalidate connection: Connection is not a poolable connection.");
1509            }
1510        } catch (final SQLException e) {
1511            throw new IllegalStateException("Cannot invalidate connection: Unwrapping poolable connection failed.", e);
1512        }
1513
1514        try {
1515            connectionPool.invalidateObject(poolableConnection);
1516        } catch (final Exception e) {
1517            throw new IllegalStateException("Invalidating connection threw unexpected exception", e);
1518        }
1519    }
1520
1521    /**
1522     * Manually evicts idle connections
1523     */
1524    public void evict() throws Exception {
1525        if (connectionPool != null) {
1526            connectionPool.evict();
1527        }
1528    }
1529
1530    /**
1531     * Returns the value of the accessToUnderlyingConnectionAllowed property.
1532     *
1533     * @return true if access to the underlying connection is allowed, false otherwise.
1534     */
1535    @Override
1536    public synchronized boolean isAccessToUnderlyingConnectionAllowed() {
1537        return this.accessToUnderlyingConnectionAllowed;
1538    }
1539
1540    /**
1541     * If true, this data source is closed and no more connections can be retrieved from this datasource.
1542     *
1543     * @return true, if the data source is closed; false otherwise
1544     */
1545    @Override
1546    public synchronized boolean isClosed() {
1547        return closed;
1548    }
1549
1550    /**
1551     * Returns true if we are pooling statements.
1552     *
1553     * @return true if prepared and callable statements are pooled
1554     */
1555    @Override
1556    public synchronized boolean isPoolPreparedStatements() {
1557        return this.poolPreparedStatements;
1558    }
1559
1560    @Override
1561    public boolean isWrapperFor(final Class<?> iface) throws SQLException {
1562        return false;
1563    }
1564
1565    private void jmxRegister() {
1566        // Return immediately if this DataSource has already been registered
1567        if (registeredJmxObjectName != null) {
1568            return;
1569        }
1570        // Return immediately if no JMX name has been specified
1571        final String requestedName = getJmxName();
1572        if (requestedName == null) {
1573            return;
1574        }
1575        try {
1576            ObjectNameWrapper.wrap(requestedName).registerMBean(this);
1577        } catch (final MalformedObjectNameException e) {
1578            log.warn("The requested JMX name [" + requestedName + "] was not valid and will be ignored.");
1579        }
1580    }
1581
1582    protected void log(final String message) {
1583        if (logWriter != null) {
1584            logWriter.println(message);
1585        }
1586    }
1587
1588    @Override
1589    public void postDeregister() {
1590        // NO-OP
1591    }
1592
1593    @Override
1594    public void postRegister(final Boolean registrationDone) {
1595        // NO-OP
1596    }
1597
1598    @Override
1599    public void preDeregister() throws Exception {
1600        // NO-OP
1601    }
1602
1603    @Override
1604    public ObjectName preRegister(final MBeanServer server, final ObjectName objectName) {
1605        final String requestedName = getJmxName();
1606        if (requestedName != null) {
1607            try {
1608                registeredJmxObjectName = ObjectNameWrapper.wrap(requestedName);
1609            } catch (final MalformedObjectNameException e) {
1610                log.warn("The requested JMX name [" + requestedName + "] was not valid and will be ignored.");
1611            }
1612        }
1613        if (registeredJmxObjectName == null) {
1614            registeredJmxObjectName = ObjectNameWrapper.wrap(objectName);
1615        }
1616        return ObjectNameWrapper.unwrap(registeredJmxObjectName);
1617    }
1618
1619    /**
1620     * Removes a custom connection property.
1621     *
1622     * @param name
1623     *            Name of the custom connection property to remove
1624     * @see #addConnectionProperty(String, String)
1625     */
1626    public void removeConnectionProperty(final String name) {
1627        connectionProperties.remove(name);
1628    }
1629
1630    /**
1631     * Sets the print writer to be used by this configuration to log information on abandoned objects.
1632     *
1633     * @param logWriter
1634     *            The new log writer
1635     */
1636    public void setAbandonedLogWriter(final PrintWriter logWriter) {
1637        if (abandonedConfig == null) {
1638            abandonedConfig = new AbandonedConfig();
1639        }
1640        abandonedConfig.setLogWriter(logWriter);
1641        final GenericObjectPool<?> gop = this.connectionPool;
1642        if (gop != null) {
1643            gop.setAbandonedConfig(abandonedConfig);
1644        }
1645    }
1646
1647    /**
1648     * If the connection pool implements {@link org.apache.commons.pool2.UsageTracking UsageTracking}, configure whether
1649     * the connection pool should record a stack trace every time a method is called on a pooled connection and retain
1650     * the most recent stack trace to aid debugging of abandoned connections.
1651     *
1652     * @param usageTracking
1653     *            A value of <code>true</code> will enable the recording of a stack trace on every use of a pooled
1654     *            connection
1655     */
1656    public void setAbandonedUsageTracking(final boolean usageTracking) {
1657        if (abandonedConfig == null) {
1658            abandonedConfig = new AbandonedConfig();
1659        }
1660        abandonedConfig.setUseUsageTracking(usageTracking);
1661        final GenericObjectPool<?> gop = this.connectionPool;
1662        if (gop != null) {
1663            gop.setAbandonedConfig(abandonedConfig);
1664        }
1665    }
1666
1667    /**
1668     * <p>
1669     * Sets the value of the accessToUnderlyingConnectionAllowed property. It controls if the PoolGuard allows access to
1670     * the underlying connection. (Default: false)
1671     * </p>
1672     * <p>
1673     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
1674     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
1675     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
1676     * </p>
1677     *
1678     * @param allow
1679     *            Access to the underlying connection is granted when true.
1680     */
1681    public synchronized void setAccessToUnderlyingConnectionAllowed(final boolean allow) {
1682        this.accessToUnderlyingConnectionAllowed = allow;
1683    }
1684
1685    /**
1686     * Sets the value of the flag that controls whether or not connections being returned to the pool will be checked
1687     * and configured with {@link Connection#setAutoCommit(boolean) Connection.setAutoCommit(true)} if the auto commit
1688     * setting is {@code false} when the connection is returned. It is <code>true</code> by default.
1689     *
1690     * @param autoCommitOnReturn
1691     *            Whether or not connections being returned to the pool will be checked and configured with auto-commit.
1692     * @since 2.6.0
1693     */
1694    public void setAutoCommitOnReturn(final boolean autoCommitOnReturn) {
1695        this.autoCommitOnReturn = autoCommitOnReturn;
1696    }
1697
1698    /**
1699     * Sets the state caching flag.
1700     *
1701     * @param cacheState
1702     *            The new value for the state caching flag
1703     */
1704    public void setCacheState(final boolean cacheState) {
1705        this.cacheState = cacheState;
1706    }
1707
1708    /**
1709     * Sets the list of SQL statements to be executed when a physical connection is first created.
1710     * <p>
1711     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
1712     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
1713     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
1714     * </p>
1715     *
1716     * @param connectionInitSqls
1717     *            Collection of SQL statements to execute on connection creation
1718     */
1719    public void setConnectionInitSqls(final Collection<String> connectionInitSqls) {
1720        if (connectionInitSqls != null && connectionInitSqls.size() > 0) {
1721            ArrayList<String> newVal = null;
1722            for (final String s : connectionInitSqls) {
1723                if (s != null && s.trim().length() > 0) {
1724                    if (newVal == null) {
1725                        newVal = new ArrayList<>();
1726                    }
1727                    newVal.add(s);
1728                }
1729            }
1730            this.connectionInitSqls = newVal;
1731        } else {
1732            this.connectionInitSqls = null;
1733        }
1734    }
1735
1736    // ----------------------------------------------------- DataSource Methods
1737
1738    /**
1739     * Sets the connection properties passed to driver.connect(...).
1740     * <p>
1741     * Format of the string must be [propertyName=property;]*
1742     * </p>
1743     * <p>
1744     * NOTE - The "user" and "password" properties will be added explicitly, so they do not need to be included here.
1745     * </p>
1746     *
1747     * @param connectionProperties
1748     *            the connection properties used to create new connections
1749     */
1750    public void setConnectionProperties(final String connectionProperties) {
1751        Objects.requireNonNull(connectionProperties, "connectionProperties is null");
1752        final String[] entries = connectionProperties.split(";");
1753        final Properties properties = new Properties();
1754        for (final String entry : entries) {
1755            if (entry.length() > 0) {
1756                final int index = entry.indexOf('=');
1757                if (index > 0) {
1758                    final String name = entry.substring(0, index);
1759                    final String value = entry.substring(index + 1);
1760                    properties.setProperty(name, value);
1761                } else {
1762                    // no value is empty string which is how java.util.Properties works
1763                    properties.setProperty(entry, "");
1764                }
1765            }
1766        }
1767        this.connectionProperties = properties;
1768    }
1769
1770    /**
1771     * <p>
1772     * Sets default auto-commit state of connections returned by this datasource.
1773     * </p>
1774     * <p>
1775     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
1776     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
1777     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
1778     * </p>
1779     *
1780     * @param defaultAutoCommit
1781     *            default auto-commit value
1782     */
1783    public void setDefaultAutoCommit(final Boolean defaultAutoCommit) {
1784        this.defaultAutoCommit = defaultAutoCommit;
1785    }
1786
1787    /**
1788     * <p>
1789     * Sets the default catalog.
1790     * </p>
1791     * <p>
1792     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
1793     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
1794     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
1795     * </p>
1796     *
1797     * @param defaultCatalog
1798     *            the default catalog
1799     */
1800    public void setDefaultCatalog(final String defaultCatalog) {
1801        if (defaultCatalog != null && defaultCatalog.trim().length() > 0) {
1802            this.defaultCatalog = defaultCatalog;
1803        } else {
1804            this.defaultCatalog = null;
1805        }
1806    }
1807
1808    /**
1809     * Sets the default query timeout that will be used for {@link java.sql.Statement Statement}s created from this
1810     * connection. <code>null</code> means that the driver default will be used.
1811     *
1812     * @param defaultQueryTimeoutSeconds
1813     *            The default query timeout in seconds.
1814     */
1815    public void setDefaultQueryTimeout(final Integer defaultQueryTimeoutSeconds) {
1816        this.defaultQueryTimeoutSeconds = defaultQueryTimeoutSeconds;
1817    }
1818
1819    /**
1820     * <p>
1821     * Sets defaultReadonly property.
1822     * </p>
1823     * <p>
1824     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
1825     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
1826     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
1827     * </p>
1828     *
1829     * @param defaultReadOnly
1830     *            default read-only value
1831     */
1832    public void setDefaultReadOnly(final Boolean defaultReadOnly) {
1833        this.defaultReadOnly = defaultReadOnly;
1834    }
1835
1836    /**
1837     * <p>
1838     * Sets the default schema.
1839     * </p>
1840     * <p>
1841     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
1842     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
1843     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
1844     * </p>
1845     *
1846     * @param defaultSchema
1847     *            the default catalog
1848     * @since 2.5.0
1849     */
1850    public void setDefaultSchema(final String defaultSchema) {
1851        if (defaultSchema != null && defaultSchema.trim().length() > 0) {
1852            this.defaultSchema = defaultSchema;
1853        } else {
1854            this.defaultSchema = null;
1855        }
1856    }
1857
1858    /**
1859     * <p>
1860     * Sets the default transaction isolation state for returned connections.
1861     * </p>
1862     * <p>
1863     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
1864     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
1865     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
1866     * </p>
1867     *
1868     * @param defaultTransactionIsolation
1869     *            the default transaction isolation state
1870     * @see Connection#getTransactionIsolation
1871     */
1872    public void setDefaultTransactionIsolation(final int defaultTransactionIsolation) {
1873        this.defaultTransactionIsolation = defaultTransactionIsolation;
1874    }
1875
1876    /**
1877     * Sets the SQL_STATE codes considered to signal fatal conditions.
1878     * <p>
1879     * Overrides the defaults in {@link Utils#DISCONNECTION_SQL_CODES} (plus anything starting with
1880     * {@link Utils#DISCONNECTION_SQL_CODE_PREFIX}). If this property is non-null and {@link #getFastFailValidation()}
1881     * is {@code true}, whenever connections created by this datasource generate exceptions with SQL_STATE codes in this
1882     * list, they will be marked as "fatally disconnected" and subsequent validations will fail fast (no attempt at
1883     * isValid or validation query).
1884     * </p>
1885     * <p>
1886     * If {@link #getFastFailValidation()} is {@code false} setting this property has no effect.
1887     * </p>
1888     * <p>
1889     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
1890     * time one of the following methods is invoked: {@code getConnection, setLogwriter,
1891     * setLoginTimeout, getLoginTimeout, getLogWriter}.
1892     * </p>
1893     *
1894     * @param disconnectionSqlCodes
1895     *            SQL_STATE codes considered to signal fatal conditions
1896     * @since 2.1
1897     */
1898    public void setDisconnectionSqlCodes(final Collection<String> disconnectionSqlCodes) {
1899        if (disconnectionSqlCodes != null && disconnectionSqlCodes.size() > 0) {
1900            HashSet<String> newVal = null;
1901            for (final String s : disconnectionSqlCodes) {
1902                if (s != null && s.trim().length() > 0) {
1903                    if (newVal == null) {
1904                        newVal = new HashSet<>();
1905                    }
1906                    newVal.add(s);
1907                }
1908            }
1909            this.disconnectionSqlCodes = newVal;
1910        } else {
1911            this.disconnectionSqlCodes = null;
1912        }
1913    }
1914
1915    /**
1916     * Sets the JDBC Driver instance to use for this pool.
1917     * <p>
1918     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
1919     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
1920     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
1921     * </p>
1922     *
1923     * @param driver
1924     *            The JDBC Driver instance to use for this pool.
1925     */
1926    public synchronized void setDriver(final Driver driver) {
1927        this.driver = driver;
1928    }
1929
1930    /**
1931     * <p>
1932     * Sets the class loader to be used to load the JDBC driver.
1933     * </p>
1934     * <p>
1935     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
1936     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
1937     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
1938     * </p>
1939     *
1940     * @param driverClassLoader
1941     *            the class loader with which to load the JDBC driver
1942     */
1943    public synchronized void setDriverClassLoader(final ClassLoader driverClassLoader) {
1944        this.driverClassLoader = driverClassLoader;
1945    }
1946
1947    /**
1948     * <p>
1949     * Sets the JDBC driver class name.
1950     * </p>
1951     * <p>
1952     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
1953     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
1954     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
1955     * </p>
1956     *
1957     * @param driverClassName
1958     *            the class name of the JDBC driver
1959     */
1960    public synchronized void setDriverClassName(final String driverClassName) {
1961        if (driverClassName != null && driverClassName.trim().length() > 0) {
1962            this.driverClassName = driverClassName;
1963        } else {
1964            this.driverClassName = null;
1965        }
1966    }
1967
1968    /**
1969     * Sets the value of the flag that controls whether or not connections being returned to the pool will be checked
1970     * and configured with {@link Connection#setAutoCommit(boolean) Connection.setAutoCommit(true)} if the auto commit
1971     * setting is {@code false} when the connection is returned. It is <code>true</code> by default.
1972     *
1973     * @param autoCommitOnReturn
1974     *            Whether or not connections being returned to the pool will be checked and configured with auto-commit.
1975     * @deprecated Use {@link #setAutoCommitOnReturn(boolean)}.
1976     */
1977    @Deprecated
1978    public void setEnableAutoCommitOnReturn(final boolean autoCommitOnReturn) {
1979        this.autoCommitOnReturn = autoCommitOnReturn;
1980    }
1981
1982    /**
1983     * Sets the EvictionPolicy implementation to use with this connection pool.
1984     *
1985     * @param evictionPolicyClassName
1986     *            The fully qualified class name of the EvictionPolicy implementation
1987     */
1988    public synchronized void setEvictionPolicyClassName(final String evictionPolicyClassName) {
1989        if (connectionPool != null) {
1990            connectionPool.setEvictionPolicyClassName(evictionPolicyClassName);
1991        }
1992        this.evictionPolicyClassName = evictionPolicyClassName;
1993    }
1994
1995    /**
1996     * @see #getFastFailValidation()
1997     * @param fastFailValidation
1998     *            true means connections created by this factory will fast fail validation
1999     * @since 2.1
2000     */
2001    public void setFastFailValidation(final boolean fastFailValidation) {
2002        this.fastFailValidation = fastFailValidation;
2003    }
2004
2005    /**
2006     * <p>
2007     * Sets the initial size of the connection pool.
2008     * </p>
2009     * <p>
2010     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
2011     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
2012     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
2013     * </p>
2014     *
2015     * @param initialSize
2016     *            the number of connections created when the pool is initialized
2017     */
2018    public synchronized void setInitialSize(final int initialSize) {
2019        this.initialSize = initialSize;
2020    }
2021
2022    /**
2023     * Sets the JMX name that has been requested for this DataSource. If the requested name is not valid, an alternative
2024     * may be chosen. This DataSource will attempt to register itself using this name. If another component registers
2025     * this DataSource with JMX and this name is valid this name will be used in preference to any specified by the
2026     * other component.
2027     *
2028     * @param jmxName
2029     *            The JMX name that has been requested for this DataSource
2030     */
2031    public void setJmxName(final String jmxName) {
2032        this.jmxName = jmxName;
2033    }
2034
2035    /**
2036     * Sets the LIFO property. True means the pool behaves as a LIFO queue; false means FIFO.
2037     *
2038     * @param lifo
2039     *            the new value for the LIFO property
2040     */
2041    public synchronized void setLifo(final boolean lifo) {
2042        this.lifo = lifo;
2043        if (connectionPool != null) {
2044            connectionPool.setLifo(lifo);
2045        }
2046    }
2047
2048    /**
2049     * @param logAbandoned
2050     *            new logAbandoned property value
2051     */
2052    public void setLogAbandoned(final boolean logAbandoned) {
2053        if (abandonedConfig == null) {
2054            abandonedConfig = new AbandonedConfig();
2055        }
2056        abandonedConfig.setLogAbandoned(logAbandoned);
2057        final GenericObjectPool<?> gop = this.connectionPool;
2058        if (gop != null) {
2059            gop.setAbandonedConfig(abandonedConfig);
2060        }
2061    }
2062
2063    /**
2064     * When {@link #getMaxConnLifetimeMillis()} is set to limit connection lifetime, this property determines whether or
2065     * not log messages are generated when the pool closes connections due to maximum lifetime exceeded. Set this
2066     * property to false to suppress log messages when connections expire.
2067     *
2068     * @param logExpiredConnections
2069     *            Whether or not log messages are generated when the pool closes connections due to maximum lifetime
2070     *            exceeded.
2071     */
2072    public void setLogExpiredConnections(final boolean logExpiredConnections) {
2073        this.logExpiredConnections = logExpiredConnections;
2074    }
2075
2076    /**
2077     * <strong>BasicDataSource does NOT support this method. </strong>
2078     *
2079     * <p>
2080     * Set the login timeout (in seconds) for connecting to the database.
2081     * </p>
2082     * <p>
2083     * Calls {@link #createDataSource()}, so has the side effect of initializing the connection pool.
2084     * </p>
2085     *
2086     * @param loginTimeout
2087     *            The new login timeout, or zero for no timeout
2088     * @throws UnsupportedOperationException
2089     *             If the DataSource implementation does not support the login timeout feature.
2090     * @throws SQLException
2091     *             if a database access error occurs
2092     */
2093    @Override
2094    public void setLoginTimeout(final int loginTimeout) throws SQLException {
2095        // This method isn't supported by the PoolingDataSource returned by the createDataSource
2096        throw new UnsupportedOperationException("Not supported by BasicDataSource");
2097    }
2098
2099    /**
2100     * <p>
2101     * Sets the log writer being used by this data source.
2102     * </p>
2103     * <p>
2104     * Calls {@link #createDataSource()}, so has the side effect of initializing the connection pool.
2105     * </p>
2106     *
2107     * @param logWriter
2108     *            The new log writer
2109     * @throws SQLException
2110     *             if a database access error occurs
2111     */
2112    @Override
2113    public void setLogWriter(final PrintWriter logWriter) throws SQLException {
2114        createDataSource().setLogWriter(logWriter);
2115        this.logWriter = logWriter;
2116    }
2117
2118    /**
2119     * <p>
2120     * Sets the maximum permitted lifetime of a connection in milliseconds. A value of zero or less indicates an
2121     * infinite lifetime.
2122     * </p>
2123     * <p>
2124     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
2125     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
2126     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
2127     * </p>
2128     *
2129     * @param maxConnLifetimeMillis
2130     *            The maximum permitted lifetime of a connection in milliseconds.
2131     */
2132    public void setMaxConnLifetimeMillis(final long maxConnLifetimeMillis) {
2133        this.maxConnLifetimeMillis = maxConnLifetimeMillis;
2134    }
2135
2136    /**
2137     * Sets the maximum number of connections that can remain idle in the pool. Excess idle connections are destroyed on
2138     * return to the pool.
2139     *
2140     * @see #getMaxIdle()
2141     * @param maxIdle
2142     *            the new value for maxIdle
2143     */
2144    public synchronized void setMaxIdle(final int maxIdle) {
2145        this.maxIdle = maxIdle;
2146        if (connectionPool != null) {
2147            connectionPool.setMaxIdle(maxIdle);
2148        }
2149    }
2150
2151    /**
2152     * <p>
2153     * Sets the value of the <code>maxOpenPreparedStatements</code> property.
2154     * </p>
2155     * <p>
2156     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
2157     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
2158     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
2159     * </p>
2160     *
2161     * @param maxOpenStatements
2162     *            the new maximum number of prepared statements
2163     */
2164    public synchronized void setMaxOpenPreparedStatements(final int maxOpenStatements) {
2165        this.maxOpenPreparedStatements = maxOpenStatements;
2166    }
2167
2168    /**
2169     * Sets the maximum total number of idle and borrows connections that can be active at the same time. Use a negative
2170     * value for no limit.
2171     *
2172     * @param maxTotal
2173     *            the new value for maxTotal
2174     * @see #getMaxTotal()
2175     */
2176    public synchronized void setMaxTotal(final int maxTotal) {
2177        this.maxTotal = maxTotal;
2178        if (connectionPool != null) {
2179            connectionPool.setMaxTotal(maxTotal);
2180        }
2181    }
2182
2183    /**
2184     * Sets the MaxWaitMillis property. Use -1 to make the pool wait indefinitely.
2185     *
2186     * @param maxWaitMillis
2187     *            the new value for MaxWaitMillis
2188     * @see #getMaxWaitMillis()
2189     */
2190    public synchronized void setMaxWaitMillis(final long maxWaitMillis) {
2191        this.maxWaitMillis = maxWaitMillis;
2192        if (connectionPool != null) {
2193            connectionPool.setMaxWaitMillis(maxWaitMillis);
2194        }
2195    }
2196
2197    /**
2198     * Sets the {@link #minEvictableIdleTimeMillis} property.
2199     *
2200     * @param minEvictableIdleTimeMillis
2201     *            the minimum amount of time an object may sit idle in the pool
2202     * @see #minEvictableIdleTimeMillis
2203     */
2204    public synchronized void setMinEvictableIdleTimeMillis(final long minEvictableIdleTimeMillis) {
2205        this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
2206        if (connectionPool != null) {
2207            connectionPool.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
2208        }
2209    }
2210
2211    /**
2212     * Sets the minimum number of idle connections in the pool. The pool attempts to ensure that minIdle connections are
2213     * available when the idle object evictor runs. The value of this property has no effect unless
2214     * {@link #timeBetweenEvictionRunsMillis} has a positive value.
2215     *
2216     * @param minIdle
2217     *            the new value for minIdle
2218     * @see GenericObjectPool#setMinIdle(int)
2219     */
2220    public synchronized void setMinIdle(final int minIdle) {
2221        this.minIdle = minIdle;
2222        if (connectionPool != null) {
2223            connectionPool.setMinIdle(minIdle);
2224        }
2225    }
2226
2227    /**
2228     * Sets the value of the {@link #numTestsPerEvictionRun} property.
2229     *
2230     * @param numTestsPerEvictionRun
2231     *            the new {@link #numTestsPerEvictionRun} value
2232     * @see #numTestsPerEvictionRun
2233     */
2234    public synchronized void setNumTestsPerEvictionRun(final int numTestsPerEvictionRun) {
2235        this.numTestsPerEvictionRun = numTestsPerEvictionRun;
2236        if (connectionPool != null) {
2237            connectionPool.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
2238        }
2239    }
2240
2241    // ------------------------------------------------------ Protected Methods
2242
2243    /**
2244     * <p>
2245     * Sets the {@link #password}.
2246     * </p>
2247     * <p>
2248     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
2249     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
2250     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
2251     * </p>
2252     *
2253     * @param password
2254     *            new value for the password
2255     */
2256    public void setPassword(final String password) {
2257        this.password = password;
2258    }
2259
2260    /**
2261     * <p>
2262     * Sets whether to pool statements or not.
2263     * </p>
2264     * <p>
2265     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
2266     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
2267     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
2268     * </p>
2269     *
2270     * @param poolingStatements
2271     *            pooling on or off
2272     */
2273    public synchronized void setPoolPreparedStatements(final boolean poolingStatements) {
2274        this.poolPreparedStatements = poolingStatements;
2275    }
2276
2277    /**
2278     * @param removeAbandonedOnBorrow
2279     *            true means abandoned connections may be removed when connections are borrowed from the pool.
2280     * @see #getRemoveAbandonedOnBorrow()
2281     */
2282    public void setRemoveAbandonedOnBorrow(final boolean removeAbandonedOnBorrow) {
2283        if (abandonedConfig == null) {
2284            abandonedConfig = new AbandonedConfig();
2285        }
2286        abandonedConfig.setRemoveAbandonedOnBorrow(removeAbandonedOnBorrow);
2287        final GenericObjectPool<?> gop = this.connectionPool;
2288        if (gop != null) {
2289            gop.setAbandonedConfig(abandonedConfig);
2290        }
2291    }
2292
2293    /**
2294     * @param removeAbandonedOnMaintenance
2295     *            true means abandoned connections may be removed on pool maintenance.
2296     * @see #getRemoveAbandonedOnMaintenance()
2297     */
2298    public void setRemoveAbandonedOnMaintenance(final boolean removeAbandonedOnMaintenance) {
2299        if (abandonedConfig == null) {
2300            abandonedConfig = new AbandonedConfig();
2301        }
2302        abandonedConfig.setRemoveAbandonedOnMaintenance(removeAbandonedOnMaintenance);
2303        final GenericObjectPool<?> gop = this.connectionPool;
2304        if (gop != null) {
2305            gop.setAbandonedConfig(abandonedConfig);
2306        }
2307    }
2308
2309    /**
2310     * <p>
2311     * Sets the timeout in seconds before an abandoned connection can be removed.
2312     * </p>
2313     *
2314     * <p>
2315     * Setting this property has no effect if {@link #getRemoveAbandonedOnBorrow()} and
2316     * {@link #getRemoveAbandonedOnMaintenance()} are false.
2317     * </p>
2318     *
2319     * @param removeAbandonedTimeout
2320     *            new abandoned timeout in seconds
2321     * @see #getRemoveAbandonedTimeout()
2322     * @see #getRemoveAbandonedOnBorrow()
2323     * @see #getRemoveAbandonedOnMaintenance()
2324     */
2325    public void setRemoveAbandonedTimeout(final int removeAbandonedTimeout) {
2326        if (abandonedConfig == null) {
2327            abandonedConfig = new AbandonedConfig();
2328        }
2329        abandonedConfig.setRemoveAbandonedTimeout(removeAbandonedTimeout);
2330        final GenericObjectPool<?> gop = this.connectionPool;
2331        if (gop != null) {
2332            gop.setAbandonedConfig(abandonedConfig);
2333        }
2334    }
2335
2336    /**
2337     * Sets the flag that controls if a connection will be rolled back when it is returned to the pool if auto commit is
2338     * not enabled and the connection is not read only.
2339     *
2340     * @param rollbackOnReturn
2341     *            whether a connection will be rolled back when it is returned to the pool.
2342     */
2343    public void setRollbackOnReturn(final boolean rollbackOnReturn) {
2344        this.rollbackOnReturn = rollbackOnReturn;
2345    }
2346
2347    /**
2348     * Sets the minimum amount of time a connection may sit idle in the pool before it is eligible for eviction by the
2349     * idle object evictor, with the extra condition that at least "minIdle" connections remain in the pool.
2350     *
2351     * @param softMinEvictableIdleTimeMillis
2352     *            minimum amount of time a connection may sit idle in the pool before it is eligible for eviction,
2353     *            assuming there are minIdle idle connections in the pool.
2354     * @see #getSoftMinEvictableIdleTimeMillis
2355     */
2356    public synchronized void setSoftMinEvictableIdleTimeMillis(final long softMinEvictableIdleTimeMillis) {
2357        this.softMinEvictableIdleTimeMillis = softMinEvictableIdleTimeMillis;
2358        if (connectionPool != null) {
2359            connectionPool.setSoftMinEvictableIdleTimeMillis(softMinEvictableIdleTimeMillis);
2360        }
2361    }
2362
2363    /**
2364     * Sets the {@link #testOnBorrow} property. This property determines whether or not the pool will validate objects
2365     * before they are borrowed from the pool.
2366     *
2367     * @param testOnBorrow
2368     *            new value for testOnBorrow property
2369     */
2370    public synchronized void setTestOnBorrow(final boolean testOnBorrow) {
2371        this.testOnBorrow = testOnBorrow;
2372        if (connectionPool != null) {
2373            connectionPool.setTestOnBorrow(testOnBorrow);
2374        }
2375    }
2376
2377    /**
2378     * Sets the {@link #testOnCreate} property. This property determines whether or not the pool will validate objects
2379     * immediately after they are created by the pool
2380     *
2381     * @param testOnCreate
2382     *            new value for testOnCreate property
2383     */
2384    public synchronized void setTestOnCreate(final boolean testOnCreate) {
2385        this.testOnCreate = testOnCreate;
2386        if (connectionPool != null) {
2387            connectionPool.setTestOnCreate(testOnCreate);
2388        }
2389    }
2390
2391    /**
2392     * Sets the <code>testOnReturn</code> property. This property determines whether or not the pool will validate
2393     * objects before they are returned to the pool.
2394     *
2395     * @param testOnReturn
2396     *            new value for testOnReturn property
2397     */
2398    public synchronized void setTestOnReturn(final boolean testOnReturn) {
2399        this.testOnReturn = testOnReturn;
2400        if (connectionPool != null) {
2401            connectionPool.setTestOnReturn(testOnReturn);
2402        }
2403    }
2404
2405    /**
2406     * Sets the <code>testWhileIdle</code> property. This property determines whether or not the idle object evictor
2407     * will validate connections.
2408     *
2409     * @param testWhileIdle
2410     *            new value for testWhileIdle property
2411     */
2412    public synchronized void setTestWhileIdle(final boolean testWhileIdle) {
2413        this.testWhileIdle = testWhileIdle;
2414        if (connectionPool != null) {
2415            connectionPool.setTestWhileIdle(testWhileIdle);
2416        }
2417    }
2418
2419    /**
2420     * Sets the {@link #timeBetweenEvictionRunsMillis} property.
2421     *
2422     * @param timeBetweenEvictionRunsMillis
2423     *            the new time between evictor runs
2424     * @see #timeBetweenEvictionRunsMillis
2425     */
2426    public synchronized void setTimeBetweenEvictionRunsMillis(final long timeBetweenEvictionRunsMillis) {
2427        this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
2428        if (connectionPool != null) {
2429            connectionPool.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
2430        }
2431    }
2432
2433    /**
2434     * <p>
2435     * Sets the {@link #url}.
2436     * </p>
2437     * <p>
2438     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
2439     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
2440     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
2441     * </p>
2442     *
2443     * @param url
2444     *            the new value for the JDBC connection url
2445     */
2446    public synchronized void setUrl(final String url) {
2447        this.url = url;
2448    }
2449
2450    /**
2451     * <p>
2452     * Sets the {@link #userName}.
2453     * </p>
2454     * <p>
2455     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
2456     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
2457     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
2458     * </p>
2459     *
2460     * @param userName
2461     *            the new value for the JDBC connection user name
2462     */
2463    public void setUsername(final String userName) {
2464        this.userName = userName;
2465    }
2466
2467    /**
2468     * <p>
2469     * Sets the {@link #validationQuery}.
2470     * </p>
2471     * <p>
2472     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
2473     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
2474     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
2475     * </p>
2476     *
2477     * @param validationQuery
2478     *            the new value for the validation query
2479     */
2480    public void setValidationQuery(final String validationQuery) {
2481        if (validationQuery != null && validationQuery.trim().length() > 0) {
2482            this.validationQuery = validationQuery;
2483        } else {
2484            this.validationQuery = null;
2485        }
2486    }
2487
2488    /**
2489     * Sets the validation query timeout, the amount of time, in seconds, that connection validation will wait for a
2490     * response from the database when executing a validation query. Use a value less than or equal to 0 for no timeout.
2491     * <p>
2492     * Note: this method currently has no effect once the pool has been initialized. The pool is initialized the first
2493     * time one of the following methods is invoked: <code>getConnection, setLogwriter,
2494     * setLoginTimeout, getLoginTimeout, getLogWriter.</code>
2495     * </p>
2496     *
2497     * @param validationQueryTimeoutSeconds
2498     *            new validation query timeout value in seconds
2499     */
2500    public void setValidationQueryTimeout(final int validationQueryTimeoutSeconds) {
2501        this.validationQueryTimeoutSeconds = validationQueryTimeoutSeconds;
2502    }
2503
2504    /**
2505     * Starts the connection pool maintenance task, if configured.
2506     */
2507    protected void startPoolMaintenance() {
2508        if (connectionPool != null && timeBetweenEvictionRunsMillis > 0) {
2509            connectionPool.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
2510        }
2511    }
2512
2513    @Override
2514    public <T> T unwrap(final Class<T> iface) throws SQLException {
2515        throw new SQLException("BasicDataSource is not a wrapper.");
2516    }
2517
2518    private void updateJmxName(final GenericObjectPoolConfig<?> config) {
2519        if (registeredJmxObjectName == null) {
2520            return;
2521        }
2522        final StringBuilder base = new StringBuilder(registeredJmxObjectName.toString());
2523        base.append(Constants.JMX_CONNECTION_POOL_BASE_EXT);
2524        config.setJmxNameBase(base.toString());
2525        config.setJmxNamePrefix(Constants.JMX_CONNECTION_POOL_PREFIX);
2526    }
2527}