Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/apache/commons/dbcp/BasicDataSource.java


1   /*
2    * Copyright 1999-2004 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.apache.commons.dbcp;
18  
19  import java.io.PrintWriter;
20  import java.util.Properties;
21  import java.sql.Connection;
22  import java.sql.Driver;
23  import java.sql.DriverManager;
24  import java.sql.SQLException;
25  import javax.sql.DataSource;
26  
27  import org.apache.commons.pool.impl.GenericKeyedObjectPool;
28  import org.apache.commons.pool.impl.GenericKeyedObjectPoolFactory;
29  import org.apache.commons.pool.impl.GenericObjectPool;
30  
31  
32  /**
33   * <p>Basic implementation of <code>javax.sql.DataSource</code> that is
34   * configured via JavaBeans properties.  This is not the only way to
35   * combine the <em>commons-dbcp</em> and <em>commons-pool</em> packages,
36   * but provides a "one stop shopping" solution for basic requirements.</p>
37   *
38   * @author Glenn L. Nielsen
39   * @author Craig R. McClanahan
40   * @author Dirk Verbeeck
41   * @version $Revision: 1.37 $ $Date: 2004/06/09 18:21:23 $
42   */
43  public class BasicDataSource implements DataSource {
44  
45      // ------------------------------------------------------------- Properties
46  
47      /**
48       * The default auto-commit state of connections created by this pool.
49       */
50      protected boolean defaultAutoCommit = true;
51  
52      public synchronized boolean getDefaultAutoCommit() {
53          return this.defaultAutoCommit;
54      }
55  
56      public synchronized void setDefaultAutoCommit(boolean defaultAutoCommit) {
57          this.defaultAutoCommit = defaultAutoCommit;
58          this.restartNeeded = true;
59      }
60  
61  
62      /**
63       * The default read-only state of connections created by this pool.
64       */
65      protected Boolean defaultReadOnly = null;
66  
67      public synchronized boolean getDefaultReadOnly() {
68          if (this.defaultReadOnly != null) {
69              return this.defaultReadOnly.booleanValue();
70          }
71          return false;
72      }
73  
74      public synchronized void setDefaultReadOnly(boolean defaultReadOnly) {
75          this.defaultReadOnly = defaultReadOnly ? Boolean.TRUE : Boolean.FALSE;
76          this.restartNeeded = true;
77      }
78  
79      /**
80       * The default TransactionIsolation state of connections created by this pool.
81       */
82      protected int defaultTransactionIsolation = PoolableConnectionFactory.UNKNOWN_TRANSACTIONISOLATION;
83  
84      public synchronized int getDefaultTransactionIsolation() {
85          return this.defaultTransactionIsolation;
86      }
87  
88      public synchronized void setDefaultTransactionIsolation(int defaultTransactionIsolation) {
89          this.defaultTransactionIsolation = defaultTransactionIsolation;
90          this.restartNeeded = true;
91      }
92  
93  
94      /**
95       * The default "catalog" of connections created by this pool.
96       */
97      protected String defaultCatalog = null;
98  
99      public synchronized String getDefaultCatalog() {
100         return this.defaultCatalog;
101     }
102 
103     public synchronized void setDefaultCatalog(String defaultCatalog) {
104         if ((defaultCatalog != null) && (defaultCatalog.trim().length() > 0)) {
105             this.defaultCatalog = defaultCatalog;
106         }
107         else {
108             this.defaultCatalog = null;
109         }
110         this.restartNeeded = true;
111     }
112 
113   
114     /**
115      * The fully qualified Java class name of the JDBC driver to be used.
116      */
117     protected String driverClassName = null;
118 
119     public synchronized String getDriverClassName() {
120         return this.driverClassName;
121     }
122 
123     public synchronized void setDriverClassName(String driverClassName) {
124         if ((driverClassName != null) && (driverClassName.trim().length() > 0)) {
125             this.driverClassName = driverClassName;
126         }
127         else {
128             this.driverClassName = null;
129         }
130         this.restartNeeded = true;
131     }
132 
133 
134     /**
135      * The maximum number of active connections that can be allocated from
136      * this pool at the same time, or zero for no limit.
137      */
138     protected int maxActive = GenericObjectPool.DEFAULT_MAX_ACTIVE;
139 
140     public synchronized int getMaxActive() {
141         return this.maxActive;
142     }
143 
144     public synchronized void setMaxActive(int maxActive) {
145         this.maxActive = maxActive;
146         if (connectionPool != null) {
147             connectionPool.setMaxActive(maxActive);
148         }
149     }
150 
151 
152     /**
153      * The maximum number of active connections that can remain idle in the
154      * pool, without extra ones being released, or zero for no limit.
155      */
156     protected int maxIdle = GenericObjectPool.DEFAULT_MAX_IDLE;;
157 
158     public synchronized int getMaxIdle() {
159         return this.maxIdle;
160     }
161 
162     public synchronized void setMaxIdle(int maxIdle) {
163         this.maxIdle = maxIdle;
164         if (connectionPool != null) {
165             connectionPool.setMaxIdle(maxIdle);
166         }
167     }
168 
169     /**
170      * The minimum number of active connections that can remain idle in the
171      * pool, without extra ones being created, or 0 to create none.
172      */
173     protected int minIdle = GenericObjectPool.DEFAULT_MIN_IDLE;;
174 
175     public synchronized int getMinIdle() {
176         return this.minIdle;
177     }
178 
179     public synchronized void setMinIdle(int minIdle) {
180        this.minIdle = minIdle;
181        if (connectionPool != null) {
182            connectionPool.setMinIdle(minIdle);
183        }
184     }
185 
186     /**
187      * The initial number of connections that are created when the pool
188      * is started.
189      * @since 1.2
190      */
191     protected int initialSize = 0;
192     
193     public synchronized int getInitialSize() {
194         return this.initialSize;
195     }
196     
197     public synchronized void setInitialSize(int initialSize) {
198         this.initialSize = initialSize;
199         this.restartNeeded = true;
200     }
201 
202     /**
203      * The maximum number of milliseconds that the pool will wait (when there
204      * are no available connections) for a connection to be returned before
205      * throwing an exception, or -1 to wait indefinitely.
206      */
207     protected long maxWait = GenericObjectPool.DEFAULT_MAX_WAIT;
208 
209     public synchronized long getMaxWait() {
210         return this.maxWait;
211     }
212 
213     public synchronized void setMaxWait(long maxWait) {
214         this.maxWait = maxWait;
215         if (connectionPool != null) {
216             connectionPool.setMaxWait(maxWait);
217         }
218     }
219 
220     /**
221      * Prepared statement pooling for this pool.
222      */
223     protected boolean poolPreparedStatements = false;
224     
225     /**
226      * Returns true if we are pooling statements.
227      * @return boolean
228      */
229     public synchronized boolean isPoolPreparedStatements() {
230         return this.poolPreparedStatements;
231     }
232 
233     /**
234      * Sets whether to pool statements or not.
235      * @param poolPreparedStatements pooling on or off
236      */
237     public synchronized void setPoolPreparedStatements(boolean poolingStatements) {
238         this.poolPreparedStatements = poolingStatements;
239         this.restartNeeded = true;
240     }
241 
242     /**
243      * The maximum number of open statements that can be allocated from
244      * the statement pool at the same time, or zero for no limit.  Since 
245      * a connection usually only uses one or two statements at a time, this is
246      * mostly used to help detect resource leaks.
247      */
248     protected int maxOpenPreparedStatements = GenericKeyedObjectPool.DEFAULT_MAX_TOTAL;
249 
250     public synchronized int getMaxOpenPreparedStatements() {
251         return this.maxOpenPreparedStatements;
252     }
253 
254     public synchronized void setMaxOpenPreparedStatements(int maxOpenStatements) {
255         this.maxOpenPreparedStatements = maxOpenStatements;
256         this.restartNeeded = true;
257     }
258 
259     /**
260      * The indication of whether objects will be validated before being
261      * borrowed from the pool.  If the object fails to validate, it will be
262      * dropped from the pool, and we will attempt to borrow another.
263      */
264     protected boolean testOnBorrow = true;
265 
266     public synchronized boolean getTestOnBorrow() {
267         return this.testOnBorrow;
268     }
269 
270     public synchronized void setTestOnBorrow(boolean testOnBorrow) {
271         this.testOnBorrow = testOnBorrow;
272         if (connectionPool != null) {
273             connectionPool.setTestOnBorrow(testOnBorrow);
274         }
275     }
276 
277     /**
278      * The indication of whether objects will be validated before being
279      * returned to the pool.
280      */
281     protected boolean testOnReturn = false;
282 
283     public synchronized boolean getTestOnReturn() {
284         return this.testOnReturn;
285     }
286 
287     public synchronized void setTestOnReturn(boolean testOnReturn) {
288         this.testOnReturn = testOnReturn;
289         if (connectionPool != null) {
290             connectionPool.setTestOnReturn(testOnReturn);
291         }
292     }
293 
294 
295     /**
296      * The number of milliseconds to sleep between runs of the idle object
297      * evictor thread.  When non-positive, no idle object evictor thread will
298      * be run.
299      */
300     protected long timeBetweenEvictionRunsMillis =
301         GenericObjectPool.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
302         
303     public synchronized long getTimeBetweenEvictionRunsMillis() {
304         return this.timeBetweenEvictionRunsMillis;
305     }
306 
307     public synchronized void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) {
308         this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
309         if (connectionPool != null) {
310             connectionPool.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
311         }
312     }
313 
314 
315     /**
316      * The number of objects to examine during each run of the idle object
317      * evictor thread (if any).
318      */
319     protected int numTestsPerEvictionRun =
320         GenericObjectPool.DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
321 
322     public synchronized int getNumTestsPerEvictionRun() {
323         return this.numTestsPerEvictionRun;
324     }
325 
326     public synchronized void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) {
327         this.numTestsPerEvictionRun = numTestsPerEvictionRun;
328         if (connectionPool != null) {
329             connectionPool.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
330         }
331     }
332 
333 
334     /**
335      * The minimum amount of time an object may sit idle in the pool before it
336      * is eligable for eviction by the idle object evictor (if any).
337      */
338     protected long minEvictableIdleTimeMillis =
339         GenericObjectPool.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
340 
341     public synchronized long getMinEvictableIdleTimeMillis() {
342         return this.minEvictableIdleTimeMillis;
343     }
344 
345     public synchronized void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) {
346         this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
347         if (connectionPool != null) {
348             connectionPool.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
349         }
350     }
351 
352     /**
353      * The indication of whether objects will be validated by the idle object
354      * evictor (if any).  If an object fails to validate, it will be dropped
355      * from the pool.
356      */
357     protected boolean testWhileIdle = false;
358 
359     public synchronized boolean getTestWhileIdle() {
360         return this.testWhileIdle;
361     }
362 
363     public synchronized void setTestWhileIdle(boolean testWhileIdle) {
364         this.testWhileIdle = testWhileIdle;
365         if (connectionPool != null) {
366             connectionPool.setTestWhileIdle(testWhileIdle);
367         }
368     }
369 
370     /**
371      * [Read Only] The current number of active connections that have been
372      * allocated from this data source.
373      */
374     public synchronized int getNumActive() {
375         if (connectionPool != null) {
376             return connectionPool.getNumActive();
377         } else {
378             return 0;
379         }
380     }
381 
382 
383     /**
384      * [Read Only] The current number of idle connections that are waiting
385      * to be allocated from this data source.
386      */
387     public synchronized int getNumIdle() {
388         if (connectionPool != null) {
389             return connectionPool.getNumIdle();
390         } else {
391             return 0;
392         }
393     }
394 
395 
396     /**
397      * The connection password to be passed to our JDBC driver to establish
398      * a connection.
399      */
400     protected String password = null;
401 
402     public synchronized String getPassword() {
403         return this.password;
404     }
405 
406     public synchronized void setPassword(String password) {
407         this.password = password;
408         this.restartNeeded = true;
409     }
410 
411 
412     /**
413      * The connection URL to be passed to our JDBC driver to establish
414      * a connection.
415      */
416     protected String url = null;
417 
418     public synchronized String getUrl() {
419         return this.url;
420     }
421 
422     public synchronized void setUrl(String url) {
423         this.url = url;
424         this.restartNeeded = true;
425     }
426 
427 
428     /**
429      * The connection username to be passed to our JDBC driver to
430      * establish a connection.
431      */
432     protected String username = null;
433 
434     public synchronized String getUsername() {
435         return this.username;
436     }
437 
438     public synchronized void setUsername(String username) {
439         this.username = username;
440         this.restartNeeded = true;
441     }
442 
443 
444     /**
445      * The SQL query that will be used to validate connections from this pool
446      * before returning them to the caller.  If specified, this query
447      * <strong>MUST</strong> be an SQL SELECT statement that returns at least
448      * one row.
449      */
450     protected String validationQuery = null;
451 
452     public synchronized String getValidationQuery() {
453         return this.validationQuery;
454     }
455 
456     public synchronized void setValidationQuery(String validationQuery) {
457         if ((validationQuery != null) && (validationQuery.trim().length() > 0)) {
458             this.validationQuery = validationQuery;
459         } else {
460             this.validationQuery = null;
461         }
462         this.restartNeeded = true;
463     }
464 
465     /** 
466      * Controls access to the underlying connection 
467      */
468     private boolean accessToUnderlyingConnectionAllowed = false; 
469 
470     /**
471      * Returns the value of the accessToUnderlyingConnectionAllowed property.
472      * 
473      * @return true if access to the underlying is allowed, false otherwise.
474      */
475     public synchronized boolean isAccessToUnderlyingConnectionAllowed() {
476         return this.accessToUnderlyingConnectionAllowed;
477     }
478 
479     /**
480      * Sets the value of the accessToUnderlyingConnectionAllowed property.
481      * It controls if the PoolGuard allows access to the underlying connection.
482      * (Default: false)
483      * 
484      * @param allow Access to the underlying connection is granted when true.
485      */
486     public synchronized void setAccessToUnderlyingConnectionAllowed(boolean allow) {
487         this.accessToUnderlyingConnectionAllowed = allow;
488         this.restartNeeded = true;
489     }
490 
491     // ----------------------------------------------------- Instance Variables
492 
493     // TODO: review & make isRestartNeeded() public, restartNeeded protected
494 
495     private boolean restartNeeded = false;
496     
497     /**
498      * Returns whether or not a restart is needed.
499      * @return true if a restart is needed
500      */
501     private synchronized boolean isRestartNeeded() {
502         return restartNeeded;
503     }
504 
505     /**
506      * The object pool that internally manages our connections.
507      */
508     protected GenericObjectPool connectionPool = null;
509     
510     /**
511      * The connection properties that will be sent to our JDBC driver when
512      * establishing new connections.  <strong>NOTE</strong> - The "user" and
513      * "password" properties will be passed explicitly, so they do not need
514      * to be included here.
515      */
516     protected Properties connectionProperties = new Properties();
517 
518     /**
519      * The data source we will use to manage connections.  This object should
520      * be acquired <strong>ONLY</strong> by calls to the
521      * <code>createDataSource()</code> method.
522      */
523     protected DataSource dataSource = null;
524 
525     /**
526      * The PrintWriter to which log messages should be directed.
527      */
528     protected PrintWriter logWriter = new PrintWriter(System.out);
529 
530 
531     // ----------------------------------------------------- DataSource Methods
532 
533 
534     /**
535      * Create (if necessary) and return a connection to the database.
536      *
537      * @exception SQLException if a database access error occurs
538      */
539     public Connection getConnection() throws SQLException {
540         return createDataSource().getConnection();
541     }
542 
543 
544     /**
545      * Create (if necessary) and return a connection to the database.
546      *
547      * @param username Database user on whose behalf the Connection
548      *   is being made
549      * @param password The database user's password
550      *
551      * @exception SQLException if a database access error occurs
552      */
553     public Connection getConnection(String username, String password) throws SQLException {
554         return createDataSource().getConnection(username, password);
555     }
556 
557 
558     /**
559      * Return the login timeout (in seconds) for connecting to the database.
560      *
561      * @exception SQLException if a database access error occurs
562      */
563     public int getLoginTimeout() throws SQLException {
564         return createDataSource().getLoginTimeout();
565     }
566 
567 
568     /**
569      * Return the log writer being used by this data source.
570      *
571      * @exception SQLException if a database access error occurs
572      */
573     public PrintWriter getLogWriter() throws SQLException {
574         return createDataSource().getLogWriter();
575     }
576 
577 
578     /**
579      * Set the login timeout (in seconds) for connecting to the database.
580      *
581      * @param loginTimeout The new login timeout, or zero for no timeout
582      *
583      * @exception SQLException if a database access error occurs
584      */
585     public void setLoginTimeout(int loginTimeout) throws SQLException {
586         createDataSource().setLoginTimeout(loginTimeout);
587     }
588 
589 
590     /**
591      * Set the log writer being used by this data source.
592      *
593      * @param logWriter The new log writer
594      *
595      * @exception SQLException if a database access error occurs
596      */
597     public void setLogWriter(PrintWriter logWriter) throws SQLException {
598         createDataSource().setLogWriter(logWriter);
599         this.logWriter = logWriter;
600     }
601 
602     private AbandonedConfig abandonedConfig;
603 
604     /**                       
605      * Flag to remove abandoned connections if they exceed the
606      * removeAbandonedTimout.
607      *
608      * Set to true or false, default false.
609      * If set to true a connection is considered abandoned and eligible
610      * for removal if it has been idle longer than the removeAbandonedTimeout.
611      * Setting this to true can recover db connections from poorly written    
612      * applications which fail to close a connection.      
613      * @deprecated                   
614      */                                                                   
615     public boolean getRemoveAbandoned() {   
616         if (abandonedConfig != null) {
617             return abandonedConfig.getRemoveAbandoned();
618         }
619         return false;
620     }                                    
621                                  
622     /**
623      * @deprecated
624      * @param removeAbandoned
625      */
626     public void setRemoveAbandoned(boolean removeAbandoned) {
627         if (abandonedConfig == null) {
628             abandonedConfig = new AbandonedConfig();
629         }
630         abandonedConfig.setRemoveAbandoned(removeAbandoned);
631         this.restartNeeded = true;
632     }                                                        
633                                                
634     /**
635      * Timeout in seconds before an abandoned connection can be removed.
636      *
637      * Defaults to 300 seconds.         
638      * @deprecated                                
639      */                                                                 
640     public int getRemoveAbandonedTimeout() { 
641         if (abandonedConfig != null) {
642             return abandonedConfig.getRemoveAbandonedTimeout();
643         }
644         return 300;
645     }                                        
646 
647     /**
648      * @deprecated
649      * @param removeAbandonedTimeout
650      */               
651     public void setRemoveAbandonedTimeout(int removeAbandonedTimeout) {
652         if (abandonedConfig == null) {
653             abandonedConfig = new AbandonedConfig();
654         }
655         abandonedConfig.setRemoveAbandonedTimeout(removeAbandonedTimeout);
656         this.restartNeeded = true;
657     }                                                                  
658                                                              
659     /**
660      * Flag to log stack traces for application code which abandoned
661      * a Statement or Connection.
662      *
663      * Defaults to false.                
664      *                                                              
665      * Logging of abandoned Statements and Connections adds overhead
666      * for every Connection open or new Statement because a stack   
667      * trace has to be generated.             
668      * @deprecated                      
669      */                                                          
670     public boolean getLogAbandoned() {   
671         if (abandonedConfig != null) {
672             return abandonedConfig.getLogAbandoned();
673         }
674         return false;
675     }                                 
676 
677     /**
678      * @deprecated
679      * @param logAbandoned
680      */
681     public void setLogAbandoned(boolean logAbandoned) {
682         if (abandonedConfig == null) {
683             abandonedConfig = new AbandonedConfig();
684         }
685         abandonedConfig.setLogAbandoned(logAbandoned);
686         this.restartNeeded = true;
687     }
688 
689     // --------------------------------------------------------- Public Methods
690 
691     /**
692      * Add a custom connection property to the set that will be passed to our
693      * JDBC driver.    This <strong>MUST</strong> be called before the first
694      * connection is retrieved (along with all the other configuration
695      * property setters).
696      *
697      * @param name Name of the custom connection property
698      * @param value Value of the custom connection property
699      */
700     public void addConnectionProperty(String name, String value) {
701         connectionProperties.put(name, value);
702         this.restartNeeded = true;
703     }
704 
705     public void removeConnectionProperty(String name) {
706         connectionProperties.remove(name);
707         this.restartNeeded = true;
708     }
709 
710     /**
711      * Close and release all connections that are currently stored in the
712      * connection pool associated with our data source.
713      *
714      * @exception SQLException if a database error occurs
715      */
716     public synchronized void close() throws SQLException {
717         GenericObjectPool oldpool = connectionPool;
718         connectionPool = null;
719         dataSource = null;
720         try {
721             if (oldpool != null) {
722                 oldpool.close();
723             }
724         } catch(SQLException e) {
725             throw e;
726         } catch(RuntimeException e) {
727             throw e;
728         } catch(Exception e) {
729             throw new SQLNestedException("Cannot close connection pool", e);
730         }
731     }
732 
733 
734     // ------------------------------------------------------ Protected Methods
735 
736 
737     /**
738      * <p>Create (if necessary) and return the internal data source we are
739      * using to manage our connections.</p>
740      *
741      * <p><strong>IMPLEMENTATION NOTE</strong> - It is tempting to use the
742      * "double checked locking" idiom in an attempt to avoid synchronizing
743      * on every single call to this method.  However, this idiom fails to
744      * work correctly in the face of some optimizations that are legal for
745      * a JVM to perform.</p>
746      *
747      * @exception SQLException if the object pool cannot be created.
748      */
749     protected synchronized DataSource createDataSource()
750         throws SQLException {
751 
752         // Return the pool if we have already created it
753         if (dataSource != null) {
754             return (dataSource);
755         }
756 
757         // Load the JDBC driver class
758         if (driverClassName != null) {
759             try {
760                 Class.forName(driverClassName);
761             } catch (Throwable t) {
762                 String message = "Cannot load JDBC driver class '" +
763                     driverClassName + "'";
764                 logWriter.println(message);
765                 t.printStackTrace(logWriter);
766                 throw new SQLNestedException(message, t);
767             }
768         }
769 
770         // Create a JDBC driver instance
771         Driver driver = null;
772         try {
773             driver = DriverManager.getDriver(url);
774         } catch (Throwable t) {
775             String message = "Cannot create JDBC driver of class '" +
776                 (driverClassName != null ? driverClassName : "") + 
777                 "' for connect URL '" + url + "'";
778             logWriter.println(message);
779             t.printStackTrace(logWriter);
780             throw new SQLNestedException(message, t);
781         }
782 
783         // Can't test without a validationQuery
784         if (validationQuery == null) {
785             setTestOnBorrow(false);
786             setTestOnReturn(false);
787             setTestWhileIdle(false);
788         }
789 
790         // Create an object pool to contain our active connections
791         if ((abandonedConfig != null) && (abandonedConfig.getRemoveAbandoned() == true)) {
792             connectionPool = new AbandonedObjectPool(null,abandonedConfig);
793         }
794         else {
795             connectionPool = new GenericObjectPool();
796         }
797         connectionPool.setMaxActive(maxActive);
798         connectionPool.setMaxIdle(maxIdle);
799         connectionPool.setMinIdle(minIdle);
800         connectionPool.setMaxWait(maxWait);
801         connectionPool.setTestOnBorrow(testOnBorrow);
802         connectionPool.setTestOnReturn(testOnReturn);
803         connectionPool.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
804         connectionPool.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
805         connectionPool.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
806         connectionPool.setTestWhileIdle(testWhileIdle);
807         
808         // Set up statement pool, if desired
809         GenericKeyedObjectPoolFactory statementPoolFactory = null;
810         if (isPoolPreparedStatements()) {
811             statementPoolFactory = new GenericKeyedObjectPoolFactory(null, 
812                         -1, // unlimited maxActive (per key)
813                         GenericKeyedObjectPool.WHEN_EXHAUSTED_FAIL, 
814                         0, // maxWait
815                         1, // maxIdle (per key) 
816                         maxOpenPreparedStatements); 
817         }
818 
819         // Set up the driver connection factory we will use
820         if (username != null) {
821             connectionProperties.put("user", username);
822         } else {
823             log("DBCP DataSource configured without a 'username'");
824         }
825         
826         if (password != null) {
827             connectionProperties.put("password", password);
828         } else {
829             log("DBCP DataSource configured without a 'password'");
830         }
831         
832         DriverConnectionFactory driverConnectionFactory =
833             new DriverConnectionFactory(driver, url, connectionProperties);
834 
835         // Set up the poolable connection factory we will use
836         PoolableConnectionFactory connectionFactory = null;
837         try {
838             connectionFactory =
839                 new PoolableConnectionFactory(driverConnectionFactory,
840                                               connectionPool,
841                                               statementPoolFactory,
842                                               validationQuery,
843                                               defaultReadOnly,
844                                               defaultAutoCommit,
845                                               defaultTransactionIsolation,
846                                               defaultCatalog,
847                                               abandonedConfig);
848             if (connectionFactory == null) {
849                 throw new SQLException("Cannot create PoolableConnectionFactory");
850             }
851             validateConnectionFactory(connectionFactory);
852         } catch (RuntimeException e) {
853             throw e;
854         } catch (Exception e) {
855             throw new SQLNestedException("Cannot create PoolableConnectionFactory (" + e.getMessage() + ")", e);
856         }
857 
858         // Create and return the pooling data source to manage the connections
859         dataSource = new PoolingDataSource(connectionPool);
860         ((PoolingDataSource) dataSource).setAccessToUnderlyingConnectionAllowed(isAccessToUnderlyingConnectionAllowed());
861         dataSource.setLogWriter(logWriter);
862         
863         try {
864             for (int i = 0 ; i < initialSize ; i++) {
865                 connectionPool.addObject();
866             }
867         } catch (Exception e) {
868             throw new SQLNestedException("Error preloading the connection pool", e);
869         }
870         
871         return dataSource;
872     }
873 
874     private static void validateConnectionFactory(PoolableConnectionFactory connectionFactory) throws Exception {
875         Connection conn = null;
876         try {
877             conn = (Connection) connectionFactory.makeObject();
878             connectionFactory.activateObject(conn);
879             connectionFactory.validateConnection(conn);
880             connectionFactory.passivateObject(conn);
881         }
882         finally {
883             connectionFactory.destroyObject(conn);
884         }
885     }
886 
887     private void restart() {
888         try {
889             close();
890         } catch (SQLException e) {
891             log("Could not restart DataSource, cause: " + e.getMessage());
892         }
893     }
894 
895     private void log(String message) {
896         if (logWriter != null) {
897             logWriter.println(message);
898         }
899     }
900 }