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