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