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