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