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: 892307 $ $Date: 2013-12-31 23:27:28 +0000 (Tue, 31 Dec 2013) $
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 released, 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.
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.
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, or 0 to create none.
336         */
337        protected int minIdle = GenericObjectPool.DEFAULT_MIN_IDLE;
338    
339        /**
340         * Returns the minimum number of idle connections in the pool
341         * 
342         * @return the minimum number of idle connections
343         * @see GenericObjectPool#getMinIdle()
344         */
345        public synchronized int getMinIdle() {
346            return this.minIdle;
347        }
348    
349        /**
350         * Sets the minimum number of idle connections in the pool.
351         * 
352         * @param minIdle the new value for minIdle
353         * @see GenericObjectPool#setMinIdle(int)
354         */
355        public synchronized void setMinIdle(int minIdle) {
356           this.minIdle = minIdle;
357           if (connectionPool != null) {
358               connectionPool.setMinIdle(minIdle);
359           }
360        }
361    
362        /**
363         * The initial number of connections that are created when the pool
364         * is started.
365         * 
366         * @since 1.2
367         */
368        protected int initialSize = 0;
369        
370        /**
371         * Returns the initial size of the connection pool.
372         * 
373         * @return the number of connections created when the pool is initialized
374         */
375        public synchronized int getInitialSize() {
376            return this.initialSize;
377        }
378        
379        /**
380         * <p>Sets the initial size of the connection pool.</p>
381         * <p>
382         * Note: this method currently has no effect once the pool has been
383         * initialized.  The pool is initialized the first time one of the
384         * following methods is invoked: <code>getConnection, setLogwriter,
385         * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
386         * 
387         * @param initialSize the number of connections created when the pool
388         * is initialized
389         */
390        public synchronized void setInitialSize(int initialSize) {
391            this.initialSize = initialSize;
392            this.restartNeeded = true;
393        }
394    
395        /**
396         * The maximum number of milliseconds that the pool will wait (when there
397         * are no available connections) for a connection to be returned before
398         * throwing an exception, or <= 0 to wait indefinitely.
399         */
400        protected long maxWait = GenericObjectPool.DEFAULT_MAX_WAIT;
401    
402        /**
403         * <p>Returns the maximum number of milliseconds that the pool will wait
404         * for a connection to be returned before throwing an exception.
405         * </p>
406         * <p>A value less than or equal to zero means the pool is set to wait
407         * indefinitely.</p>
408         * 
409         * @return the maxWait property value
410         */
411        public synchronized long getMaxWait() {
412            return this.maxWait;
413        }
414    
415        /**
416         * <p>Sets the maxWait property.
417         * </p>
418         * <p>Use -1 to make the pool wait indefinitely.
419         * </p>
420         * 
421         * @param maxWait the new value for maxWait
422         * @see #getMaxWait()
423         */
424        public synchronized void setMaxWait(long maxWait) {
425            this.maxWait = maxWait;
426            if (connectionPool != null) {
427                connectionPool.setMaxWait(maxWait);
428            }
429        }
430    
431        /**
432         * Prepared statement pooling for this pool. When this property is set to <code>true</code>
433         * both PreparedStatements and CallableStatements are pooled.
434         */
435        protected boolean poolPreparedStatements = false;
436        
437        /**
438         * Returns true if we are pooling statements.
439         * 
440         * @return true if prepared and callable statements are pooled
441         */
442        public synchronized boolean isPoolPreparedStatements() {
443            return this.poolPreparedStatements;
444        }
445    
446        /**
447         * <p>Sets whether to pool statements or not.</p>
448         * <p>
449         * Note: this method currently has no effect once the pool has been
450         * initialized.  The pool is initialized the first time one of the
451         * following methods is invoked: <code>getConnection, setLogwriter,
452         * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
453         * 
454         * @param poolingStatements pooling on or off
455         */
456        public synchronized void setPoolPreparedStatements(boolean poolingStatements) {
457            this.poolPreparedStatements = poolingStatements;
458            this.restartNeeded = true;
459        }
460    
461        /**
462         * <p>The maximum number of open statements that can be allocated from
463         * the statement pool at the same time, or non-positive for no limit.  Since 
464         * a connection usually only uses one or two statements at a time, this is
465         * mostly used to help detect resource leaks.</p>
466         * 
467         * <p>Note: As of version 1.3, CallableStatements (those produced by {@link Connection#prepareCall})
468         * are pooled along with PreparedStatements (produced by {@link Connection#prepareStatement})
469         * and <code>maxOpenPreparedStatements</code> limits the total number of prepared or callable statements
470         * that may be in use at a given time.</p>
471         */
472        protected int maxOpenPreparedStatements = GenericKeyedObjectPool.DEFAULT_MAX_TOTAL;
473    
474        /**
475         * Gets the value of the {@link #maxOpenPreparedStatements} property.
476         * 
477         * @return the maximum number of open statements
478         * @see #maxOpenPreparedStatements
479         */
480        public synchronized int getMaxOpenPreparedStatements() {
481            return this.maxOpenPreparedStatements;
482        }
483    
484        /** 
485         * <p>Sets the value of the {@link #maxOpenPreparedStatements}
486         * property.</p>
487         * <p>
488         * Note: this method currently has no effect once the pool has been
489         * initialized.  The pool is initialized the first time one of the
490         * following methods is invoked: <code>getConnection, setLogwriter,
491         * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
492         * 
493         * @param maxOpenStatements the new maximum number of prepared statements
494         * @see #maxOpenPreparedStatements
495         */
496        public synchronized void setMaxOpenPreparedStatements(int maxOpenStatements) {
497            this.maxOpenPreparedStatements = maxOpenStatements;
498            this.restartNeeded = true;
499        }
500    
501        /**
502         * The indication of whether objects will be validated before being
503         * borrowed from the pool.  If the object fails to validate, it will be
504         * dropped from the pool, and we will attempt to borrow another.
505         */
506        protected boolean testOnBorrow = true;
507    
508        /**
509         * Returns the {@link #testOnBorrow} property.
510         * 
511         * @return true if objects are validated before being borrowed from the
512         * pool
513         * 
514         * @see #testOnBorrow
515         */
516        public synchronized boolean getTestOnBorrow() {
517            return this.testOnBorrow;
518        }
519    
520        /**
521         * Sets the {@link #testOnBorrow} property. This property determines
522         * whether or not the pool will validate objects before they are borrowed
523         * from the pool. For a <code>true</code> value to have any effect, the 
524         * <code>validationQuery</code> property must be set to a non-null string.
525         * 
526         * @param testOnBorrow new value for testOnBorrow property
527         */
528        public synchronized void setTestOnBorrow(boolean testOnBorrow) {
529            this.testOnBorrow = testOnBorrow;
530            if (connectionPool != null) {
531                connectionPool.setTestOnBorrow(testOnBorrow);
532            }
533        }
534    
535        /**
536         * The indication of whether objects will be validated before being
537         * returned to the pool.
538         */
539        protected boolean testOnReturn = false;
540    
541        /**
542         * Returns the value of the {@link #testOnReturn} property.
543         * 
544         * @return true if objects are validated before being returned to the
545         * pool
546         * @see #testOnReturn
547         */
548        public synchronized boolean getTestOnReturn() {
549            return this.testOnReturn;
550        }
551    
552        /**
553         * Sets the <code>testOnReturn</code> property. This property determines
554         * whether or not the pool will validate objects before they are returned
555         * to the pool. For a <code>true</code> value to have any effect, the 
556         * <code>validationQuery</code> property must be set to a non-null string.
557         * 
558         * @param testOnReturn new value for testOnReturn property
559         */
560        public synchronized void setTestOnReturn(boolean testOnReturn) {
561            this.testOnReturn = testOnReturn;
562            if (connectionPool != null) {
563                connectionPool.setTestOnReturn(testOnReturn);
564            }
565        }
566    
567        /**
568         * The number of milliseconds to sleep between runs of the idle object
569         * evictor thread.  When non-positive, no idle object evictor thread will
570         * be run.
571         */
572        protected long timeBetweenEvictionRunsMillis =
573            GenericObjectPool.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
574            
575        /**
576         * Returns the value of the {@link #timeBetweenEvictionRunsMillis}
577         * property.
578         * 
579         * @return the time (in miliseconds) between evictor runs
580         * @see #timeBetweenEvictionRunsMillis
581         */
582        public synchronized long getTimeBetweenEvictionRunsMillis() {
583            return this.timeBetweenEvictionRunsMillis;
584        }
585    
586        /**
587         * Sets the {@link #timeBetweenEvictionRunsMillis} property.
588         * 
589         * @param timeBetweenEvictionRunsMillis the new time between evictor runs
590         * @see #timeBetweenEvictionRunsMillis
591         */
592        public synchronized void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) {
593            this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
594            if (connectionPool != null) {
595                connectionPool.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
596            }
597        }
598    
599        /**
600         * The number of objects to examine during each run of the idle object
601         * evictor thread (if any).
602         */
603        protected int numTestsPerEvictionRun =
604            GenericObjectPool.DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
605    
606        /**
607         * Returns the value of the {@link #numTestsPerEvictionRun} property.
608         * 
609         * @return the number of objects to examine during idle object evictor
610         * runs
611         * @see #numTestsPerEvictionRun
612         */
613        public synchronized int getNumTestsPerEvictionRun() {
614            return this.numTestsPerEvictionRun;
615        }
616    
617        /**
618         * Sets the value of the {@link #numTestsPerEvictionRun} property.
619         * 
620         * @param numTestsPerEvictionRun the new {@link #numTestsPerEvictionRun} 
621         * value
622         * @see #numTestsPerEvictionRun
623         */
624        public synchronized void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) {
625            this.numTestsPerEvictionRun = numTestsPerEvictionRun;
626            if (connectionPool != null) {
627                connectionPool.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
628            }
629        }
630    
631        /**
632         * The minimum amount of time an object may sit idle in the pool before it
633         * is eligable for eviction by the idle object evictor (if any).
634         */
635        protected long minEvictableIdleTimeMillis =
636            GenericObjectPool.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
637    
638        /**
639         * Returns the {@link #minEvictableIdleTimeMillis} property.
640         * 
641         * @return the value of the {@link #minEvictableIdleTimeMillis} property
642         * @see #minEvictableIdleTimeMillis
643         */
644        public synchronized long getMinEvictableIdleTimeMillis() {
645            return this.minEvictableIdleTimeMillis;
646        }
647    
648        /**
649         * Sets the {@link #minEvictableIdleTimeMillis} property.
650         * 
651         * @param minEvictableIdleTimeMillis the minimum amount of time an object
652         * may sit idle in the pool 
653         * @see #minEvictableIdleTimeMillis
654         */
655        public synchronized void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) {
656            this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
657            if (connectionPool != null) {
658                connectionPool.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
659            }
660        }
661    
662        /**
663         * The indication of whether objects will be validated by the idle object
664         * evictor (if any).  If an object fails to validate, it will be dropped
665         * from the pool.
666         */
667        protected boolean testWhileIdle = false;
668    
669        /**
670         * Returns the value of the {@link #testWhileIdle} property.
671         * 
672         * @return true if objects examined by the idle object evictor are
673         * validated
674         * @see #testWhileIdle
675         */
676        public synchronized boolean getTestWhileIdle() {
677            return this.testWhileIdle;
678        }
679    
680        /**
681         * Sets the <code>testWhileIdle</code> property. This property determines
682         * whether or not the idle object evictor will validate connections.  For a
683         * <code>true</code> value to have any effect, the 
684         * <code>validationQuery</code> property must be set to a non-null string.
685         * 
686         * @param testWhileIdle new value for testWhileIdle property
687         */
688        public synchronized void setTestWhileIdle(boolean testWhileIdle) {
689            this.testWhileIdle = testWhileIdle;
690            if (connectionPool != null) {
691                connectionPool.setTestWhileIdle(testWhileIdle);
692            }
693        }
694    
695        /**
696         * [Read Only] The current number of active connections that have been
697         * allocated from this data source.
698         * 
699         * @return the current number of active connections
700         */
701        public synchronized int getNumActive() {
702            if (connectionPool != null) {
703                return connectionPool.getNumActive();
704            } else {
705                return 0;
706            }
707        }
708    
709    
710        /**
711         * [Read Only] The current number of idle connections that are waiting
712         * to be allocated from this data source.
713         * 
714         * @return the current number of idle connections
715         */
716        public synchronized int getNumIdle() {
717            if (connectionPool != null) {
718                return connectionPool.getNumIdle();
719            } else {
720                return 0;
721            }
722        }
723    
724        /**
725         * The connection password to be passed to our JDBC driver to establish
726         * a connection.
727         */
728        protected volatile String password = null;
729    
730        /**
731         * Returns the password passed to the JDBC driver to establish connections.
732         * 
733         * @return the connection password
734         */
735        public String getPassword() {
736            return this.password;
737        }
738    
739        /** 
740         * <p>Sets the {@link #password}.</p>
741         * <p>
742         * Note: this method currently has no effect once the pool has been
743         * initialized.  The pool is initialized the first time one of the
744         * following methods is invoked: <code>getConnection, setLogwriter,
745         * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
746         * 
747         * @param password new value for the password
748         */
749        public void setPassword(String password) {
750            this.password = password;
751            this.restartNeeded = true;
752        }
753    
754        /**
755         * The connection URL to be passed to our JDBC driver to establish
756         * a connection.
757         */
758        protected String url = null;
759    
760        /**
761         * Returns the JDBC connection {@link #url} property.
762         * 
763         * @return the {@link #url} passed to the JDBC driver to establish
764         * connections
765         */
766        public synchronized String getUrl() {
767            return this.url;
768        }
769    
770        /** 
771         * <p>Sets the {@link #url}.</p>
772         * <p>
773         * Note: this method currently has no effect once the pool has been
774         * initialized.  The pool is initialized the first time one of the
775         * following methods is invoked: <code>getConnection, setLogwriter,
776         * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
777         * 
778         * @param url the new value for the JDBC connection url
779         */
780        public synchronized void setUrl(String url) {
781            this.url = url;
782            this.restartNeeded = true;
783        }
784    
785        /**
786         * The connection username to be passed to our JDBC driver to
787         * establish a connection.
788         */
789        protected String username = null;
790    
791        /**
792         * Returns the JDBC connection {@link #username} property.
793         * 
794         * @return the {@link #username} passed to the JDBC driver to establish
795         * connections
796         */
797        public String getUsername() {
798            return this.username;
799        }
800    
801        /** 
802         * <p>Sets the {@link #username}.</p>
803         * <p>
804         * Note: this method currently has no effect once the pool has been
805         * initialized.  The pool is initialized the first time one of the
806         * following methods is invoked: <code>getConnection, setLogwriter,
807         * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
808         * 
809         * @param username the new value for the JDBC connection username
810         */
811        public void setUsername(String username) {
812            this.username = username;
813            this.restartNeeded = true;
814        }
815    
816        /**
817         * The SQL query that will be used to validate connections from this pool
818         * before returning them to the caller.  If specified, this query
819         * <strong>MUST</strong> be an SQL SELECT statement that returns at least
820         * one row.
821         */
822        protected volatile String validationQuery = null;
823    
824        /**
825         * Returns the validation query used to validate connections before
826         * returning them.
827         * 
828         * @return the SQL validation query
829         * @see #validationQuery
830         */
831        public String getValidationQuery() {
832            return this.validationQuery;
833        }
834    
835        /** 
836         * <p>Sets the {@link #validationQuery}.</p>
837         * <p>
838         * Note: this method currently has no effect once the pool has been
839         * initialized.  The pool is initialized the first time one of the
840         * following methods is invoked: <code>getConnection, setLogwriter,
841         * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
842         * 
843         * @param validationQuery the new value for the validation query
844         */
845        public void setValidationQuery(String validationQuery) {
846            if ((validationQuery != null) && (validationQuery.trim().length() > 0)) {
847                this.validationQuery = validationQuery;
848            } else {
849                this.validationQuery = null;
850            }
851            this.restartNeeded = true;
852        }
853        
854        /**
855         * Timeout in seconds before connection validation queries fail. 
856         * 
857         * @since 1.3
858         */
859        protected volatile int validationQueryTimeout = -1;
860        
861        /**
862         * Returns the validation query timeout.
863         * 
864         * @return the timeout in seconds before connection validation queries fail.
865         * @since 1.3
866         */
867        public int getValidationQueryTimeout() {
868            return validationQueryTimeout;
869        }
870        
871        /**
872         * Sets the validation query timeout, the amount of time, in seconds, that
873         * connection validation will wait for a response from the database when
874         * executing a validation query.  Use a value less than or equal to 0 for
875         * no timeout.
876         * <p>
877         * Note: this method currently has no effect once the pool has been
878         * initialized.  The pool is initialized the first time one of the
879         * following methods is invoked: <code>getConnection, setLogwriter,
880         * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
881         * 
882         * @param timeout new validation query timeout value in seconds
883         * @since 1.3
884         */
885        public void setValidationQueryTimeout(int timeout) {
886            this.validationQueryTimeout = timeout;
887            restartNeeded = true;
888        }
889        
890        /**
891         * These SQL statements run once after a Connection is created.
892         * <p>
893         * This property can be used for example to run ALTER SESSION SET
894         * NLS_SORT=XCYECH in an Oracle Database only once after connection
895         * creation.
896         * </p>
897         * 
898         * @since 1.3
899         */
900        protected volatile List connectionInitSqls;
901    
902        /**
903         * Returns the list of SQL statements executed when a physical connection
904         * is first created. Returns an empty list if there are no initialization
905         * statements configured.
906         * 
907         * @return initialization SQL statements
908         * @since 1.3
909         */
910        public Collection getConnectionInitSqls() {
911            Collection result = connectionInitSqls; 
912            if (result == null) {
913                return Collections.EMPTY_LIST;
914            }
915            return result;
916        }
917    
918        /**
919         * Sets the list of SQL statements to be executed when a physical
920         * connection is first created.
921         * <p>
922         * Note: this method currently has no effect once the pool has been
923         * initialized.  The pool is initialized the first time one of the
924         * following methods is invoked: <code>getConnection, setLogwriter,
925         * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
926         * 
927         * @param connectionInitSqls Collection of SQL statements to execute
928         * on connection creation
929         */
930        public void setConnectionInitSqls(Collection connectionInitSqls) {
931            if ((connectionInitSqls != null) && (connectionInitSqls.size() > 0)) {
932                ArrayList newVal = null;
933                for (Iterator iterator = connectionInitSqls.iterator();
934                iterator.hasNext();) {
935                    Object o = iterator.next();
936                    if (o != null) {
937                        String s = o.toString();
938                        if (s.trim().length() > 0) {
939                            if (newVal == null) {
940                                newVal = new ArrayList();
941                            }
942                            newVal.add(s);
943                        }
944                    }
945                }
946                this.connectionInitSqls = newVal;
947            } else {
948                this.connectionInitSqls = null;
949            }
950            this.restartNeeded = true;
951        }
952    
953    
954        /** 
955         * Controls access to the underlying connection.
956         */
957        private boolean accessToUnderlyingConnectionAllowed = false; 
958    
959        /**
960         * Returns the value of the accessToUnderlyingConnectionAllowed property.
961         * 
962         * @return true if access to the underlying connection is allowed, false
963         * otherwise.
964         */
965        public synchronized boolean isAccessToUnderlyingConnectionAllowed() {
966            return this.accessToUnderlyingConnectionAllowed;
967        }
968    
969        /**
970         * <p>Sets the value of the accessToUnderlyingConnectionAllowed property.
971         * It controls if the PoolGuard allows access to the underlying connection.
972         * (Default: false)</p>
973         * <p>
974         * Note: this method currently has no effect once the pool has been
975         * initialized.  The pool is initialized the first time one of the
976         * following methods is invoked: <code>getConnection, setLogwriter,
977         * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
978         * 
979         * @param allow Access to the underlying connection is granted when true.
980         */
981        public synchronized void setAccessToUnderlyingConnectionAllowed(boolean allow) {
982            this.accessToUnderlyingConnectionAllowed = allow;
983            this.restartNeeded = true;
984        }
985    
986        // ----------------------------------------------------- Instance Variables
987    
988        // TODO: review & make isRestartNeeded() public, restartNeeded protected
989    
990        /**
991         * A property setter has been invoked that will require the connection
992         * pool to be re-initialized. Currently, restart is not triggered, so
993         * this property has no effect.
994         */
995        private volatile boolean restartNeeded = false;
996        
997        /**
998         * Returns whether or not a restart is needed. 
999         *  
1000         * Note: restart is not currently triggered by property changes.
1001         * 
1002         * @return true if a restart is needed
1003         */
1004        private boolean isRestartNeeded() {
1005            return restartNeeded;
1006        }
1007    
1008        /**
1009         * The object pool that internally manages our connections.
1010         */
1011        protected volatile GenericObjectPool connectionPool = null;
1012        
1013        /**
1014         * The connection properties that will be sent to our JDBC driver when
1015         * establishing new connections.  <strong>NOTE</strong> - The "user" and
1016         * "password" properties will be passed explicitly, so they do not need
1017         * to be included here.
1018         */
1019        protected Properties connectionProperties = new Properties();
1020    
1021        /**
1022         * The data source we will use to manage connections.  This object should
1023         * be acquired <strong>ONLY</strong> by calls to the
1024         * <code>createDataSource()</code> method.
1025         */
1026        protected volatile DataSource dataSource = null;
1027    
1028        /**
1029         * The PrintWriter to which log messages should be directed.
1030         */
1031        protected PrintWriter logWriter = new PrintWriter(System.out);
1032    
1033    
1034        // ----------------------------------------------------- DataSource Methods
1035    
1036    
1037        /**
1038         * Create (if necessary) and return a connection to the database.
1039         *
1040         * @throws SQLException if a database access error occurs
1041         * @return a database connection
1042         */
1043        public Connection getConnection() throws SQLException {
1044            return createDataSource().getConnection();
1045        }
1046    
1047    
1048        /**
1049         * <strong>BasicDataSource does NOT support this method. </strong>
1050         *
1051         * @param user Database user on whose behalf the Connection
1052         *   is being made
1053         * @param pass The database user's password
1054         *
1055         * @throws UnsupportedOperationException
1056         * @throws SQLException if a database access error occurs
1057         * @return nothing - always throws UnsupportedOperationException
1058         */
1059        public Connection getConnection(String user, String pass) throws SQLException {
1060            // This method isn't supported by the PoolingDataSource returned by
1061            // the createDataSource
1062            throw new UnsupportedOperationException("Not supported by BasicDataSource");
1063            // return createDataSource().getConnection(username, password);
1064        }
1065    
1066    
1067        /**
1068         * <strong>BasicDataSource does NOT support this method. </strong>
1069         *
1070         * <p>Returns the login timeout (in seconds) for connecting to the database.
1071         * </p>
1072         * <p>Calls {@link #createDataSource()}, so has the side effect
1073         * of initializing the connection pool.</p>
1074         *
1075         * @throws SQLException if a database access error occurs
1076         * @throws UnsupportedOperationException If the DataSource implementation
1077         *   does not support the login timeout feature.
1078         * @return login timeout in seconds
1079         */
1080        public int getLoginTimeout() throws SQLException {
1081            // This method isn't supported by the PoolingDataSource returned by
1082            // the createDataSource
1083            throw new UnsupportedOperationException("Not supported by BasicDataSource");
1084            //return createDataSource().getLoginTimeout();
1085        }
1086    
1087    
1088        /**
1089         * <p>Returns the log writer being used by this data source.</p>
1090         * <p>
1091         * Calls {@link #createDataSource()}, so has the side effect
1092         * of initializing the connection pool.</p>
1093         *
1094         * @throws SQLException if a database access error occurs
1095         * @return log writer in use
1096         */
1097        public PrintWriter getLogWriter() throws SQLException {
1098            return createDataSource().getLogWriter();
1099        }
1100    
1101    
1102        /**
1103         * <strong>BasicDataSource does NOT support this method. </strong>
1104         *
1105         * <p>Set the login timeout (in seconds) for connecting to the
1106         * database.</p>
1107         * <p>
1108         * Calls {@link #createDataSource()}, so has the side effect
1109         * of initializing the connection pool.</p>
1110         *
1111         * @param loginTimeout The new login timeout, or zero for no timeout
1112         * @throws UnsupportedOperationException If the DataSource implementation
1113         *   does not support the login timeout feature.
1114         * @throws SQLException if a database access error occurs
1115         */
1116        public void setLoginTimeout(int loginTimeout) throws SQLException {
1117            // This method isn't supported by the PoolingDataSource returned by
1118            // the createDataSource
1119            throw new UnsupportedOperationException("Not supported by BasicDataSource");
1120            //createDataSource().setLoginTimeout(loginTimeout);
1121        }
1122    
1123    
1124        /**
1125         * <p>Sets the log writer being used by this data source.</p>
1126         * <p>
1127         * Calls {@link #createDataSource()}, so has the side effect
1128         * of initializing the connection pool.</p>
1129         *
1130         * @param logWriter The new log writer
1131         * @throws SQLException if a database access error occurs
1132         */
1133        public void setLogWriter(PrintWriter logWriter) throws SQLException {
1134            createDataSource().setLogWriter(logWriter);
1135            this.logWriter = logWriter;
1136        }
1137    
1138        private AbandonedConfig abandonedConfig;
1139    
1140        /**                       
1141         * Flag to remove abandoned connections if they exceed the
1142         * removeAbandonedTimout.
1143         *
1144         * Set to true or false, default false.
1145         * If set to true a connection is considered abandoned and eligible
1146         * for removal if it has been idle longer than the removeAbandonedTimeout.
1147         * Setting this to true can recover db connections from poorly written    
1148         * applications which fail to close a connection.
1149         * <p>
1150         * Abandonded connections are identified and removed when 
1151         * {@link #getConnection()} is invoked and the following conditions hold
1152         * <ul><li>{@link #getRemoveAbandoned()} = true </li>
1153         *     <li>{@link #getNumActive()} > {@link #getMaxActive()} - 3 </li>
1154         *     <li>{@link #getNumIdle()} < 2 </li></ul></p>
1155         */                                                                   
1156        public boolean getRemoveAbandoned() {   
1157            if (abandonedConfig != null) {
1158                return abandonedConfig.getRemoveAbandoned();
1159            }
1160            return false;
1161        }                                    
1162                                     
1163        /**
1164         * @param removeAbandoned new removeAbandoned property value
1165         * @see #getRemoveAbandoned()
1166         */
1167        public void setRemoveAbandoned(boolean removeAbandoned) {
1168            if (abandonedConfig == null) {
1169                abandonedConfig = new AbandonedConfig();
1170            }
1171            abandonedConfig.setRemoveAbandoned(removeAbandoned);
1172            this.restartNeeded = true;
1173        }                                                        
1174                                                   
1175        /**
1176         * Timeout in seconds before an abandoned connection can be removed.
1177         *
1178         * Defaults to 300 seconds. 
1179         * @return abandoned connection timeout        
1180         */                                                                 
1181        public int getRemoveAbandonedTimeout() { 
1182            if (abandonedConfig != null) {
1183                return abandonedConfig.getRemoveAbandonedTimeout();
1184            }
1185            return 300;
1186        }                                        
1187    
1188        /**
1189         * @param removeAbandonedTimeout new removeAbandonedTimeout value
1190         */               
1191        public void setRemoveAbandonedTimeout(int removeAbandonedTimeout) {
1192            if (abandonedConfig == null) {
1193                abandonedConfig = new AbandonedConfig();
1194            }
1195            abandonedConfig.setRemoveAbandonedTimeout(removeAbandonedTimeout);
1196            this.restartNeeded = true;
1197        }                                                                  
1198                                                                 
1199        /**
1200         * <p>Flag to log stack traces for application code which abandoned
1201         * a Statement or Connection.
1202         * </p>
1203         * <p>Defaults to false.                
1204         * </p>                                                            
1205         * <p>Logging of abandoned Statements and Connections adds overhead
1206         * for every Connection open or new Statement because a stack   
1207         * trace has to be generated. </p>
1208         */                                                          
1209        public boolean getLogAbandoned() {   
1210            if (abandonedConfig != null) {
1211                return abandonedConfig.getLogAbandoned();
1212            }
1213            return false;
1214        }                                 
1215    
1216        /**
1217         * @param logAbandoned new logAbandoned property value
1218         */
1219        public void setLogAbandoned(boolean logAbandoned) {
1220            if (abandonedConfig == null) {
1221                abandonedConfig = new AbandonedConfig();
1222            }
1223            abandonedConfig.setLogAbandoned(logAbandoned);
1224            this.restartNeeded = true;
1225        }
1226    
1227        // --------------------------------------------------------- Public Methods
1228    
1229        /**
1230         * Add a custom connection property to the set that will be passed to our
1231         * JDBC driver. This <strong>MUST</strong> be called before the first
1232         * connection is retrieved (along with all the other configuration
1233         * property setters). Calls to this method after the connection pool
1234         * has been initialized have no effect.
1235         *
1236         * @param name Name of the custom connection property
1237         * @param value Value of the custom connection property
1238         */
1239        public void addConnectionProperty(String name, String value) {
1240            connectionProperties.put(name, value);
1241            this.restartNeeded = true;
1242        }
1243    
1244        /**
1245         * Remove a custom connection property.
1246         * 
1247         * @param name Name of the custom connection property to remove
1248         * @see #addConnectionProperty(String, String)
1249         */
1250        public void removeConnectionProperty(String name) {
1251            connectionProperties.remove(name);
1252            this.restartNeeded = true;
1253        }
1254    
1255        /**
1256         * Sets the connection properties passed to driver.connect(...).
1257         *
1258         * Format of the string must be [propertyName=property;]*
1259         *
1260         * NOTE - The "user" and "password" properties will be added
1261         * explicitly, so they do not need to be included here.
1262         *
1263         * @param connectionProperties the connection properties used to
1264         * create new connections
1265         */
1266        public void setConnectionProperties(String connectionProperties) {
1267            if (connectionProperties == null) throw new NullPointerException("connectionProperties is null");
1268    
1269            String[] entries = connectionProperties.split(";");
1270            Properties properties = new Properties();
1271            for (int i = 0; i < entries.length; i++) {
1272                String entry = entries[i];
1273                if (entry.length() > 0) {
1274                    int index = entry.indexOf('=');
1275                    if (index > 0) {
1276                        String name = entry.substring(0, index);
1277                        String value = entry.substring(index + 1);
1278                        properties.setProperty(name, value);
1279                    } else {
1280                        // no value is empty string which is how java.util.Properties works
1281                        properties.setProperty(entry, "");
1282                    }
1283                }
1284            }
1285            this.connectionProperties = properties;
1286            this.restartNeeded = true;
1287        }
1288    
1289        protected boolean closed;
1290    
1291        /**
1292         * <p>Closes and releases all idle connections that are currently stored in the connection pool
1293         * associated with this data source.</p>
1294         *
1295         * <p>Connections that are checked out to clients when this method is invoked are not affected.  
1296         * When client applications subsequently invoke {@link Connection#close()} to return
1297         * these connections to the pool, the underlying JDBC connections are closed.</p>
1298         * 
1299         * <p>Attempts to acquire connections using {@link #getConnection()} after this method has been
1300         * invoked result in SQLExceptions.<p>
1301         * 
1302         * <p>This method is idempotent - i.e., closing an already closed BasicDataSource has no effect
1303         * and does not generate exceptions.</p>
1304         * 
1305         * @throws SQLException if an error occurs closing idle connections
1306         */
1307        public synchronized void close() throws SQLException {
1308            closed = true;
1309            GenericObjectPool oldpool = connectionPool;
1310            connectionPool = null;
1311            dataSource = null;
1312            try {
1313                if (oldpool != null) {
1314                    oldpool.close();
1315                }
1316            } catch(SQLException e) {
1317                throw e;
1318            } catch(RuntimeException e) {
1319                throw e;
1320            } catch(Exception e) {
1321                throw new SQLNestedException("Cannot close connection pool", e);
1322            }
1323        }
1324    
1325        /**
1326         * If true, this data source is closed and no more connections can be retrieved from this datasource.
1327         * @return true, if the data source is closed; false otherwise
1328         */
1329        public synchronized boolean isClosed() {
1330            return closed;
1331        }
1332    
1333        /*
1334        public boolean isWrapperFor(Class<?> iface) throws SQLException {
1335            return false;
1336        }
1337    
1338        public <T> T unwrap(Class<T> iface) throws SQLException {
1339            throw new SQLException("BasicDataSource is not a wrapper.");
1340        }
1341        */
1342    
1343            
1344        // ------------------------------------------------------ Protected Methods
1345    
1346    
1347        /**
1348         * <p>Create (if necessary) and return the internal data source we are
1349         * using to manage our connections.</p>
1350         *
1351         * <p><strong>IMPLEMENTATION NOTE</strong> - It is tempting to use the
1352         * "double checked locking" idiom in an attempt to avoid synchronizing
1353         * on every single call to this method.  However, this idiom fails to
1354         * work correctly in the face of some optimizations that are legal for
1355         * a JVM to perform.</p>
1356         *
1357         * @throws SQLException if the object pool cannot be created.
1358         */
1359        protected synchronized DataSource createDataSource()
1360            throws SQLException {
1361            if (closed) {
1362                throw new SQLException("Data source is closed");
1363            }
1364    
1365            // Return the pool if we have already created it
1366            if (dataSource != null) {
1367                return (dataSource);
1368            }
1369    
1370            // create factory which returns raw physical connections
1371            ConnectionFactory driverConnectionFactory = createConnectionFactory();
1372    
1373            // create a pool for our connections
1374            createConnectionPool();
1375    
1376            // Set up statement pool, if desired
1377            GenericKeyedObjectPoolFactory statementPoolFactory = null;
1378            if (isPoolPreparedStatements()) {
1379                statementPoolFactory = new GenericKeyedObjectPoolFactory(null,
1380                            -1, // unlimited maxActive (per key)
1381                            GenericKeyedObjectPool.WHEN_EXHAUSTED_FAIL,
1382                            0, // maxWait
1383                            1, // maxIdle (per key)
1384                            maxOpenPreparedStatements);
1385            }
1386    
1387            // Set up the poolable connection factory
1388            createPoolableConnectionFactory(driverConnectionFactory, statementPoolFactory, abandonedConfig);
1389    
1390            // Create and return the pooling data source to manage the connections
1391            createDataSourceInstance();
1392            
1393            try {
1394                for (int i = 0 ; i < initialSize ; i++) {
1395                    connectionPool.addObject();
1396                }
1397            } catch (Exception e) {
1398                throw new SQLNestedException("Error preloading the connection pool", e);
1399            }
1400            
1401            return dataSource;
1402        }
1403    
1404        /**
1405         * Creates a JDBC connection factory for this datasource.  This method only
1406         * exists so subclasses can replace the implementation class.
1407         */
1408        protected ConnectionFactory createConnectionFactory() throws SQLException {
1409            // Load the JDBC driver class
1410            Class driverFromCCL = null;
1411            if (driverClassName != null) {
1412                try {
1413                    try {
1414                        if (driverClassLoader == null) {
1415                            Class.forName(driverClassName);
1416                        } else {
1417                            Class.forName(driverClassName, true, driverClassLoader);
1418                        }
1419                    } catch (ClassNotFoundException cnfe) {
1420                        driverFromCCL = Thread.currentThread(
1421                                ).getContextClassLoader().loadClass(
1422                                        driverClassName);
1423                    }
1424                } catch (Throwable t) {
1425                    String message = "Cannot load JDBC driver class '" +
1426                        driverClassName + "'";
1427                    logWriter.println(message);
1428                    t.printStackTrace(logWriter);
1429                    throw new SQLNestedException(message, t);
1430                }
1431            }
1432    
1433            // Create a JDBC driver instance
1434            Driver driver = null;
1435            try {
1436                if (driverFromCCL == null) {
1437                    driver = DriverManager.getDriver(url);
1438                } else {
1439                    // Usage of DriverManager is not possible, as it does not
1440                    // respect the ContextClassLoader
1441                    driver = (Driver) driverFromCCL.newInstance();
1442                    if (!driver.acceptsURL(url)) {
1443                        throw new SQLException("No suitable driver", "08001"); 
1444                    }
1445                }
1446            } catch (Throwable t) {
1447                String message = "Cannot create JDBC driver of class '" +
1448                    (driverClassName != null ? driverClassName : "") +
1449                    "' for connect URL '" + url + "'";
1450                logWriter.println(message);
1451                t.printStackTrace(logWriter);
1452                throw new SQLNestedException(message, t);
1453            }
1454    
1455            // Can't test without a validationQuery
1456            if (validationQuery == null) {
1457                setTestOnBorrow(false);
1458                setTestOnReturn(false);
1459                setTestWhileIdle(false);
1460            }
1461    
1462            // Set up the driver connection factory we will use
1463            String user = username;
1464            if (user != null) {
1465                connectionProperties.put("user", user);
1466            } else {
1467                log("DBCP DataSource configured without a 'username'");
1468            }
1469    
1470            String pwd = password;
1471            if (pwd != null) {
1472                connectionProperties.put("password", pwd);
1473            } else {
1474                log("DBCP DataSource configured without a 'password'");
1475            }
1476    
1477            ConnectionFactory driverConnectionFactory = new DriverConnectionFactory(driver, url, connectionProperties);
1478            return driverConnectionFactory;
1479        }
1480    
1481        /**
1482         * Creates a connection pool for this datasource.  This method only exists
1483         * so subclasses can replace the implementation class.
1484         */
1485        protected void createConnectionPool() {
1486            // Create an object pool to contain our active connections
1487            GenericObjectPool gop;
1488            if ((abandonedConfig != null) && (abandonedConfig.getRemoveAbandoned())) {
1489                gop = new AbandonedObjectPool(null,abandonedConfig);
1490            }
1491            else {
1492                gop = new GenericObjectPool();
1493            }
1494            gop.setMaxActive(maxActive);
1495            gop.setMaxIdle(maxIdle);
1496            gop.setMinIdle(minIdle);
1497            gop.setMaxWait(maxWait);
1498            gop.setTestOnBorrow(testOnBorrow);
1499            gop.setTestOnReturn(testOnReturn);
1500            gop.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
1501            gop.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
1502            gop.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
1503            gop.setTestWhileIdle(testWhileIdle);
1504            connectionPool = gop;
1505        }
1506    
1507        /**
1508         * Creates the actual data source instance.  This method only exists so
1509         * subclasses can replace the implementation class.
1510         * 
1511         * @throws SQLException if unable to create a datasource instance
1512         */
1513        protected void createDataSourceInstance() throws SQLException {
1514            PoolingDataSource pds = new PoolingDataSource(connectionPool);
1515            pds.setAccessToUnderlyingConnectionAllowed(isAccessToUnderlyingConnectionAllowed());
1516            pds.setLogWriter(logWriter);
1517            dataSource = pds;
1518        }
1519    
1520        /**
1521         * Creates the PoolableConnectionFactory and attaches it to the connection pool.  This method only exists
1522         * so subclasses can replace the default implementation.
1523         * 
1524         * @param driverConnectionFactory JDBC connection factory
1525         * @param statementPoolFactory statement pool factory (null if statement pooling is turned off)
1526         * @param configuration abandoned connection tracking configuration (null if no tracking)
1527         * @throws SQLException if an error occurs creating the PoolableConnectionFactory
1528         */
1529        protected void createPoolableConnectionFactory(ConnectionFactory driverConnectionFactory,
1530                KeyedObjectPoolFactory statementPoolFactory, AbandonedConfig configuration) throws SQLException {
1531            PoolableConnectionFactory connectionFactory = null;
1532            try {
1533                connectionFactory =
1534                    new PoolableConnectionFactory(driverConnectionFactory,
1535                                                  connectionPool,
1536                                                  statementPoolFactory,
1537                                                  validationQuery,
1538                                                  validationQueryTimeout,
1539                                                  connectionInitSqls,
1540                                                  defaultReadOnly,
1541                                                  defaultAutoCommit,
1542                                                  defaultTransactionIsolation,
1543                                                  defaultCatalog,
1544                                                  configuration);
1545                validateConnectionFactory(connectionFactory);
1546            } catch (RuntimeException e) {
1547                throw e;
1548            } catch (Exception e) {
1549                throw new SQLNestedException("Cannot create PoolableConnectionFactory (" + e.getMessage() + ")", e);
1550            }
1551        }
1552    
1553        protected static void validateConnectionFactory(PoolableConnectionFactory connectionFactory) throws Exception {
1554            Connection conn = null;
1555            try {
1556                conn = (Connection) connectionFactory.makeObject();
1557                connectionFactory.activateObject(conn);
1558                connectionFactory.validateConnection(conn);
1559                connectionFactory.passivateObject(conn);
1560            }
1561            finally {
1562                connectionFactory.destroyObject(conn);
1563            }
1564        }
1565    
1566        /**
1567         * Not used currently
1568         */
1569        private void restart() {
1570            try {
1571                close();
1572            } catch (SQLException e) {
1573                log("Could not restart DataSource, cause: " + e.getMessage());
1574            }
1575        }
1576    
1577        protected void log(String message) {
1578            if (logWriter != null) {
1579                logWriter.println(message);
1580            }
1581        }
1582    }