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     */
017    
018    package org.apache.commons.dbcp;
019    
020    import java.io.PrintWriter;
021    import java.util.Properties;
022    import java.util.Collection;
023    import java.util.List;
024    import java.util.ArrayList;
025    import java.util.Iterator;
026    import java.util.Collections;
027    import java.sql.Connection;
028    import java.sql.Driver;
029    import java.sql.DriverManager;
030    import java.sql.SQLException;
031    import javax.sql.DataSource;
032    
033    import org.apache.commons.pool.KeyedObjectPoolFactory;
034    import org.apache.commons.pool.impl.GenericKeyedObjectPool;
035    import org.apache.commons.pool.impl.GenericKeyedObjectPoolFactory;
036    import org.apache.commons.pool.impl.GenericObjectPool;
037    
038    
039    /**
040     * <p>Basic implementation of <code>javax.sql.DataSource</code> that is
041     * configured via JavaBeans properties.  This is not the only way to
042     * combine the <em>commons-dbcp</em> and <em>commons-pool</em> packages,
043     * but provides a "one stop shopping" solution for basic requirements.</p>
044     * 
045     * <p>Users extending this class should take care to use appropriate accessors
046     * rather than accessing protected fields directly to ensure thread-safety.</p>
047     *
048     * @author Glenn L. Nielsen
049     * @author Craig R. McClanahan
050     * @author Dirk Verbeeck
051     * @version $Revision: 1023401 $ $Date: 2010-10-16 21:54:24 -0400 (Sat, 16 Oct 2010) $
052     */
053    public class BasicDataSource implements DataSource {
054        
055        static {
056            // Attempt to prevent deadlocks - see DBCP - 272
057            DriverManager.getDrivers();
058        }
059    
060        // ------------------------------------------------------------- Properties
061    
062        /**
063         * The default auto-commit state of connections created by this pool.
064         */
065        protected volatile boolean defaultAutoCommit = true;
066    
067        /**
068         * Returns the default auto-commit property.
069         * 
070         * @return true if default auto-commit is enabled
071         */
072        public boolean getDefaultAutoCommit() {
073            return this.defaultAutoCommit;
074        }
075    
076        /**
077         * <p>Sets default auto-commit state of connections returned by this
078         * datasource.</p>
079         * <p>
080         * Note: this method currently has no effect once the pool has been
081         * initialized.  The pool is initialized the first time one of the
082         * following methods is invoked: <code>getConnection, setLogwriter,
083         * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
084         * 
085         * @param defaultAutoCommit default auto-commit value
086         */
087        public void setDefaultAutoCommit(boolean defaultAutoCommit) {
088            this.defaultAutoCommit = defaultAutoCommit;
089            this.restartNeeded = true;
090        }
091    
092    
093        /**
094         * The default read-only state of connections created by this pool.
095         */
096        protected transient Boolean defaultReadOnly = null;
097    
098        /**
099         * 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    }