View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.dbcp;
19  
20  import java.io.PrintWriter;
21  import java.util.Properties;
22  import java.util.Collection;
23  import java.util.List;
24  import java.util.ArrayList;
25  import java.util.Iterator;
26  import java.util.Collections;
27  import java.sql.Connection;
28  import java.sql.Driver;
29  import java.sql.DriverManager;
30  import java.sql.SQLException;
31  import javax.sql.DataSource;
32  
33  import org.apache.commons.pool.KeyedObjectPoolFactory;
34  import org.apache.commons.pool.impl.GenericKeyedObjectPool;
35  import org.apache.commons.pool.impl.GenericKeyedObjectPoolFactory;
36  import org.apache.commons.pool.impl.GenericObjectPool;
37  
38  
39  /**
40   * <p>Basic implementation of <code>javax.sql.DataSource</code> that is
41   * configured via JavaBeans properties.  This is not the only way to
42   * combine the <em>commons-dbcp</em> and <em>commons-pool</em> packages,
43   * but provides a "one stop shopping" solution for basic requirements.</p>
44   * 
45   * <p>Users extending this class should take care to use appropriate accessors
46   * rather than accessing protected fields directly to ensure thread-safety.</p>
47   *
48   * @author Glenn L. Nielsen
49   * @author Craig R. McClanahan
50   * @author Dirk Verbeeck
51   * @version $Revision: 1023401 $ $Date: 2010-10-16 21:54:24 -0400 (Sat, 16 Oct 2010) $
52   */
53  public class BasicDataSource implements DataSource {
54      
55      static {
56          // Attempt to prevent deadlocks - see DBCP - 272
57          DriverManager.getDrivers();
58      }
59  
60      // ------------------------------------------------------------- Properties
61  
62      /**
63       * The default auto-commit state of connections created by this pool.
64       */
65      protected volatile boolean defaultAutoCommit = true;
66  
67      /**
68       * Returns the default auto-commit property.
69       * 
70       * @return true if default auto-commit is enabled
71       */
72      public boolean getDefaultAutoCommit() {
73          return this.defaultAutoCommit;
74      }
75  
76      /**
77       * <p>Sets default auto-commit state of connections returned by this
78       * datasource.</p>
79       * <p>
80       * Note: this method currently has no effect once the pool has been
81       * initialized.  The pool is initialized the first time one of the
82       * following methods is invoked: <code>getConnection, setLogwriter,
83       * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
84       * 
85       * @param defaultAutoCommit default auto-commit value
86       */
87      public void setDefaultAutoCommit(boolean defaultAutoCommit) {
88          this.defaultAutoCommit = defaultAutoCommit;
89          this.restartNeeded = true;
90      }
91  
92  
93      /**
94       * The default read-only state of connections created by this pool.
95       */
96      protected transient Boolean defaultReadOnly = null;
97  
98      /**
99       * Returns the default readOnly property.
100      * 
101      * @return true if connections are readOnly by default
102      */
103     public boolean getDefaultReadOnly() {
104         Boolean val = defaultReadOnly;
105         if (val != null) {
106             return val.booleanValue();
107         }
108         return false;
109     }
110 
111     /**
112      * <p>Sets defaultReadonly property.</p>
113      * <p>
114      * Note: this method currently has no effect once the pool has been
115      * initialized.  The pool is initialized the first time one of the
116      * following methods is invoked: <code>getConnection, setLogwriter,
117      * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
118      * 
119      * @param defaultReadOnly default read-only value
120      */
121     public void setDefaultReadOnly(boolean defaultReadOnly) {
122         this.defaultReadOnly = defaultReadOnly ? Boolean.TRUE : Boolean.FALSE;
123         this.restartNeeded = true;
124     }
125 
126     /**
127      * The default TransactionIsolation state of connections created by this pool.
128      */
129     protected volatile int defaultTransactionIsolation =
130         PoolableConnectionFactory.UNKNOWN_TRANSACTIONISOLATION;
131 
132     /**
133      * Returns the default transaction isolation state of returned connections.
134      * 
135      * @return the default value for transaction isolation state
136      * @see Connection#getTransactionIsolation
137      */
138     public int getDefaultTransactionIsolation() {
139         return this.defaultTransactionIsolation;
140     }
141 
142     /**
143      * <p>Sets the default transaction isolation state for returned
144      * connections.</p>
145      * <p>
146      * Note: this method currently has no effect once the pool has been
147      * initialized.  The pool is initialized the first time one of the
148      * following methods is invoked: <code>getConnection, setLogwriter,
149      * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
150      * 
151      * @param defaultTransactionIsolation the default transaction isolation
152      * state
153      * @see Connection#getTransactionIsolation
154      */
155     public void setDefaultTransactionIsolation(int defaultTransactionIsolation) {
156         this.defaultTransactionIsolation = defaultTransactionIsolation;
157         this.restartNeeded = true;
158     }
159 
160 
161     /**
162      * The default "catalog" of connections created by this pool.
163      */
164     protected volatile String defaultCatalog = null;
165 
166     /**
167      * Returns the default catalog.
168      * 
169      * @return the default catalog
170      */
171     public String getDefaultCatalog() {
172         return this.defaultCatalog;
173     }
174 
175     /**
176      * <p>Sets the default catalog.</p>
177      * <p>
178      * Note: this method currently has no effect once the pool has been
179      * initialized.  The pool is initialized the first time one of the
180      * following methods is invoked: <code>getConnection, setLogwriter,
181      * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
182      * 
183      * @param defaultCatalog the default catalog
184      */
185     public void setDefaultCatalog(String defaultCatalog) {
186         if ((defaultCatalog != null) && (defaultCatalog.trim().length() > 0)) {
187             this.defaultCatalog = defaultCatalog;
188         }
189         else {
190             this.defaultCatalog = null;
191         }
192         this.restartNeeded = true;
193     }
194 
195   
196     /**
197      * The fully qualified Java class name of the JDBC driver to be used.
198      */
199     protected String driverClassName = null;
200 
201     /**
202      * Returns the jdbc driver class name.
203      * 
204      * @return the jdbc driver class name
205      */
206     public synchronized String getDriverClassName() {
207         return this.driverClassName;
208     }
209 
210     /**
211      * <p>Sets the jdbc driver class name.</p>
212      * <p>
213      * Note: this method currently has no effect once the pool has been
214      * initialized.  The pool is initialized the first time one of the
215      * following methods is invoked: <code>getConnection, setLogwriter,
216      * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
217      * 
218      * @param driverClassName the class name of the jdbc driver
219      */
220     public synchronized void setDriverClassName(String driverClassName) {
221         if ((driverClassName != null) && (driverClassName.trim().length() > 0)) {
222             this.driverClassName = driverClassName;
223         }
224         else {
225             this.driverClassName = null;
226         }
227         this.restartNeeded = true;
228     }
229 
230     /**
231      * The class loader instance to use to load the JDBC driver. If not
232      * specified, {@link Class#forName(String)} is used to load the JDBC driver.
233      * If specified, {@link Class#forName(String, boolean, ClassLoader)} is
234      * used.
235      */
236     protected ClassLoader driverClassLoader = null;
237     
238     /**
239      * Returns the class loader specified for loading the JDBC driver. Returns
240      * <code>null</code> if no class loader has been explicitly specified.
241      */
242     public synchronized ClassLoader getDriverClassLoader() {
243         return this.driverClassLoader;
244     }
245 
246     /**
247      * <p>Sets the class loader to be used to load the JDBC driver.</p>
248      * <p>
249      * Note: this method currently has no effect once the pool has been
250      * initialized.  The pool is initialized the first time one of the
251      * following methods is invoked: <code>getConnection, setLogwriter,
252      * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
253      * 
254      * @param driverClassLoader the class loader with which to load the JDBC
255      *                          driver
256      */
257     public synchronized void setDriverClassLoader(
258             ClassLoader driverClassLoader) {
259         this.driverClassLoader = driverClassLoader;
260         this.restartNeeded = true;
261     }
262     
263     /**
264      * The maximum number of active connections that can be allocated from
265      * this pool at the same time, or negative for no limit.
266      */
267     protected int maxActive = GenericObjectPool.DEFAULT_MAX_ACTIVE;
268 
269     /**
270      * <p>Returns the maximum number of active connections that can be
271      * allocated at the same time.
272      * </p>
273      * <p>A negative number means that there is no limit.</p>
274      * 
275      * @return the maximum number of active connections
276      */
277     public synchronized int getMaxActive() {
278         return this.maxActive;
279     }
280 
281     /**
282      * Sets the maximum number of active connections that can be
283      * allocated at the same time. Use a negative value for no limit.
284      * 
285      * @param maxActive the new value for maxActive
286      * @see #getMaxActive()
287      */
288     public synchronized void setMaxActive(int maxActive) {
289         this.maxActive = maxActive;
290         if (connectionPool != null) {
291             connectionPool.setMaxActive(maxActive);
292         }
293     }
294 
295     /**
296      * The maximum number of connections that can remain idle in the
297      * pool, without extra ones being destroyed, or negative for no limit.
298      * If maxIdle is set too low on heavily loaded systems it is possible you
299      * will see connections being closed and almost immediately new connections
300      * being opened. This is a result of the active threads momentarily closing
301      * connections faster than they are opening them, causing the number of idle
302      * connections to rise above maxIdle. The best value for maxIdle for heavily
303      * loaded system will vary but the default is a good starting point.
304      */
305     protected int maxIdle = GenericObjectPool.DEFAULT_MAX_IDLE;
306 
307     /**
308      * <p>Returns the maximum number of connections that can remain idle in the
309      * pool. Excess idle connections are destroyed on return to the pool.
310      * </p>
311      * <p>A negative value indicates that there is no limit</p>
312      * 
313      * @return the maximum number of idle connections
314      */
315     public synchronized int getMaxIdle() {
316         return this.maxIdle;
317     }
318 
319     /**
320      * Sets the maximum number of connections that can remain idle in the
321      * pool. Excess idle connections are destroyed on return to the pool.
322      * 
323      * @see #getMaxIdle()
324      * @param maxIdle the new value for maxIdle
325      */
326     public synchronized void setMaxIdle(int maxIdle) {
327         this.maxIdle = maxIdle;
328         if (connectionPool != null) {
329             connectionPool.setMaxIdle(maxIdle);
330         }
331     }
332 
333     /**
334      * The minimum number of active connections that can remain idle in the
335      * pool, without extra ones being created when the evictor runs, or 0 to create none. 
336      * The pool attempts to ensure that minIdle connections are available when the idle object evictor
337      * runs. The value of this property has no effect unless {@link #timeBetweenEvictionRunsMillis}
338      * has a positive value.
339      */
340     protected int minIdle = GenericObjectPool.DEFAULT_MIN_IDLE;
341 
342     /**
343      * Returns the minimum number of idle connections in the pool. The pool attempts
344      * to ensure that minIdle connections are available when the idle object evictor
345      * runs. The value of this property has no effect unless {@link #timeBetweenEvictionRunsMillis}
346      * has a positive value.
347      * 
348      * @return the minimum number of idle connections
349      * @see GenericObjectPool#getMinIdle()
350      */
351     public synchronized int getMinIdle() {
352         return this.minIdle;
353     }
354 
355     /**
356      * Sets the minimum number of idle connections in the pool. The pool attempts
357      * to ensure that minIdle connections are available when the idle object evictor
358      * runs. The value of this property has no effect unless {@link #timeBetweenEvictionRunsMillis}
359      * has a positive value.
360      * 
361      * @param minIdle the new value for minIdle
362      * @see GenericObjectPool#setMinIdle(int)
363      */
364     public synchronized void setMinIdle(int minIdle) {
365        this.minIdle = minIdle;
366        if (connectionPool != null) {
367            connectionPool.setMinIdle(minIdle);
368        }
369     }
370 
371     /**
372      * The initial number of connections that are created when the pool
373      * is started.
374      * 
375      * @since 1.2
376      */
377     protected int initialSize = 0;
378     
379     /**
380      * Returns the initial size of the connection pool.
381      * 
382      * @return the number of connections created when the pool is initialized
383      */
384     public synchronized int getInitialSize() {
385         return this.initialSize;
386     }
387     
388     /**
389      * <p>Sets the initial size of the connection pool.</p>
390      * <p>
391      * Note: this method currently has no effect once the pool has been
392      * initialized.  The pool is initialized the first time one of the
393      * following methods is invoked: <code>getConnection, setLogwriter,
394      * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
395      * 
396      * @param initialSize the number of connections created when the pool
397      * is initialized
398      */
399     public synchronized void setInitialSize(int initialSize) {
400         this.initialSize = initialSize;
401         this.restartNeeded = true;
402     }
403 
404     /**
405      * The maximum number of milliseconds that the pool will wait (when there
406      * are no available connections) for a connection to be returned before
407      * throwing an exception, or <= 0 to wait indefinitely.
408      */
409     protected long maxWait = GenericObjectPool.DEFAULT_MAX_WAIT;
410 
411     /**
412      * <p>Returns the maximum number of milliseconds that the pool will wait
413      * for a connection to be returned before throwing an exception.
414      * </p>
415      * <p>A value less than or equal to zero means the pool is set to wait
416      * indefinitely.</p>
417      * 
418      * @return the maxWait property value
419      */
420     public synchronized long getMaxWait() {
421         return this.maxWait;
422     }
423 
424     /**
425      * <p>Sets the maxWait property.
426      * </p>
427      * <p>Use -1 to make the pool wait indefinitely.
428      * </p>
429      * 
430      * @param maxWait the new value for maxWait
431      * @see #getMaxWait()
432      */
433     public synchronized void setMaxWait(long maxWait) {
434         this.maxWait = maxWait;
435         if (connectionPool != null) {
436             connectionPool.setMaxWait(maxWait);
437         }
438     }
439 
440     /**
441      * Prepared statement pooling for this pool. When this property is set to <code>true</code>
442      * both PreparedStatements and CallableStatements are pooled.
443      */
444     protected boolean poolPreparedStatements = false;
445     
446     /**
447      * Returns true if we are pooling statements.
448      * 
449      * @return true if prepared and callable statements are pooled
450      */
451     public synchronized boolean isPoolPreparedStatements() {
452         return this.poolPreparedStatements;
453     }
454 
455     /**
456      * <p>Sets whether to pool statements or not.</p>
457      * <p>
458      * Note: this method currently has no effect once the pool has been
459      * initialized.  The pool is initialized the first time one of the
460      * following methods is invoked: <code>getConnection, setLogwriter,
461      * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
462      * 
463      * @param poolingStatements pooling on or off
464      */
465     public synchronized void setPoolPreparedStatements(boolean poolingStatements) {
466         this.poolPreparedStatements = poolingStatements;
467         this.restartNeeded = true;
468     }
469 
470     /**
471      * <p>The maximum number of open statements that can be allocated from
472      * the statement pool at the same time, or non-positive for no limit.  Since 
473      * a connection usually only uses one or two statements at a time, this is
474      * mostly used to help detect resource leaks.</p>
475      * 
476      * <p>Note: As of version 1.3, CallableStatements (those produced by {@link Connection#prepareCall})
477      * are pooled along with PreparedStatements (produced by {@link Connection#prepareStatement})
478      * and <code>maxOpenPreparedStatements</code> limits the total number of prepared or callable statements
479      * that may be in use at a given time.</p>
480      */
481     protected int maxOpenPreparedStatements = GenericKeyedObjectPool.DEFAULT_MAX_TOTAL;
482 
483     /**
484      * Gets the value of the {@link #maxOpenPreparedStatements} property.
485      * 
486      * @return the maximum number of open statements
487      * @see #maxOpenPreparedStatements
488      */
489     public synchronized int getMaxOpenPreparedStatements() {
490         return this.maxOpenPreparedStatements;
491     }
492 
493     /** 
494      * <p>Sets the value of the {@link #maxOpenPreparedStatements}
495      * property.</p>
496      * <p>
497      * Note: this method currently has no effect once the pool has been
498      * initialized.  The pool is initialized the first time one of the
499      * following methods is invoked: <code>getConnection, setLogwriter,
500      * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
501      * 
502      * @param maxOpenStatements the new maximum number of prepared statements
503      * @see #maxOpenPreparedStatements
504      */
505     public synchronized void setMaxOpenPreparedStatements(int maxOpenStatements) {
506         this.maxOpenPreparedStatements = maxOpenStatements;
507         this.restartNeeded = true;
508     }
509 
510     /**
511      * The indication of whether objects will be validated before being
512      * borrowed from the pool.  If the object fails to validate, it will be
513      * dropped from the pool, and we will attempt to borrow another.
514      */
515     protected boolean testOnBorrow = true;
516 
517     /**
518      * Returns the {@link #testOnBorrow} property.
519      * 
520      * @return true if objects are validated before being borrowed from the
521      * pool
522      * 
523      * @see #testOnBorrow
524      */
525     public synchronized boolean getTestOnBorrow() {
526         return this.testOnBorrow;
527     }
528 
529     /**
530      * Sets the {@link #testOnBorrow} property. This property determines
531      * whether or not the pool will validate objects before they are borrowed
532      * from the pool. For a <code>true</code> value to have any effect, the 
533      * <code>validationQuery</code> property must be set to a non-null string.
534      * 
535      * @param testOnBorrow new value for testOnBorrow property
536      */
537     public synchronized void setTestOnBorrow(boolean testOnBorrow) {
538         this.testOnBorrow = testOnBorrow;
539         if (connectionPool != null) {
540             connectionPool.setTestOnBorrow(testOnBorrow);
541         }
542     }
543 
544     /**
545      * The indication of whether objects will be validated before being
546      * returned to the pool.
547      */
548     protected boolean testOnReturn = false;
549 
550     /**
551      * Returns the value of the {@link #testOnReturn} property.
552      * 
553      * @return true if objects are validated before being returned to the
554      * pool
555      * @see #testOnReturn
556      */
557     public synchronized boolean getTestOnReturn() {
558         return this.testOnReturn;
559     }
560 
561     /**
562      * Sets the <code>testOnReturn</code> property. This property determines
563      * whether or not the pool will validate objects before they are returned
564      * to the pool. For a <code>true</code> value to have any effect, the 
565      * <code>validationQuery</code> property must be set to a non-null string.
566      * 
567      * @param testOnReturn new value for testOnReturn property
568      */
569     public synchronized void setTestOnReturn(boolean testOnReturn) {
570         this.testOnReturn = testOnReturn;
571         if (connectionPool != null) {
572             connectionPool.setTestOnReturn(testOnReturn);
573         }
574     }
575 
576     /**
577      * The number of milliseconds to sleep between runs of the idle object
578      * evictor thread.  When non-positive, no idle object evictor thread will
579      * be run.
580      */
581     protected long timeBetweenEvictionRunsMillis =
582         GenericObjectPool.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
583         
584     /**
585      * Returns the value of the {@link #timeBetweenEvictionRunsMillis}
586      * property.
587      * 
588      * @return the time (in miliseconds) between evictor runs
589      * @see #timeBetweenEvictionRunsMillis
590      */
591     public synchronized long getTimeBetweenEvictionRunsMillis() {
592         return this.timeBetweenEvictionRunsMillis;
593     }
594 
595     /**
596      * Sets the {@link #timeBetweenEvictionRunsMillis} property.
597      * 
598      * @param timeBetweenEvictionRunsMillis the new time between evictor runs
599      * @see #timeBetweenEvictionRunsMillis
600      */
601     public synchronized void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) {
602         this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
603         if (connectionPool != null) {
604             connectionPool.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
605         }
606     }
607 
608     /**
609      * The number of objects to examine during each run of the idle object
610      * evictor thread (if any).
611      */
612     protected int numTestsPerEvictionRun =
613         GenericObjectPool.DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
614 
615     /**
616      * Returns the value of the {@link #numTestsPerEvictionRun} property.
617      * 
618      * @return the number of objects to examine during idle object evictor
619      * runs
620      * @see #numTestsPerEvictionRun
621      */
622     public synchronized int getNumTestsPerEvictionRun() {
623         return this.numTestsPerEvictionRun;
624     }
625 
626     /**
627      * Sets the value of the {@link #numTestsPerEvictionRun} property.
628      * 
629      * @param numTestsPerEvictionRun the new {@link #numTestsPerEvictionRun} 
630      * value
631      * @see #numTestsPerEvictionRun
632      */
633     public synchronized void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) {
634         this.numTestsPerEvictionRun = numTestsPerEvictionRun;
635         if (connectionPool != null) {
636             connectionPool.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
637         }
638     }
639 
640     /**
641      * The minimum amount of time an object may sit idle in the pool before it
642      * is eligible for eviction by the idle object evictor (if any).
643      */
644     protected long minEvictableIdleTimeMillis =
645         GenericObjectPool.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
646 
647     /**
648      * Returns the {@link #minEvictableIdleTimeMillis} property.
649      * 
650      * @return the value of the {@link #minEvictableIdleTimeMillis} property
651      * @see #minEvictableIdleTimeMillis
652      */
653     public synchronized long getMinEvictableIdleTimeMillis() {
654         return this.minEvictableIdleTimeMillis;
655     }
656 
657     /**
658      * Sets the {@link #minEvictableIdleTimeMillis} property.
659      * 
660      * @param minEvictableIdleTimeMillis the minimum amount of time an object
661      * may sit idle in the pool 
662      * @see #minEvictableIdleTimeMillis
663      */
664     public synchronized void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) {
665         this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
666         if (connectionPool != null) {
667             connectionPool.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
668         }
669     }
670 
671     /**
672      * The indication of whether objects will be validated by the idle object
673      * evictor (if any).  If an object fails to validate, it will be dropped
674      * from the pool.
675      */
676     protected boolean testWhileIdle = false;
677 
678     /**
679      * Returns the value of the {@link #testWhileIdle} property.
680      * 
681      * @return true if objects examined by the idle object evictor are
682      * validated
683      * @see #testWhileIdle
684      */
685     public synchronized boolean getTestWhileIdle() {
686         return this.testWhileIdle;
687     }
688 
689     /**
690      * Sets the <code>testWhileIdle</code> property. This property determines
691      * whether or not the idle object evictor will validate connections.  For a
692      * <code>true</code> value to have any effect, the 
693      * <code>validationQuery</code> property must be set to a non-null string.
694      * 
695      * @param testWhileIdle new value for testWhileIdle property
696      */
697     public synchronized void setTestWhileIdle(boolean testWhileIdle) {
698         this.testWhileIdle = testWhileIdle;
699         if (connectionPool != null) {
700             connectionPool.setTestWhileIdle(testWhileIdle);
701         }
702     }
703 
704     /**
705      * [Read Only] The current number of active connections that have been
706      * allocated from this data source.
707      * 
708      * @return the current number of active connections
709      */
710     public synchronized int getNumActive() {
711         if (connectionPool != null) {
712             return connectionPool.getNumActive();
713         } else {
714             return 0;
715         }
716     }
717 
718 
719     /**
720      * [Read Only] The current number of idle connections that are waiting
721      * to be allocated from this data source.
722      * 
723      * @return the current number of idle connections
724      */
725     public synchronized int getNumIdle() {
726         if (connectionPool != null) {
727             return connectionPool.getNumIdle();
728         } else {
729             return 0;
730         }
731     }
732 
733     /**
734      * The connection password to be passed to our JDBC driver to establish
735      * a connection.
736      */
737     protected volatile String password = null;
738 
739     /**
740      * Returns the password passed to the JDBC driver to establish connections.
741      * 
742      * @return the connection password
743      */
744     public String getPassword() {
745         return this.password;
746     }
747 
748     /** 
749      * <p>Sets the {@link #password}.</p>
750      * <p>
751      * Note: this method currently has no effect once the pool has been
752      * initialized.  The pool is initialized the first time one of the
753      * following methods is invoked: <code>getConnection, setLogwriter,
754      * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
755      * 
756      * @param password new value for the password
757      */
758     public void setPassword(String password) {
759         this.password = password;
760         this.restartNeeded = true;
761     }
762 
763     /**
764      * The connection URL to be passed to our JDBC driver to establish
765      * a connection.
766      */
767     protected String url = null;
768 
769     /**
770      * Returns the JDBC connection {@link #url} property.
771      * 
772      * @return the {@link #url} passed to the JDBC driver to establish
773      * connections
774      */
775     public synchronized String getUrl() {
776         return this.url;
777     }
778 
779     /** 
780      * <p>Sets the {@link #url}.</p>
781      * <p>
782      * Note: this method currently has no effect once the pool has been
783      * initialized.  The pool is initialized the first time one of the
784      * following methods is invoked: <code>getConnection, setLogwriter,
785      * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
786      * 
787      * @param url the new value for the JDBC connection url
788      */
789     public synchronized void setUrl(String url) {
790         this.url = url;
791         this.restartNeeded = true;
792     }
793 
794     /**
795      * The connection username to be passed to our JDBC driver to
796      * establish a connection.
797      */
798     protected String username = null;
799 
800     /**
801      * Returns the JDBC connection {@link #username} property.
802      * 
803      * @return the {@link #username} passed to the JDBC driver to establish
804      * connections
805      */
806     public String getUsername() {
807         return this.username;
808     }
809 
810     /** 
811      * <p>Sets the {@link #username}.</p>
812      * <p>
813      * Note: this method currently has no effect once the pool has been
814      * initialized.  The pool is initialized the first time one of the
815      * following methods is invoked: <code>getConnection, setLogwriter,
816      * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
817      * 
818      * @param username the new value for the JDBC connection username
819      */
820     public void setUsername(String username) {
821         this.username = username;
822         this.restartNeeded = true;
823     }
824 
825     /**
826      * The SQL query that will be used to validate connections from this pool
827      * before returning them to the caller.  If specified, this query
828      * <strong>MUST</strong> be an SQL SELECT statement that returns at least
829      * one row.
830      */
831     protected volatile String validationQuery = null;
832 
833     /**
834      * Returns the validation query used to validate connections before
835      * returning them.
836      * 
837      * @return the SQL validation query
838      * @see #validationQuery
839      */
840     public String getValidationQuery() {
841         return this.validationQuery;
842     }
843 
844     /** 
845      * <p>Sets the {@link #validationQuery}.</p>
846      * <p>
847      * Note: this method currently has no effect once the pool has been
848      * initialized.  The pool is initialized the first time one of the
849      * following methods is invoked: <code>getConnection, setLogwriter,
850      * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
851      * 
852      * @param validationQuery the new value for the validation query
853      */
854     public void setValidationQuery(String validationQuery) {
855         if ((validationQuery != null) && (validationQuery.trim().length() > 0)) {
856             this.validationQuery = validationQuery;
857         } else {
858             this.validationQuery = null;
859         }
860         this.restartNeeded = true;
861     }
862     
863     /**
864      * Timeout in seconds before connection validation queries fail. 
865      * 
866      * @since 1.3
867      */
868     protected volatile int validationQueryTimeout = -1;
869     
870     /**
871      * Returns the validation query timeout.
872      * 
873      * @return the timeout in seconds before connection validation queries fail.
874      * @since 1.3
875      */
876     public int getValidationQueryTimeout() {
877         return validationQueryTimeout;
878     }
879     
880     /**
881      * Sets the validation query timeout, the amount of time, in seconds, that
882      * connection validation will wait for a response from the database when
883      * executing a validation query.  Use a value less than or equal to 0 for
884      * no timeout.
885      * <p>
886      * Note: this method currently has no effect once the pool has been
887      * initialized.  The pool is initialized the first time one of the
888      * following methods is invoked: <code>getConnection, setLogwriter,
889      * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
890      * 
891      * @param timeout new validation query timeout value in seconds
892      * @since 1.3
893      */
894     public void setValidationQueryTimeout(int timeout) {
895         this.validationQueryTimeout = timeout;
896         restartNeeded = true;
897     }
898     
899     /**
900      * These SQL statements run once after a Connection is created.
901      * <p>
902      * This property can be used for example to run ALTER SESSION SET
903      * NLS_SORT=XCYECH in an Oracle Database only once after connection
904      * creation.
905      * </p>
906      * 
907      * @since 1.3
908      */
909     protected volatile List connectionInitSqls;
910 
911     /**
912      * Returns the list of SQL statements executed when a physical connection
913      * is first created. Returns an empty list if there are no initialization
914      * statements configured.
915      * 
916      * @return initialization SQL statements
917      * @since 1.3
918      */
919     public Collection getConnectionInitSqls() {
920         Collection result = connectionInitSqls; 
921         if (result == null) {
922             return Collections.EMPTY_LIST;
923         }
924         return result;
925     }
926 
927     /**
928      * Sets the list of SQL statements to be executed when a physical
929      * connection is first created.
930      * <p>
931      * Note: this method currently has no effect once the pool has been
932      * initialized.  The pool is initialized the first time one of the
933      * following methods is invoked: <code>getConnection, setLogwriter,
934      * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
935      * 
936      * @param connectionInitSqls Collection of SQL statements to execute
937      * on connection creation
938      */
939     public void setConnectionInitSqls(Collection connectionInitSqls) {
940         if ((connectionInitSqls != null) && (connectionInitSqls.size() > 0)) {
941             ArrayList newVal = null;
942             for (Iterator iterator = connectionInitSqls.iterator();
943             iterator.hasNext();) {
944                 Object o = iterator.next();
945                 if (o != null) {
946                     String s = o.toString();
947                     if (s.trim().length() > 0) {
948                         if (newVal == null) {
949                             newVal = new ArrayList();
950                         }
951                         newVal.add(s);
952                     }
953                 }
954             }
955             this.connectionInitSqls = newVal;
956         } else {
957             this.connectionInitSqls = null;
958         }
959         this.restartNeeded = true;
960     }
961 
962 
963     /** 
964      * Controls access to the underlying connection.
965      */
966     private boolean accessToUnderlyingConnectionAllowed = false; 
967 
968     /**
969      * Returns the value of the accessToUnderlyingConnectionAllowed property.
970      * 
971      * @return true if access to the underlying connection is allowed, false
972      * otherwise.
973      */
974     public synchronized boolean isAccessToUnderlyingConnectionAllowed() {
975         return this.accessToUnderlyingConnectionAllowed;
976     }
977 
978     /**
979      * <p>Sets the value of the accessToUnderlyingConnectionAllowed property.
980      * It controls if the PoolGuard allows access to the underlying connection.
981      * (Default: false)</p>
982      * <p>
983      * Note: this method currently has no effect once the pool has been
984      * initialized.  The pool is initialized the first time one of the
985      * following methods is invoked: <code>getConnection, setLogwriter,
986      * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
987      * 
988      * @param allow Access to the underlying connection is granted when true.
989      */
990     public synchronized void setAccessToUnderlyingConnectionAllowed(boolean allow) {
991         this.accessToUnderlyingConnectionAllowed = allow;
992         this.restartNeeded = true;
993     }
994 
995     // ----------------------------------------------------- Instance Variables
996 
997     // TODO: review & make isRestartNeeded() public, restartNeeded protected
998 
999     /**
1000      * A property setter has been invoked that will require the connection
1001      * pool to be re-initialized. Currently, restart is not triggered, so
1002      * this property has no effect.
1003      */
1004     private volatile boolean restartNeeded = false;
1005     
1006     /**
1007      * Returns whether or not a restart is needed. 
1008      *  
1009      * Note: restart is not currently triggered by property changes.
1010      * 
1011      * @return true if a restart is needed
1012      */
1013     private boolean isRestartNeeded() {
1014         return restartNeeded;
1015     }
1016 
1017     /**
1018      * The object pool that internally manages our connections.
1019      */
1020     protected volatile GenericObjectPool connectionPool = null;
1021     
1022     /**
1023      * The connection properties that will be sent to our JDBC driver when
1024      * establishing new connections.  <strong>NOTE</strong> - The "user" and
1025      * "password" properties will be passed explicitly, so they do not need
1026      * to be included here.
1027      */
1028     protected Properties connectionProperties = new Properties();
1029 
1030     /**
1031      * The data source we will use to manage connections.  This object should
1032      * be acquired <strong>ONLY</strong> by calls to the
1033      * <code>createDataSource()</code> method.
1034      */
1035     protected volatile DataSource dataSource = null;
1036 
1037     /**
1038      * The PrintWriter to which log messages should be directed.
1039      */
1040     protected PrintWriter logWriter = new PrintWriter(System.out);
1041 
1042 
1043     // ----------------------------------------------------- DataSource Methods
1044 
1045 
1046     /**
1047      * Create (if necessary) and return a connection to the database.
1048      *
1049      * @throws SQLException if a database access error occurs
1050      * @return a database connection
1051      */
1052     public Connection getConnection() throws SQLException {
1053         return createDataSource().getConnection();
1054     }
1055 
1056 
1057     /**
1058      * <strong>BasicDataSource does NOT support this method. </strong>
1059      *
1060      * @param user Database user on whose behalf the Connection
1061      *   is being made
1062      * @param pass The database user's password
1063      *
1064      * @throws UnsupportedOperationException
1065      * @throws SQLException if a database access error occurs
1066      * @return nothing - always throws UnsupportedOperationException
1067      */
1068     public Connection getConnection(String user, String pass) throws SQLException {
1069         // This method isn't supported by the PoolingDataSource returned by
1070         // the createDataSource
1071         throw new UnsupportedOperationException("Not supported by BasicDataSource");
1072         // return createDataSource().getConnection(username, password);
1073     }
1074 
1075 
1076     /**
1077      * <strong>BasicDataSource does NOT support this method. </strong>
1078      *
1079      * <p>Returns the login timeout (in seconds) for connecting to the database.
1080      * </p>
1081      * <p>Calls {@link #createDataSource()}, so has the side effect
1082      * of initializing the connection pool.</p>
1083      *
1084      * @throws SQLException if a database access error occurs
1085      * @throws UnsupportedOperationException If the DataSource implementation
1086      *   does not support the login timeout feature.
1087      * @return login timeout in seconds
1088      */
1089     public int getLoginTimeout() throws SQLException {
1090         // This method isn't supported by the PoolingDataSource returned by
1091         // the createDataSource
1092         throw new UnsupportedOperationException("Not supported by BasicDataSource");
1093         //return createDataSource().getLoginTimeout();
1094     }
1095 
1096 
1097     /**
1098      * <p>Returns the log writer being used by this data source.</p>
1099      * <p>
1100      * Calls {@link #createDataSource()}, so has the side effect
1101      * of initializing the connection pool.</p>
1102      *
1103      * @throws SQLException if a database access error occurs
1104      * @return log writer in use
1105      */
1106     public PrintWriter getLogWriter() throws SQLException {
1107         return createDataSource().getLogWriter();
1108     }
1109 
1110 
1111     /**
1112      * <strong>BasicDataSource does NOT support this method. </strong>
1113      *
1114      * <p>Set the login timeout (in seconds) for connecting to the
1115      * database.</p>
1116      * <p>
1117      * Calls {@link #createDataSource()}, so has the side effect
1118      * of initializing the connection pool.</p>
1119      *
1120      * @param loginTimeout The new login timeout, or zero for no timeout
1121      * @throws UnsupportedOperationException If the DataSource implementation
1122      *   does not support the login timeout feature.
1123      * @throws SQLException if a database access error occurs
1124      */
1125     public void setLoginTimeout(int loginTimeout) throws SQLException {
1126         // This method isn't supported by the PoolingDataSource returned by
1127         // the createDataSource
1128         throw new UnsupportedOperationException("Not supported by BasicDataSource");
1129         //createDataSource().setLoginTimeout(loginTimeout);
1130     }
1131 
1132 
1133     /**
1134      * <p>Sets the log writer being used by this data source.</p>
1135      * <p>
1136      * Calls {@link #createDataSource()}, so has the side effect
1137      * of initializing the connection pool.</p>
1138      *
1139      * @param logWriter The new log writer
1140      * @throws SQLException if a database access error occurs
1141      */
1142     public void setLogWriter(PrintWriter logWriter) throws SQLException {
1143         createDataSource().setLogWriter(logWriter);
1144         this.logWriter = logWriter;
1145     }
1146 
1147     private AbandonedConfig abandonedConfig;
1148 
1149     /**                       
1150      * Flag to remove abandoned connections if they exceed the
1151      * removeAbandonedTimout.
1152      *
1153      * Set to true or false, default false.
1154      * If set to true a connection is considered abandoned and eligible
1155      * for removal if it has been idle longer than the removeAbandonedTimeout.
1156      * Setting this to true can recover db connections from poorly written    
1157      * applications which fail to close a connection.
1158      * <p>
1159      * Abandonded connections are identified and removed when 
1160      * {@link #getConnection()} is invoked and the following conditions hold
1161      * <ul><li>{@link #getRemoveAbandoned()} = true </li>
1162      *     <li>{@link #getNumActive()} > {@link #getMaxActive()} - 3 </li>
1163      *     <li>{@link #getNumIdle()} < 2 </li></ul></p>
1164      */                                                                   
1165     public boolean getRemoveAbandoned() {   
1166         if (abandonedConfig != null) {
1167             return abandonedConfig.getRemoveAbandoned();
1168         }
1169         return false;
1170     }                                    
1171                                  
1172     /**
1173      * @param removeAbandoned new removeAbandoned property value
1174      * @see #getRemoveAbandoned()
1175      */
1176     public void setRemoveAbandoned(boolean removeAbandoned) {
1177         if (abandonedConfig == null) {
1178             abandonedConfig = new AbandonedConfig();
1179         }
1180         abandonedConfig.setRemoveAbandoned(removeAbandoned);
1181         this.restartNeeded = true;
1182     }                                                        
1183                                                
1184     /**
1185      * Timeout in seconds before an abandoned connection can be removed.
1186      *
1187      * Defaults to 300 seconds. 
1188      * @return abandoned connection timeout        
1189      */                                                                 
1190     public int getRemoveAbandonedTimeout() { 
1191         if (abandonedConfig != null) {
1192             return abandonedConfig.getRemoveAbandonedTimeout();
1193         }
1194         return 300;
1195     }                                        
1196 
1197     /**
1198      * @param removeAbandonedTimeout new removeAbandonedTimeout value
1199      */               
1200     public void setRemoveAbandonedTimeout(int removeAbandonedTimeout) {
1201         if (abandonedConfig == null) {
1202             abandonedConfig = new AbandonedConfig();
1203         }
1204         abandonedConfig.setRemoveAbandonedTimeout(removeAbandonedTimeout);
1205         this.restartNeeded = true;
1206     }                                                                  
1207                                                              
1208     /**
1209      * <p>Flag to log stack traces for application code which abandoned
1210      * a Statement or Connection.
1211      * </p>
1212      * <p>Defaults to false.                
1213      * </p>                                                            
1214      * <p>Logging of abandoned Statements and Connections adds overhead
1215      * for every Connection open or new Statement because a stack   
1216      * trace has to be generated. </p>
1217      */                                                          
1218     public boolean getLogAbandoned() {   
1219         if (abandonedConfig != null) {
1220             return abandonedConfig.getLogAbandoned();
1221         }
1222         return false;
1223     }                                 
1224 
1225     /**
1226      * @param logAbandoned new logAbandoned property value
1227      */
1228     public void setLogAbandoned(boolean logAbandoned) {
1229         if (abandonedConfig == null) {
1230             abandonedConfig = new AbandonedConfig();
1231         }
1232         abandonedConfig.setLogAbandoned(logAbandoned);
1233         this.restartNeeded = true;
1234     }
1235 
1236     // --------------------------------------------------------- Public Methods
1237 
1238     /**
1239      * Add a custom connection property to the set that will be passed to our
1240      * JDBC driver. This <strong>MUST</strong> be called before the first
1241      * connection is retrieved (along with all the other configuration
1242      * property setters). Calls to this method after the connection pool
1243      * has been initialized have no effect.
1244      *
1245      * @param name Name of the custom connection property
1246      * @param value Value of the custom connection property
1247      */
1248     public void addConnectionProperty(String name, String value) {
1249         connectionProperties.put(name, value);
1250         this.restartNeeded = true;
1251     }
1252 
1253     /**
1254      * Remove a custom connection property.
1255      * 
1256      * @param name Name of the custom connection property to remove
1257      * @see #addConnectionProperty(String, String)
1258      */
1259     public void removeConnectionProperty(String name) {
1260         connectionProperties.remove(name);
1261         this.restartNeeded = true;
1262     }
1263 
1264     /**
1265      * Sets the connection properties passed to driver.connect(...).
1266      *
1267      * Format of the string must be [propertyName=property;]*
1268      *
1269      * NOTE - The "user" and "password" properties will be added
1270      * explicitly, so they do not need to be included here.
1271      *
1272      * @param connectionProperties the connection properties used to
1273      * create new connections
1274      */
1275     public void setConnectionProperties(String connectionProperties) {
1276         if (connectionProperties == null) throw new NullPointerException("connectionProperties is null");
1277 
1278         String[] entries = connectionProperties.split(";");
1279         Properties properties = new Properties();
1280         for (int i = 0; i < entries.length; i++) {
1281             String entry = entries[i];
1282             if (entry.length() > 0) {
1283                 int index = entry.indexOf('=');
1284                 if (index > 0) {
1285                     String name = entry.substring(0, index);
1286                     String value = entry.substring(index + 1);
1287                     properties.setProperty(name, value);
1288                 } else {
1289                     // no value is empty string which is how java.util.Properties works
1290                     properties.setProperty(entry, "");
1291                 }
1292             }
1293         }
1294         this.connectionProperties = properties;
1295         this.restartNeeded = true;
1296     }
1297 
1298     protected boolean closed;
1299 
1300     /**
1301      * <p>Closes and releases all idle connections that are currently stored in the connection pool
1302      * associated with this data source.</p>
1303      *
1304      * <p>Connections that are checked out to clients when this method is invoked are not affected.  
1305      * When client applications subsequently invoke {@link Connection#close()} to return
1306      * these connections to the pool, the underlying JDBC connections are closed.</p>
1307      * 
1308      * <p>Attempts to acquire connections using {@link #getConnection()} after this method has been
1309      * invoked result in SQLExceptions.<p>
1310      * 
1311      * <p>This method is idempotent - i.e., closing an already closed BasicDataSource has no effect
1312      * and does not generate exceptions.</p>
1313      * 
1314      * @throws SQLException if an error occurs closing idle connections
1315      */
1316     public synchronized void close() throws SQLException {
1317         closed = true;
1318         GenericObjectPool oldpool = connectionPool;
1319         connectionPool = null;
1320         dataSource = null;
1321         try {
1322             if (oldpool != null) {
1323                 oldpool.close();
1324             }
1325         } catch(SQLException e) {
1326             throw e;
1327         } catch(RuntimeException e) {
1328             throw e;
1329         } catch(Exception e) {
1330             throw new SQLNestedException("Cannot close connection pool", e);
1331         }
1332     }
1333 
1334     /**
1335      * If true, this data source is closed and no more connections can be retrieved from this datasource.
1336      * @return true, if the data source is closed; false otherwise
1337      */
1338     public synchronized boolean isClosed() {
1339         return closed;
1340     }
1341 
1342     /* JDBC_4_ANT_KEY_BEGIN */
1343     public boolean isWrapperFor(Class<?> iface) throws SQLException {
1344         return false;
1345     }
1346 
1347     public <T> T unwrap(Class<T> iface) throws SQLException {
1348         throw new SQLException("BasicDataSource is not a wrapper.");
1349     }
1350     /* JDBC_4_ANT_KEY_END */
1351 
1352         
1353     // ------------------------------------------------------ Protected Methods
1354 
1355 
1356     /**
1357      * <p>Create (if necessary) and return the internal data source we are
1358      * using to manage our connections.</p>
1359      *
1360      * <p><strong>IMPLEMENTATION NOTE</strong> - It is tempting to use the
1361      * "double checked locking" idiom in an attempt to avoid synchronizing
1362      * on every single call to this method.  However, this idiom fails to
1363      * work correctly in the face of some optimizations that are legal for
1364      * a JVM to perform.</p>
1365      *
1366      * @throws SQLException if the object pool cannot be created.
1367      */
1368     protected synchronized DataSource createDataSource()
1369         throws SQLException {
1370         if (closed) {
1371             throw new SQLException("Data source is closed");
1372         }
1373 
1374         // Return the pool if we have already created it
1375         if (dataSource != null) {
1376             return (dataSource);
1377         }
1378 
1379         // create factory which returns raw physical connections
1380         ConnectionFactory driverConnectionFactory = createConnectionFactory();
1381 
1382         // create a pool for our connections
1383         createConnectionPool();
1384 
1385         // Set up statement pool, if desired
1386         GenericKeyedObjectPoolFactory statementPoolFactory = null;
1387         if (isPoolPreparedStatements()) {
1388             statementPoolFactory = new GenericKeyedObjectPoolFactory(null,
1389                         -1, // unlimited maxActive (per key)
1390                         GenericKeyedObjectPool.WHEN_EXHAUSTED_FAIL,
1391                         0, // maxWait
1392                         1, // maxIdle (per key)
1393                         maxOpenPreparedStatements);
1394         }
1395 
1396         // Set up the poolable connection factory
1397         createPoolableConnectionFactory(driverConnectionFactory, statementPoolFactory, abandonedConfig);
1398 
1399         // Create and return the pooling data source to manage the connections
1400         createDataSourceInstance();
1401         
1402         try {
1403             for (int i = 0 ; i < initialSize ; i++) {
1404                 connectionPool.addObject();
1405             }
1406         } catch (Exception e) {
1407             throw new SQLNestedException("Error preloading the connection pool", e);
1408         }
1409         
1410         return dataSource;
1411     }
1412 
1413     /**
1414      * Creates a JDBC connection factory for this datasource.  This method only
1415      * exists so subclasses can replace the implementation class.
1416      */
1417     protected ConnectionFactory createConnectionFactory() throws SQLException {
1418         // Load the JDBC driver class
1419         Class driverFromCCL = null;
1420         if (driverClassName != null) {
1421             try {
1422                 try {
1423                     if (driverClassLoader == null) {
1424                         Class.forName(driverClassName);
1425                     } else {
1426                         Class.forName(driverClassName, true, driverClassLoader);
1427                     }
1428                 } catch (ClassNotFoundException cnfe) {
1429                     driverFromCCL = Thread.currentThread(
1430                             ).getContextClassLoader().loadClass(
1431                                     driverClassName);
1432                 }
1433             } catch (Throwable t) {
1434                 String message = "Cannot load JDBC driver class '" +
1435                     driverClassName + "'";
1436                 logWriter.println(message);
1437                 t.printStackTrace(logWriter);
1438                 throw new SQLNestedException(message, t);
1439             }
1440         }
1441 
1442         // Create a JDBC driver instance
1443         Driver driver = null;
1444         try {
1445             if (driverFromCCL == null) {
1446                 driver = DriverManager.getDriver(url);
1447             } else {
1448                 // Usage of DriverManager is not possible, as it does not
1449                 // respect the ContextClassLoader
1450                 driver = (Driver) driverFromCCL.newInstance();
1451                 if (!driver.acceptsURL(url)) {
1452                     throw new SQLException("No suitable driver", "08001"); 
1453                 }
1454             }
1455         } catch (Throwable t) {
1456             String message = "Cannot create JDBC driver of class '" +
1457                 (driverClassName != null ? driverClassName : "") +
1458                 "' for connect URL '" + url + "'";
1459             logWriter.println(message);
1460             t.printStackTrace(logWriter);
1461             throw new SQLNestedException(message, t);
1462         }
1463 
1464         // Can't test without a validationQuery
1465         if (validationQuery == null) {
1466             setTestOnBorrow(false);
1467             setTestOnReturn(false);
1468             setTestWhileIdle(false);
1469         }
1470 
1471         // Set up the driver connection factory we will use
1472         String user = username;
1473         if (user != null) {
1474             connectionProperties.put("user", user);
1475         } else {
1476             log("DBCP DataSource configured without a 'username'");
1477         }
1478 
1479         String pwd = password;
1480         if (pwd != null) {
1481             connectionProperties.put("password", pwd);
1482         } else {
1483             log("DBCP DataSource configured without a 'password'");
1484         }
1485 
1486         ConnectionFactory driverConnectionFactory = new DriverConnectionFactory(driver, url, connectionProperties);
1487         return driverConnectionFactory;
1488     }
1489 
1490     /**
1491      * Creates a connection pool for this datasource.  This method only exists
1492      * so subclasses can replace the implementation class.
1493      */
1494     protected void createConnectionPool() {
1495         // Create an object pool to contain our active connections
1496         GenericObjectPool gop;
1497         if ((abandonedConfig != null) && (abandonedConfig.getRemoveAbandoned())) {
1498             gop = new AbandonedObjectPool(null,abandonedConfig);
1499         }
1500         else {
1501             gop = new GenericObjectPool();
1502         }
1503         gop.setMaxActive(maxActive);
1504         gop.setMaxIdle(maxIdle);
1505         gop.setMinIdle(minIdle);
1506         gop.setMaxWait(maxWait);
1507         gop.setTestOnBorrow(testOnBorrow);
1508         gop.setTestOnReturn(testOnReturn);
1509         gop.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
1510         gop.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
1511         gop.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
1512         gop.setTestWhileIdle(testWhileIdle);
1513         connectionPool = gop;
1514     }
1515 
1516     /**
1517      * Creates the actual data source instance.  This method only exists so
1518      * subclasses can replace the implementation class.
1519      * 
1520      * @throws SQLException if unable to create a datasource instance
1521      */
1522     protected void createDataSourceInstance() throws SQLException {
1523         PoolingDataSource pds = new PoolingDataSource(connectionPool);
1524         pds.setAccessToUnderlyingConnectionAllowed(isAccessToUnderlyingConnectionAllowed());
1525         pds.setLogWriter(logWriter);
1526         dataSource = pds;
1527     }
1528 
1529     /**
1530      * Creates the PoolableConnectionFactory and attaches it to the connection pool.  This method only exists
1531      * so subclasses can replace the default implementation.
1532      * 
1533      * @param driverConnectionFactory JDBC connection factory
1534      * @param statementPoolFactory statement pool factory (null if statement pooling is turned off)
1535      * @param configuration abandoned connection tracking configuration (null if no tracking)
1536      * @throws SQLException if an error occurs creating the PoolableConnectionFactory
1537      */
1538     protected void createPoolableConnectionFactory(ConnectionFactory driverConnectionFactory,
1539             KeyedObjectPoolFactory statementPoolFactory, AbandonedConfig configuration) throws SQLException {
1540         PoolableConnectionFactory connectionFactory = null;
1541         try {
1542             connectionFactory =
1543                 new PoolableConnectionFactory(driverConnectionFactory,
1544                                               connectionPool,
1545                                               statementPoolFactory,
1546                                               validationQuery,
1547                                               validationQueryTimeout,
1548                                               connectionInitSqls,
1549                                               defaultReadOnly,
1550                                               defaultAutoCommit,
1551                                               defaultTransactionIsolation,
1552                                               defaultCatalog,
1553                                               configuration);
1554             validateConnectionFactory(connectionFactory);
1555         } catch (RuntimeException e) {
1556             throw e;
1557         } catch (Exception e) {
1558             throw new SQLNestedException("Cannot create PoolableConnectionFactory (" + e.getMessage() + ")", e);
1559         }
1560     }
1561 
1562     protected static void validateConnectionFactory(PoolableConnectionFactory connectionFactory) throws Exception {
1563         Connection conn = null;
1564         try {
1565             conn = (Connection) connectionFactory.makeObject();
1566             connectionFactory.activateObject(conn);
1567             connectionFactory.validateConnection(conn);
1568             connectionFactory.passivateObject(conn);
1569         }
1570         finally {
1571             connectionFactory.destroyObject(conn);
1572         }
1573     }
1574 
1575     /**
1576      * Not used currently
1577      */
1578     private void restart() {
1579         try {
1580             close();
1581         } catch (SQLException e) {
1582             log("Could not restart DataSource, cause: " + e.getMessage());
1583         }
1584     }
1585 
1586     protected void log(String message) {
1587         if (logWriter != null) {
1588             logWriter.println(message);
1589         }
1590     }
1591 }