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-dbcp2</em> and <em>commons-pool2</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$
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                final ClassLoader loader = BasicDataSource.class.getClassLoader();
085                final 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                final String poolPackageName = PooledObject.class.getPackage().getName();
097                loader.loadClass(poolPackageName + ".impl.LinkedBlockingDeque$Node");
098                loader.loadClass(poolPackageName + ".impl.GenericKeyedObjectPool$ObjectDeque");
099            }
100        } catch (final 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;
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(final 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;
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(final 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(final int defaultTransactionIsolation) {
198        this.defaultTransactionIsolation = defaultTransactionIsolation;
199    }
200
201
202    private Integer defaultQueryTimeout;
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(final 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;
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(final 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(final boolean cacheState) {
280        this.cacheState = cacheState;
281    }
282
283    /**
284     * The instance of the JDBC Driver to use.
285     */
286    private Driver driver;
287
288    /**
289     * Returns the JDBC Driver that has been configured for use by this pool.
290     * <p>
291     * Note: This getter only returns the last value set by a call to
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(final Driver driver) {
313        this.driver = driver;
314    }
315
316    /**
317     * The fully qualified Java class name of the JDBC driver to be used.
318     */
319    private String driverClassName;
320
321    /**
322     * Returns the JDBC driver class name.
323     * <p>
324     * Note: This getter only returns the last value set by a call to
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(final 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;
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            final 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(final boolean lifo) {
417        this.lifo = lifo;
418        if (connectionPool != null) {
419            connectionPool.setLifo(lifo);
420        }
421    }
422
423    /**
424     * The maximum number of active connections that can be allocated from
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(final 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(final 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(final 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(final 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(final 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(final 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(final 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(final 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(final 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(final boolean testOnReturn) {
761        this.testOnReturn = testOnReturn;
762        if (connectionPool != null) {
763            connectionPool.setTestOnReturn(testOnReturn);
764        }
765    }
766
767    /**
768     * The number of milliseconds to sleep between runs of the idle object
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(final 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(final 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(final 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(final 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() minEvictableIdleTimeMillis}
899     * is set to a positive value, minEvictableIdleTimeMillis 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            final 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(final 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        final 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        final 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;
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(final 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;
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(final 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;
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(final 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;
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(final 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(final 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        final 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        final 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(final Collection<String> connectionInitSqls) {
1216        if (connectionInitSqls != null && connectionInitSqls.size() > 0) {
1217            ArrayList<String> newVal = null;
1218            for (final 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(final 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(final 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(final boolean logExpiredConnections) {
1311        this.logExpiredConnections = logExpiredConnections;
1312    }
1313
1314    private String jmxName;
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(final 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(final 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(final 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        final 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        final 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(final Collection<String> disconnectionSqlCodes) {
1430        if (disconnectionSqlCodes != null && disconnectionSqlCodes.size() > 0) {
1431            HashSet<String> newVal = null;
1432            for (final 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(final 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;
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;
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            final PrivilegedExceptionAction<Connection> action = new PaGetConnection();
1523            try {
1524                return AccessController.doPrivileged(action);
1525            } catch (final PrivilegedActionException e) {
1526                final 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(final String user, final 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(final 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(final 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            final boolean removeAbandonedOnMaintenance) {
1665        if (abandonedConfig == null) {
1666            abandonedConfig = new AbandonedConfig();
1667        }
1668        abandonedConfig.setRemoveAbandonedOnMaintenance(
1669                removeAbandonedOnMaintenance);
1670        final GenericObjectPool<?> gop = this.connectionPool;
1671        if (gop != null) {
1672            gop.setAbandonedConfig(abandonedConfig);
1673        }
1674    }
1675
1676    /**
1677     * <p>Flag to remove abandoned connections if they exceed the
1678     * removeAbandonedTimeout during pool maintenance.</p>
1679     *
1680     * <p>The default value is false.</p>
1681     *
1682     * <p>If set to true a connection is considered abandoned and eligible
1683     * for removal if it has not been used for more than
1684     * {@link #getRemoveAbandonedTimeout() removeAbandonedTimeout} seconds.</p>
1685     *
1686     * @see #getRemoveAbandonedTimeout()
1687     */
1688    @Override
1689    public boolean getRemoveAbandonedOnMaintenance() {
1690        if (abandonedConfig != null) {
1691            return abandonedConfig.getRemoveAbandonedOnMaintenance();
1692        }
1693        return false;
1694    }
1695
1696    /**
1697     * @param removeAbandonedOnBorrow true means abandoned connections may be
1698     *                                removed when connections are borrowed from the pool.
1699     * @see #getRemoveAbandonedOnBorrow()
1700     */
1701    public void setRemoveAbandonedOnBorrow(final boolean removeAbandonedOnBorrow) {
1702        if (abandonedConfig == null) {
1703            abandonedConfig = new AbandonedConfig();
1704        }
1705        abandonedConfig.setRemoveAbandonedOnBorrow(removeAbandonedOnBorrow);
1706        final GenericObjectPool<?> gop = this.connectionPool;
1707        if (gop != null) {
1708            gop.setAbandonedConfig(abandonedConfig);
1709        }
1710    }
1711
1712    /**
1713     * <p>Timeout in seconds before an abandoned connection can be removed.</p>
1714     *
1715     * <p>Creating a Statement, PreparedStatement or CallableStatement or using
1716     * one of these to execute a query (using one of the execute methods)
1717     * resets the lastUsed property of the parent connection.</p>
1718     *
1719     * <p>Abandoned connection cleanup happens when:</p>
1720     * <ul>
1721     * <li>{@link #getRemoveAbandonedOnBorrow()} or
1722     *     {@link #getRemoveAbandonedOnMaintenance()} = true</li>
1723     * <li>{@link #getNumIdle() numIdle} &lt; 2</li>
1724     * <li>{@link #getNumActive() numActive} &gt; {@link #getMaxTotal() maxTotal} - 3</li>
1725     * </ul>
1726     *
1727     * <p>The default value is 300 seconds.</p>
1728     */
1729    @Override
1730    public int getRemoveAbandonedTimeout() {
1731        if (abandonedConfig != null) {
1732            return abandonedConfig.getRemoveAbandonedTimeout();
1733        }
1734        return 300;
1735    }
1736
1737    /**
1738     * <p>Sets the timeout in seconds before an abandoned connection can be
1739     * removed.</p>
1740     *
1741     * <p>Setting this property has no effect if
1742     * {@link #getRemoveAbandonedOnBorrow()} and
1743     * {@link #getRemoveAbandonedOnMaintenance()} are false.</p>
1744     *
1745     * @param removeAbandonedTimeout new abandoned timeout in seconds
1746     * @see #getRemoveAbandonedTimeout()
1747     * @see #getRemoveAbandonedOnBorrow()
1748     * @see #getRemoveAbandonedOnMaintenance()
1749     */
1750    public void setRemoveAbandonedTimeout(final int removeAbandonedTimeout) {
1751        if (abandonedConfig == null) {
1752            abandonedConfig = new AbandonedConfig();
1753        }
1754        abandonedConfig.setRemoveAbandonedTimeout(removeAbandonedTimeout);
1755        final GenericObjectPool<?> gop = this.connectionPool;
1756        if (gop != null) {
1757            gop.setAbandonedConfig(abandonedConfig);
1758        }
1759    }
1760
1761    /**
1762     * <p>Flag to log stack traces for application code which abandoned
1763     * a Statement or Connection.
1764     * </p>
1765     * <p>Defaults to false.
1766     * </p>
1767     * <p>Logging of abandoned Statements and Connections adds overhead
1768     * for every Connection open or new Statement because a stack
1769     * trace has to be generated. </p>
1770     */
1771    @Override
1772    public boolean getLogAbandoned() {
1773        if (abandonedConfig != null) {
1774            return abandonedConfig.getLogAbandoned();
1775        }
1776        return false;
1777    }
1778
1779    /**
1780     * @param logAbandoned new logAbandoned property value
1781     */
1782    public void setLogAbandoned(final boolean logAbandoned) {
1783        if (abandonedConfig == null) {
1784            abandonedConfig = new AbandonedConfig();
1785        }
1786        abandonedConfig.setLogAbandoned(logAbandoned);
1787        final GenericObjectPool<?> gop = this.connectionPool;
1788        if (gop != null) {
1789            gop.setAbandonedConfig(abandonedConfig);
1790        }
1791    }
1792
1793    /**
1794     * Gets the log writer to be used by this configuration to log
1795     * information on abandoned objects.
1796     */
1797    public PrintWriter getAbandonedLogWriter() {
1798        if (abandonedConfig != null) {
1799            return abandonedConfig.getLogWriter();
1800        }
1801        return null;
1802    }
1803
1804    /**
1805     * Sets the log writer to be used by this configuration to log
1806     * information on abandoned objects.
1807     *
1808     * @param logWriter The new log writer
1809     */
1810    public void setAbandonedLogWriter(final PrintWriter logWriter) {
1811        if (abandonedConfig == null) {
1812            abandonedConfig = new AbandonedConfig();
1813        }
1814        abandonedConfig.setLogWriter(logWriter);
1815        final GenericObjectPool<?> gop = this.connectionPool;
1816        if (gop != null) {
1817            gop.setAbandonedConfig(abandonedConfig);
1818        }
1819    }
1820
1821    /**
1822     * If the connection pool implements {@link org.apache.commons.pool2.UsageTracking UsageTracking}, should the
1823     * connection pool record a stack trace every time a method is called on a
1824     * pooled connection and retain the most recent stack trace to aid debugging
1825     * of abandoned connections?
1826     *
1827     * @return <code>true</code> if usage tracking is enabled
1828     */
1829    @Override
1830    public boolean getAbandonedUsageTracking() {
1831        if (abandonedConfig != null) {
1832            return abandonedConfig.getUseUsageTracking();
1833        }
1834        return false;
1835    }
1836
1837    /**
1838     * If the connection pool implements {@link org.apache.commons.pool2.UsageTracking UsageTracking}, configure
1839     * whether the connection pool should record a stack trace every time a
1840     * method is called on a pooled connection and retain the most recent stack
1841     * trace to aid debugging of abandoned connections.
1842     *
1843     * @param   usageTracking    A value of <code>true</code> will enable
1844     *                              the recording of a stack trace on every use
1845     *                              of a pooled connection
1846     */
1847    public void setAbandonedUsageTracking(final boolean usageTracking) {
1848        if (abandonedConfig == null) {
1849            abandonedConfig = new AbandonedConfig();
1850        }
1851        abandonedConfig.setUseUsageTracking(usageTracking);
1852        final GenericObjectPool<?> gop = this.connectionPool;
1853        if (gop != null) {
1854            gop.setAbandonedConfig(abandonedConfig);
1855        }
1856    }
1857
1858    // --------------------------------------------------------- Public Methods
1859
1860    /**
1861     * Add a custom connection property to the set that will be passed to our
1862     * JDBC driver. This <strong>MUST</strong> be called before the first
1863     * connection is retrieved (along with all the other configuration
1864     * property setters). Calls to this method after the connection pool
1865     * has been initialized have no effect.
1866     *
1867     * @param name Name of the custom connection property
1868     * @param value Value of the custom connection property
1869     */
1870    public void addConnectionProperty(final String name, final String value) {
1871        connectionProperties.put(name, value);
1872    }
1873
1874    /**
1875     * Remove a custom connection property.
1876     *
1877     * @param name Name of the custom connection property to remove
1878     * @see #addConnectionProperty(String, String)
1879     */
1880    public void removeConnectionProperty(final String name) {
1881        connectionProperties.remove(name);
1882    }
1883
1884    /**
1885     * Sets the connection properties passed to driver.connect(...).
1886     *
1887     * Format of the string must be [propertyName=property;]*
1888     *
1889     * NOTE - The "user" and "password" properties will be added
1890     * explicitly, so they do not need to be included here.
1891     *
1892     * @param connectionProperties the connection properties used to
1893     * create new connections
1894     */
1895    public void setConnectionProperties(final String connectionProperties) {
1896        if (connectionProperties == null) {
1897            throw new NullPointerException("connectionProperties is null");
1898        }
1899
1900        final String[] entries = connectionProperties.split(";");
1901        final Properties properties = new Properties();
1902        for (final String entry : entries) {
1903            if (entry.length() > 0) {
1904                final int index = entry.indexOf('=');
1905                if (index > 0) {
1906                    final String name = entry.substring(0, index);
1907                    final String value = entry.substring(index + 1);
1908                    properties.setProperty(name, value);
1909                } else {
1910                    // no value is empty string which is how java.util.Properties works
1911                    properties.setProperty(entry, "");
1912                }
1913            }
1914        }
1915        this.connectionProperties = properties;
1916    }
1917
1918    private boolean closed;
1919
1920    /**
1921     * <p>Closes and releases all idle connections that are currently stored in the connection pool
1922     * associated with this data source.</p>
1923     *
1924     * <p>Connections that are checked out to clients when this method is invoked are not affected.
1925     * When client applications subsequently invoke {@link Connection#close()} to return
1926     * these connections to the pool, the underlying JDBC connections are closed.</p>
1927     *
1928     * <p>Attempts to acquire connections using {@link #getConnection()} after this method has been
1929     * invoked result in SQLExceptions.</p>
1930     *
1931     * <p>This method is idempotent - i.e., closing an already closed BasicDataSource has no effect
1932     * and does not generate exceptions.</p>
1933     *
1934     * @throws SQLException if an error occurs closing idle connections
1935     */
1936    @Override
1937    public synchronized void close() throws SQLException {
1938        if (registeredJmxName != null) {
1939            final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
1940            try {
1941                mbs.unregisterMBean(registeredJmxName);
1942            } catch (final JMException e) {
1943                log.warn("Failed to unregister the JMX name: " + registeredJmxName, e);
1944            } finally {
1945                registeredJmxName = null;
1946            }
1947        }
1948        closed = true;
1949        final GenericObjectPool<?> oldpool = connectionPool;
1950        connectionPool = null;
1951        dataSource = null;
1952        try {
1953            if (oldpool != null) {
1954                oldpool.close();
1955            }
1956        } catch(final RuntimeException e) {
1957            throw e;
1958        } catch(final Exception e) {
1959            throw new SQLException(Utils.getMessage("pool.close.fail"), e);
1960        }
1961    }
1962
1963    /**
1964     * If true, this data source is closed and no more connections can be retrieved from this datasource.
1965     * @return true, if the data source is closed; false otherwise
1966     */
1967    @Override
1968    public synchronized boolean isClosed() {
1969        return closed;
1970    }
1971
1972    @Override
1973    public boolean isWrapperFor(final Class<?> iface) throws SQLException {
1974        return false;
1975    }
1976
1977    @Override
1978    public <T> T unwrap(final Class<T> iface) throws SQLException {
1979        throw new SQLException("BasicDataSource is not a wrapper.");
1980    }
1981
1982    @Override
1983    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
1984        throw new SQLFeatureNotSupportedException();
1985    }
1986
1987    /**
1988     * Manually invalidates a connection, effectively requesting the pool to try
1989     * to close it, remove it from the pool and reclaim pool capacity.
1990     *
1991     * @throws IllegalStateException
1992     *             if invalidating the connection failed.
1993     * @since 2.1
1994     */
1995    public void invalidateConnection(final Connection connection) throws IllegalStateException {
1996        if (connection == null) {
1997            return;
1998        }
1999        if (connectionPool == null) {
2000            throw new IllegalStateException("Cannot invalidate connection: ConnectionPool is null.");
2001        }
2002
2003        final PoolableConnection poolableConnection;
2004        try {
2005            poolableConnection = connection.unwrap(PoolableConnection.class);
2006            if (poolableConnection == null) {
2007                throw new IllegalStateException(
2008                        "Cannot invalidate connection: Connection is not a poolable connection.");
2009            }
2010        } catch (final SQLException e) {
2011            throw new IllegalStateException("Cannot invalidate connection: Unwrapping poolable connection failed.", e);
2012        }
2013
2014        try {
2015            connectionPool.invalidateObject(poolableConnection);
2016        } catch (final Exception e) {
2017            throw new IllegalStateException("Invalidating connection threw unexpected exception", e);
2018        }
2019    }
2020
2021    // ------------------------------------------------------ Protected Methods
2022
2023
2024    /**
2025     * <p>Create (if necessary) and return the internal data source we are
2026     * using to manage our connections.</p>
2027     *
2028     * @throws SQLException if the object pool cannot be created.
2029     */
2030    protected DataSource createDataSource()
2031        throws SQLException {
2032        if (closed) {
2033            throw new SQLException("Data source is closed");
2034        }
2035
2036        // Return the pool if we have already created it
2037        // This is double-checked locking. This is safe since dataSource is
2038        // volatile and the code is targeted at Java 5 onwards.
2039        if (dataSource != null) {
2040            return dataSource;
2041        }
2042        synchronized (this) {
2043            if (dataSource != null) {
2044                return dataSource;
2045            }
2046
2047            jmxRegister();
2048
2049            // create factory which returns raw physical connections
2050            final ConnectionFactory driverConnectionFactory = createConnectionFactory();
2051
2052            // Set up the poolable connection factory
2053            boolean success = false;
2054            PoolableConnectionFactory poolableConnectionFactory;
2055            try {
2056                poolableConnectionFactory = createPoolableConnectionFactory(
2057                        driverConnectionFactory);
2058                poolableConnectionFactory.setPoolStatements(
2059                        poolPreparedStatements);
2060                poolableConnectionFactory.setMaxOpenPreparedStatements(
2061                        maxOpenPreparedStatements);
2062                success = true;
2063            } catch (final SQLException se) {
2064                throw se;
2065            } catch (final RuntimeException rte) {
2066                throw rte;
2067            } catch (final Exception ex) {
2068                throw new SQLException("Error creating connection factory", ex);
2069            }
2070
2071            if (success) {
2072                // create a pool for our connections
2073                createConnectionPool(poolableConnectionFactory);
2074            }
2075
2076            // Create the pooling data source to manage connections
2077            DataSource newDataSource;
2078            success = false;
2079            try {
2080                newDataSource = createDataSourceInstance();
2081                newDataSource.setLogWriter(logWriter);
2082                success = true;
2083            } catch (final SQLException se) {
2084                throw se;
2085            } catch (final RuntimeException rte) {
2086                throw rte;
2087            } catch (final Exception ex) {
2088                throw new SQLException("Error creating datasource", ex);
2089            } finally {
2090                if (!success) {
2091                    closeConnectionPool();
2092                }
2093            }
2094
2095            // If initialSize > 0, preload the pool
2096            try {
2097                for (int i = 0 ; i < initialSize ; i++) {
2098                    connectionPool.addObject();
2099                }
2100            } catch (final Exception e) {
2101                closeConnectionPool();
2102                throw new SQLException("Error preloading the connection pool", e);
2103            }
2104
2105            // If timeBetweenEvictionRunsMillis > 0, start the pool's evictor task
2106            startPoolMaintenance();
2107
2108            dataSource = newDataSource;
2109            return dataSource;
2110        }
2111    }
2112
2113    /**
2114     * Creates a JDBC connection factory for this datasource.  The JDBC driver
2115     * is loaded using the following algorithm:
2116     * <ol>
2117     * <li>If a Driver instance has been specified via
2118     * {@link #setDriver(Driver)} use it</li>
2119     * <li>If no Driver instance was specified and {@link #driverClassName} is
2120     * specified that class is loaded using the {@link ClassLoader} of this
2121     * class or, if {@link #driverClassLoader} is set, {@link #driverClassName}
2122     * is loaded with the specified {@link ClassLoader}.</li>
2123     * <li>If {@link #driverClassName} is specified and the previous attempt
2124     * fails, the class is loaded using the context class loader of the current
2125     * thread.</li>
2126     * <li>If a driver still isn't loaded one is loaded via the
2127     * {@link DriverManager} using the specified {@link #url}.
2128     * </ol>
2129     * This method exists so subclasses can replace the implementation class.
2130     */
2131    protected ConnectionFactory createConnectionFactory() throws SQLException {
2132        // Load the JDBC driver class
2133        Driver driverToUse = this.driver;
2134
2135        if (driverToUse == null) {
2136            Class<?> driverFromCCL = null;
2137            if (driverClassName != null) {
2138                try {
2139                    try {
2140                        if (driverClassLoader == null) {
2141                            driverFromCCL = Class.forName(driverClassName);
2142                        } else {
2143                            driverFromCCL = Class.forName(
2144                                    driverClassName, true, driverClassLoader);
2145                        }
2146                    } catch (final ClassNotFoundException cnfe) {
2147                        driverFromCCL = Thread.currentThread(
2148                                ).getContextClassLoader().loadClass(
2149                                        driverClassName);
2150                    }
2151                } catch (final Exception t) {
2152                    final String message = "Cannot load JDBC driver class '" +
2153                        driverClassName + "'";
2154                    logWriter.println(message);
2155                    t.printStackTrace(logWriter);
2156                    throw new SQLException(message, t);
2157                }
2158            }
2159
2160            try {
2161                if (driverFromCCL == null) {
2162                    driverToUse = DriverManager.getDriver(url);
2163                } else {
2164                    // Usage of DriverManager is not possible, as it does not
2165                    // respect the ContextClassLoader
2166                    // N.B. This cast may cause ClassCastException which is handled below
2167                    driverToUse = (Driver) driverFromCCL.getConstructor().newInstance();
2168                    if (!driverToUse.acceptsURL(url)) {
2169                        throw new SQLException("No suitable driver", "08001");
2170                    }
2171                }
2172            } catch (final Exception t) {
2173                final String message = "Cannot create JDBC driver of class '" +
2174                    (driverClassName != null ? driverClassName : "") +
2175                    "' for connect URL '" + url + "'";
2176                logWriter.println(message);
2177                t.printStackTrace(logWriter);
2178                throw new SQLException(message, t);
2179            }
2180        }
2181
2182        // Set up the driver connection factory we will use
2183        final String user = username;
2184        if (user != null) {
2185            connectionProperties.put("user", user);
2186        } else {
2187            log("DBCP DataSource configured without a 'username'");
2188        }
2189
2190        final String pwd = password;
2191        if (pwd != null) {
2192            connectionProperties.put("password", pwd);
2193        } else {
2194            log("DBCP DataSource configured without a 'password'");
2195        }
2196
2197        final ConnectionFactory driverConnectionFactory =
2198                new DriverConnectionFactory(driverToUse, url, connectionProperties);
2199        return driverConnectionFactory;
2200    }
2201
2202    /**
2203     * Creates a connection pool for this datasource.  This method only exists
2204     * so subclasses can replace the implementation class.
2205     *
2206     * This implementation configures all pool properties other than
2207     * timeBetweenEvictionRunsMillis.  Setting that property is deferred to
2208     * {@link #startPoolMaintenance()}, since setting timeBetweenEvictionRunsMillis
2209     * to a positive value causes {@link GenericObjectPool}'s eviction timer
2210     * to be started.
2211     */
2212    protected void createConnectionPool(final PoolableConnectionFactory factory) {
2213        // Create an object pool to contain our active connections
2214        final GenericObjectPoolConfig config = new GenericObjectPoolConfig();
2215        updateJmxName(config);
2216        config.setJmxEnabled(registeredJmxName != null);  // Disable JMX on the underlying pool if the DS is not registered.
2217        final GenericObjectPool<PoolableConnection> gop = createObjectPool(factory, config, abandonedConfig);
2218        gop.setMaxTotal(maxTotal);
2219        gop.setMaxIdle(maxIdle);
2220        gop.setMinIdle(minIdle);
2221        gop.setMaxWaitMillis(maxWaitMillis);
2222        gop.setTestOnCreate(testOnCreate);
2223        gop.setTestOnBorrow(testOnBorrow);
2224        gop.setTestOnReturn(testOnReturn);
2225        gop.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
2226        gop.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
2227        gop.setSoftMinEvictableIdleTimeMillis(softMinEvictableIdleTimeMillis);
2228        gop.setTestWhileIdle(testWhileIdle);
2229        gop.setLifo(lifo);
2230        gop.setSwallowedExceptionListener(new SwallowedExceptionLogger(log, logExpiredConnections));
2231        gop.setEvictionPolicyClassName(evictionPolicyClassName);
2232        factory.setPool(gop);
2233        connectionPool = gop;
2234    }
2235
2236    /**
2237     * Creates an object pool used to provide pooling support for {@link Connection JDBC connections}.
2238     *
2239     * @param factory         the object factory
2240     * @param poolConfig      the object pool configuration
2241     * @param abandonedConfig the abandoned objects configuration
2242     * @return a non-null instance
2243     */
2244    protected  GenericObjectPool<PoolableConnection> createObjectPool(
2245            final PoolableConnectionFactory factory, final GenericObjectPoolConfig poolConfig,
2246            final AbandonedConfig abandonedConfig) {
2247        GenericObjectPool<PoolableConnection> gop;
2248        if (abandonedConfig != null &&
2249                (abandonedConfig.getRemoveAbandonedOnBorrow() ||
2250                        abandonedConfig.getRemoveAbandonedOnMaintenance())) {
2251            gop = new GenericObjectPool<>(factory, poolConfig, abandonedConfig);
2252        }
2253        else {
2254            gop = new GenericObjectPool<>(factory, poolConfig);
2255        }
2256        return gop;
2257    }
2258
2259    /**
2260     * Closes the connection pool, silently swallowing any exception that occurs.
2261     */
2262    private void closeConnectionPool() {
2263        final GenericObjectPool<?> oldpool = connectionPool;
2264        connectionPool = null;
2265        try {
2266            if (oldpool != null) {
2267                oldpool.close();
2268            }
2269        } catch(final Exception e) {
2270            /* Ignore */
2271        }
2272    }
2273
2274    /**
2275     * Starts the connection pool maintenance task, if configured.
2276     */
2277    protected void startPoolMaintenance() {
2278        if (connectionPool != null && timeBetweenEvictionRunsMillis > 0) {
2279            connectionPool.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
2280        }
2281    }
2282
2283    /**
2284     * Creates the actual data source instance.  This method only exists so
2285     * that subclasses can replace the implementation class.
2286     *
2287     * @throws SQLException if unable to create a datasource instance
2288     */
2289    protected DataSource createDataSourceInstance() throws SQLException {
2290        final PoolingDataSource<PoolableConnection> pds = new PoolingDataSource<>(connectionPool);
2291        pds.setAccessToUnderlyingConnectionAllowed(isAccessToUnderlyingConnectionAllowed());
2292        return pds;
2293    }
2294
2295    /**
2296     * Creates the PoolableConnectionFactory and attaches it to the connection pool.  This method only exists
2297     * so subclasses can replace the default implementation.
2298     *
2299     * @param driverConnectionFactory JDBC connection factory
2300     * @throws SQLException if an error occurs creating the PoolableConnectionFactory
2301     */
2302    protected PoolableConnectionFactory createPoolableConnectionFactory(
2303            final ConnectionFactory driverConnectionFactory) throws SQLException {
2304        PoolableConnectionFactory connectionFactory = null;
2305        try {
2306            connectionFactory = new PoolableConnectionFactory(driverConnectionFactory, registeredJmxName);
2307            connectionFactory.setValidationQuery(validationQuery);
2308            connectionFactory.setValidationQueryTimeout(validationQueryTimeout);
2309            connectionFactory.setConnectionInitSql(connectionInitSqls);
2310            connectionFactory.setDefaultReadOnly(defaultReadOnly);
2311            connectionFactory.setDefaultAutoCommit(defaultAutoCommit);
2312            connectionFactory.setDefaultTransactionIsolation(defaultTransactionIsolation);
2313            connectionFactory.setDefaultCatalog(defaultCatalog);
2314            connectionFactory.setCacheState(cacheState);
2315            connectionFactory.setPoolStatements(poolPreparedStatements);
2316            connectionFactory.setMaxOpenPreparedStatements(maxOpenPreparedStatements);
2317            connectionFactory.setMaxConnLifetimeMillis(maxConnLifetimeMillis);
2318            connectionFactory.setRollbackOnReturn(getRollbackOnReturn());
2319            connectionFactory.setEnableAutoCommitOnReturn(getEnableAutoCommitOnReturn());
2320            connectionFactory.setDefaultQueryTimeout(getDefaultQueryTimeout());
2321            connectionFactory.setFastFailValidation(fastFailValidation);
2322            connectionFactory.setDisconnectionSqlCodes(disconnectionSqlCodes);
2323            validateConnectionFactory(connectionFactory);
2324        } catch (final RuntimeException e) {
2325            throw e;
2326        } catch (final Exception e) {
2327            throw new SQLException("Cannot create PoolableConnectionFactory (" + e.getMessage() + ")", e);
2328        }
2329        return connectionFactory;
2330    }
2331
2332    protected static void validateConnectionFactory(
2333            final PoolableConnectionFactory connectionFactory) throws Exception {
2334        PoolableConnection conn = null;
2335        PooledObject<PoolableConnection> p = null;
2336        try {
2337            p = connectionFactory.makeObject();
2338            conn = p.getObject();
2339            connectionFactory.activateObject(p);
2340            connectionFactory.validateConnection(conn);
2341            connectionFactory.passivateObject(p);
2342        }
2343        finally {
2344            if (p != null) {
2345                connectionFactory.destroyObject(p);
2346            }
2347        }
2348    }
2349
2350    protected void log(final String message) {
2351        if (logWriter != null) {
2352            logWriter.println(message);
2353        }
2354    }
2355
2356    /**
2357     * Actual name under which this component has been registered.
2358     */
2359    private ObjectName registeredJmxName = null;
2360
2361    private void jmxRegister() {
2362        // Return immediately if this DataSource has already been registered
2363        if (registeredJmxName != null) {
2364            return;
2365        }
2366        // Return immediately if no JMX name has been specified
2367        final String requestedName = getJmxName();
2368        if (requestedName == null) {
2369            return;
2370        }
2371        ObjectName oname;
2372        try {
2373             oname = new ObjectName(requestedName);
2374        } catch (final MalformedObjectNameException e) {
2375            log.warn("The requested JMX name [" + requestedName +
2376                    "] was not valid and will be ignored.");
2377            return;
2378        }
2379
2380        final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
2381        try {
2382            mbs.registerMBean(this, oname);
2383        } catch (InstanceAlreadyExistsException | MBeanRegistrationException
2384                | NotCompliantMBeanException e) {
2385            log.warn("Failed to complete JMX registration", e);
2386        }
2387    }
2388
2389    @Override
2390    public ObjectName preRegister(final MBeanServer server, final ObjectName name) {
2391        final String requestedName = getJmxName();
2392        if (requestedName != null) {
2393            try {
2394                registeredJmxName = new ObjectName(requestedName);
2395            } catch (final MalformedObjectNameException e) {
2396                log.warn("The requested JMX name [" + requestedName +
2397                        "] was not valid and will be ignored.");
2398            }
2399        }
2400        if (registeredJmxName == null) {
2401            registeredJmxName = name;
2402        }
2403        return registeredJmxName;
2404    }
2405
2406    @Override
2407    public void postRegister(final Boolean registrationDone) {
2408        // NO-OP
2409    }
2410
2411    @Override
2412    public void preDeregister() throws Exception {
2413        // NO-OP
2414    }
2415
2416    @Override
2417    public void postDeregister() {
2418        // NO-OP
2419    }
2420
2421    private void updateJmxName(final GenericObjectPoolConfig config) {
2422        if (registeredJmxName == null) {
2423            return;
2424        }
2425        final StringBuilder base = new StringBuilder(registeredJmxName.toString());
2426        base.append(Constants.JMX_CONNECTION_POOL_BASE_EXT);
2427        config.setJmxNameBase(base.toString());
2428        config.setJmxNamePrefix(Constants.JMX_CONNECTION_POOL_PREFIX);
2429    }
2430
2431    protected ObjectName getRegisteredJmxName() {
2432        return registeredJmxName;
2433    }
2434
2435    /**
2436     * @since 2.0
2437     */
2438    private class PaGetConnection implements PrivilegedExceptionAction<Connection> {
2439
2440        @Override
2441        public Connection run() throws SQLException {
2442            return createDataSource().getConnection();
2443        }
2444    }
2445}