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