Save This Page
Home » commons-dbcp-1.4-src » org.apache.commons » dbcp » [javadoc | source]
    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    * 
    9    *      http://www.apache.org/licenses/LICENSE-2.0
   10    * 
   11    * Unless required by applicable law or agreed to in writing, software
   12    * distributed under the License is distributed on an "AS IS" BASIS,
   13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    * See the License for the specific language governing permissions and
   15    * limitations under the License.
   16    */
   17   
   18   package org.apache.commons.dbcp;
   19   
   20   import java.io.PrintWriter;
   21   import java.util.Properties;
   22   import java.util.Collection;
   23   import java.util.List;
   24   import java.util.ArrayList;
   25   import java.util.Iterator;
   26   import java.util.Collections;
   27   import java.sql.Connection;
   28   import java.sql.Driver;
   29   import java.sql.DriverManager;
   30   import java.sql.SQLException;
   31   import javax.sql.DataSource;
   32   
   33   import org.apache.commons.pool.KeyedObjectPoolFactory;
   34   import org.apache.commons.pool.impl.GenericKeyedObjectPool;
   35   import org.apache.commons.pool.impl.GenericKeyedObjectPoolFactory;
   36   import org.apache.commons.pool.impl.GenericObjectPool;
   37   
   38   
   39   /**
   40    * <p>Basic implementation of <code>javax.sql.DataSource</code> that is
   41    * configured via JavaBeans properties.  This is not the only way to
   42    * combine the <em>commons-dbcp</em> and <em>commons-pool</em> packages,
   43    * but provides a "one stop shopping" solution for basic requirements.</p>
   44    * 
   45    * <p>Users extending this class should take care to use appropriate accessors
   46    * rather than accessing protected fields directly to ensure thread-safety.</p>
   47    *
   48    * @author Glenn L. Nielsen
   49    * @author Craig R. McClanahan
   50    * @author Dirk Verbeeck
   51    * @version $Revision: 895844 $ $Date: 2010-01-04 20:50:04 -0500 (Mon, 04 Jan 2010) $
   52    */
   53   public class BasicDataSource implements DataSource {
   54       
   55       static {
   56           // Attempt to prevent deadlocks - see DBCP - 272
   57           DriverManager.getDrivers();
   58       }
   59   
   60       // ------------------------------------------------------------- Properties
   61   
   62       /**
   63        * The default auto-commit state of connections created by this pool.
   64        */
   65       protected volatile boolean defaultAutoCommit = true;
   66   
   67       /**
   68        * Returns the default auto-commit property.
   69        * 
   70        * @return true if default auto-commit is enabled
   71        */
   72       public boolean getDefaultAutoCommit() {
   73           return this.defaultAutoCommit;
   74       }
   75   
   76       /**
   77        * <p>Sets default auto-commit state of connections returned by this
   78        * datasource.</p>
   79        * <p>
   80        * Note: this method currently has no effect once the pool has been
   81        * initialized.  The pool is initialized the first time one of the
   82        * following methods is invoked: <code>getConnection, setLogwriter,
   83        * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
   84        * 
   85        * @param defaultAutoCommit default auto-commit value
   86        */
   87       public void setDefaultAutoCommit(boolean defaultAutoCommit) {
   88           this.defaultAutoCommit = defaultAutoCommit;
   89           this.restartNeeded = true;
   90       }
   91   
   92   
   93       /**
   94        * The default read-only state of connections created by this pool.
   95        */
   96       protected transient Boolean defaultReadOnly = null;
   97   
   98       /**
   99        * Returns the default readOnly property.
  100        * 
  101        * @return true if connections are readOnly by default
  102        */
  103       public boolean getDefaultReadOnly() {
  104           Boolean val = defaultReadOnly;
  105           if (val != null) {
  106               return val.booleanValue();
  107           }
  108           return false;
  109       }
  110   
  111       /**
  112        * <p>Sets defaultReadonly property.</p>
  113        * <p>
  114        * Note: this method currently has no effect once the pool has been
  115        * initialized.  The pool is initialized the first time one of the
  116        * following methods is invoked: <code>getConnection, setLogwriter,
  117        * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
  118        * 
  119        * @param defaultReadOnly default read-only value
  120        */
  121       public void setDefaultReadOnly(boolean defaultReadOnly) {
  122           this.defaultReadOnly = defaultReadOnly ? Boolean.TRUE : Boolean.FALSE;
  123           this.restartNeeded = true;
  124       }
  125   
  126       /**
  127        * The default TransactionIsolation state of connections created by this pool.
  128        */
  129       protected volatile int defaultTransactionIsolation =
  130           PoolableConnectionFactory.UNKNOWN_TRANSACTIONISOLATION;
  131   
  132       /**
  133        * Returns the default transaction isolation state of returned connections.
  134        * 
  135        * @return the default value for transaction isolation state
  136        * @see Connection#getTransactionIsolation
  137        */
  138       public int getDefaultTransactionIsolation() {
  139           return this.defaultTransactionIsolation;
  140       }
  141   
  142       /**
  143        * <p>Sets the default transaction isolation state for returned
  144        * connections.</p>
  145        * <p>
  146        * Note: this method currently has no effect once the pool has been
  147        * initialized.  The pool is initialized the first time one of the
  148        * following methods is invoked: <code>getConnection, setLogwriter,
  149        * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
  150        * 
  151        * @param defaultTransactionIsolation the default transaction isolation
  152        * state
  153        * @see Connection#getTransactionIsolation
  154        */
  155       public void setDefaultTransactionIsolation(int defaultTransactionIsolation) {
  156           this.defaultTransactionIsolation = defaultTransactionIsolation;
  157           this.restartNeeded = true;
  158       }
  159   
  160   
  161       /**
  162        * The default "catalog" of connections created by this pool.
  163        */
  164       protected volatile String defaultCatalog = null;
  165   
  166       /**
  167        * Returns the default catalog.
  168        * 
  169        * @return the default catalog
  170        */
  171       public String getDefaultCatalog() {
  172           return this.defaultCatalog;
  173       }
  174   
  175       /**
  176        * <p>Sets the default catalog.</p>
  177        * <p>
  178        * Note: this method currently has no effect once the pool has been
  179        * initialized.  The pool is initialized the first time one of the
  180        * following methods is invoked: <code>getConnection, setLogwriter,
  181        * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
  182        * 
  183        * @param defaultCatalog the default catalog
  184        */
  185       public void setDefaultCatalog(String defaultCatalog) {
  186           if ((defaultCatalog != null) && (defaultCatalog.trim().length() > 0)) {
  187               this.defaultCatalog = defaultCatalog;
  188           }
  189           else {
  190               this.defaultCatalog = null;
  191           }
  192           this.restartNeeded = true;
  193       }
  194   
  195     
  196       /**
  197        * The fully qualified Java class name of the JDBC driver to be used.
  198        */
  199       protected String driverClassName = null;
  200   
  201       /**
  202        * Returns the jdbc driver class name.
  203        * 
  204        * @return the jdbc driver class name
  205        */
  206       public synchronized String getDriverClassName() {
  207           return this.driverClassName;
  208       }
  209   
  210       /**
  211        * <p>Sets the jdbc driver class name.</p>
  212        * <p>
  213        * Note: this method currently has no effect once the pool has been
  214        * initialized.  The pool is initialized the first time one of the
  215        * following methods is invoked: <code>getConnection, setLogwriter,
  216        * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
  217        * 
  218        * @param driverClassName the class name of the jdbc driver
  219        */
  220       public synchronized void setDriverClassName(String driverClassName) {
  221           if ((driverClassName != null) && (driverClassName.trim().length() > 0)) {
  222               this.driverClassName = driverClassName;
  223           }
  224           else {
  225               this.driverClassName = null;
  226           }
  227           this.restartNeeded = true;
  228       }
  229   
  230       /**
  231        * The class loader instance to use to load the JDBC driver. If not
  232        * specified, {@link Class#forName(String)} is used to load the JDBC driver.
  233        * If specified, {@link Class#forName(String, boolean, ClassLoader)} is
  234        * used.
  235        */
  236       protected ClassLoader driverClassLoader = null;
  237       
  238       /**
  239        * Returns the class loader specified for loading the JDBC driver. Returns
  240        * <code>null</code> if no class loader has been explicitly specified.
  241        */
  242       public synchronized ClassLoader getDriverClassLoader() {
  243           return this.driverClassLoader;
  244       }
  245   
  246       /**
  247        * <p>Sets the class loader to be used to load the JDBC driver.</p>
  248        * <p>
  249        * Note: this method currently has no effect once the pool has been
  250        * initialized.  The pool is initialized the first time one of the
  251        * following methods is invoked: <code>getConnection, setLogwriter,
  252        * setLoginTimeout, getLoginTimeout, getLogWriter.</code></p>
  253        * 
  254        * @param driverClassLoader the class loader with which to load the JDBC
  255        *                          driver
  256        */
  257       public synchronized void setDriverClassLoader(
  258               ClassLoader driverClassLoader) {
  259           this.driverClassLoader = driverClassLoader;
  260           this.restartNeeded = true;
  261       }
  262       
  263       /**
  264        * The maximum number of active connections that can be allocated from
  265        * this pool at the same time, or negative for no limit.
  266        */
  267       protected int maxActive = GenericObjectPool.DEFAULT_MAX_ACTIVE;
  268   
  269       /**
  270        * <p>Returns the maximum number of active connections that can be
  271        * allocated at the same time.
  272        * </p>
  273        * <p>A negative number means that there is no limit.</p>
  274        * 
  275        * @return the maximum number of active connections
  276        */
  277       public synchronized int getMaxActive() {
  278           return this.maxActive;
  279       }
  280   
  281       /**
  282        * Sets the maximum number of active connections that can be
  283        * allocated at the same time. Use a negative value for no limit.
  284        * 
  285        * @param maxActive the new value for maxActive
  286        * @see #getMaxActive()
  287        */
  288       public synchronized void setMaxActive(int maxActive) {
  289           this.maxActive = maxActive;
  290           if (connectionPool != null) {
  291               connectionPool.setMaxActive(maxActive);
  292           }
  293       }
  294   
  295       /**
  296        * The maximum number of connections that can remain idle in the
  297        * pool, without extra ones being 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       /* JDBC_4_ANT_KEY_BEGIN */
 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       /* JDBC_4_ANT_KEY_END */
 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   }

Save This Page
Home » commons-dbcp-1.4-src » org.apache.commons » dbcp » [javadoc | source]