You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by jm...@apache.org on 2002/03/04 08:52:38 UTC

cvs commit: jakarta-commons-sandbox/jdbc2pool/src/java/org/apache/commons/jdbc2pool CPDSConnectionFactory.java TorqueClassicDataSource.java Jdbc2PoolDataSource.java

jmcnally    02/03/03 23:52:38

  Modified:    jdbc2pool build.xml default.properties
               jdbc2pool/src/java/org/apache/commons/jdbc2pool
                        Jdbc2PoolDataSource.java
  Added:       jdbc2pool/src/java/org/apache/commons/jdbc2pool
                        CPDSConnectionFactory.java
                        TorqueClassicDataSource.java
  Log:
  switched Jdbc2PoolDataSource to use a pool from the commons pool package.
  Moved the version based on torque's connection pool to a new class.
  
  Revision  Changes    Path
  1.3       +4 -0      jakarta-commons-sandbox/jdbc2pool/build.xml
  
  Index: build.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/jdbc2pool/build.xml,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- build.xml	26 Jan 2002 22:24:47 -0000	1.2
  +++ build.xml	4 Mar 2002 07:52:37 -0000	1.3
  @@ -14,6 +14,8 @@
       <pathelement location="${jdbc.jar}"/>
       <pathelement location="${log4j.jar}"/>
       <pathelement location="${commons-util.jar}"/>
  +    <pathelement location="${commons-pool.jar}"/>
  +    <pathelement location="${commons-dbcp.jar}"/>
       <pathelement location="${junit.jar}"/>
     </path>
   
  @@ -29,6 +31,8 @@
       <echo message="jdbc.jar = ${jdbc.jar}"/>
       <echo message="junit.jar = ${junit.jar}"/>
       <echo message="commons-util.jar = ${commons-util.jar}"/>
  +    <echo message="commons-pool.jar = ${commons-pool.jar}"/>
  +    <echo message="commons-dbcp.jar = ${commons-dbcp.jar}"/>
     </target>
   
     <!-- ================================================================== -->
  
  
  
  1.3       +2 -0      jakarta-commons-sandbox/jdbc2pool/default.properties
  
  Index: default.properties
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/jdbc2pool/default.properties,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- default.properties	26 Jan 2002 22:24:47 -0000	1.2
  +++ default.properties	4 Mar 2002 07:52:37 -0000	1.3
  @@ -31,6 +31,8 @@
   
   log4j.jar = ${lib.repo}/log4j-1.1.3.jar
   commons-util.jar = ${lib.repo}/commons-util-0.1-dev.jar
  +commons-pool.jar = ${lib.repo}/commons-pool.jar
  +commons-dbcp.jar = ${lib.repo}/commons-dbcp.jar
   jdbc.jar = ${lib.repo}/jdbc2_0-stdext.jar
   junit.jar = ${lib.repo}/junit-3.7.jar
   
  
  
  
  1.3       +453 -108  jakarta-commons-sandbox/jdbc2pool/src/java/org/apache/commons/jdbc2pool/Jdbc2PoolDataSource.java
  
  Index: Jdbc2PoolDataSource.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/jdbc2pool/src/java/org/apache/commons/jdbc2pool/Jdbc2PoolDataSource.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- Jdbc2PoolDataSource.java	17 Jan 2002 05:44:26 -0000	1.2
  +++ Jdbc2PoolDataSource.java	4 Mar 2002 07:52:37 -0000	1.3
  @@ -69,6 +69,7 @@
   import java.sql.SQLException;
   import javax.sql.DataSource;
   import javax.sql.ConnectionPoolDataSource;
  +import javax.sql.PooledConnection;
   import javax.naming.Name;
   import javax.naming.Context;
   import javax.naming.InitialContext;
  @@ -81,16 +82,23 @@
   import javax.naming.spi.ObjectFactory;
   
   import org.apache.commons.util.ObjectUtils;
  +import org.apache.commons.pool.ObjectPool;
  +import org.apache.commons.pool.impl.GenericObjectPool;
   
   /**
  - * Torque's default connection pool DataSource
  + * DataSource that pools PooledConnection's from a 
  + * ConnectionPoolDataSource.
    *
    * @author <a href="mailto:jmcnally@collab.net">John D. McNally</a>
  - * @version $Id: Jdbc2PoolDataSource.java,v 1.2 2002/01/17 05:44:26 jmcnally Exp $
  + * @version $Id: Jdbc2PoolDataSource.java,v 1.3 2002/03/04 07:52:37 jmcnally Exp $
    */
   public class Jdbc2PoolDataSource
       implements DataSource, Referenceable, Serializable, ObjectFactory
   {
  +    private static final String GET_CONNECTION_CALLED = 
  +        "A Connection was already requested from this source, " + 
  +        "further initialization is not allowed.";
  +
       /** Pools keyed by username. */
       private static Map pools = new HashMap(); 
   
  @@ -110,122 +118,162 @@
       /** Environment that may be used to set up a jndi initial context. */
       private Properties jndiEnvironment;
   
  -    private int defaultMaxConnections;
  -    private Properties perUserMaxConnections;
  -    private int maxExpiryTime;
  -    private int connectionWaitTimeout;
  +
       private int logInterval;
       private boolean defaultAutoCommit;
       private boolean defaultReadOnly;
   
  +    private boolean getConnectionCalled = false;
  +
       /**
        * Default no-arg constructor for Serialization
        */
       public Jdbc2PoolDataSource() 
       {
  -        defaultAutoCommit = true;
       }
   
  +    /**
  +     * Throws an IllegalStateException, if a PooledConnection has already
  +     * been requested.
  +     */
  +    private void assertInitializationAllowed()
  +        throws IllegalStateException 
  +    {
  +        if (getConnectionCalled) 
  +        {
  +            throw new IllegalStateException(GET_CONNECTION_CALLED);
  +        }
  +    }
  +
  +    // -------------------------------------------------------------------
       // Properties
           
       /**
  -     * Get the number of database connections to cache per user.
  +     * The maximum number of active connections that can be allocated from
  +     * this pool at the same time, or zero for no limit.
        * This value is used for any username which is not specified
  -     * in perUserMaxConnections.  The default is 1.
  -     *
  -     * @return value of maxConnections.
  +     * in perUserMaxConnections.  The default is 0.
        */
  -    public int getDefaultMaxConnections() 
  -    {
  -        return defaultMaxConnections;
  +    private int defaultMaxActive = 0;
  +
  +    public int getDefaultMaxActive() {
  +        return (this.defaultMaxActive);
       }
  -    
  +
  +    public void setDefaultMaxActive(int maxActive) {
  +        assertInitializationAllowed();
  +        this.defaultMaxActive = maxActive;
  +    }
  +
       /**
  -     * Set the number of database connections to cache per user.
  +     * The maximum number of active connections that can remain idle in the
  +     * pool, without extra ones being released, or zero for no limit.
        * This value is used for any username which is not specified
  -     * in perUserMaxConnections.  The default is 1.
  -     *
  -     * @param v  Value to assign to maxConnections.
  +     * in perUserMaxIdle.  The default is 0.
        */
  -    public void setDefaultMaxConnections(int  v) 
  -    {
  -        this.defaultMaxConnections = v;
  +    private int defaultMaxIdle = 0;
  +
  +    public int getDefaultMaxIdle() {
  +        return (this.defaultMaxIdle);
       }
  -    
  -    
  +
  +    public void setDefaultMaxIdle(int defaultMaxIdle) {
  +        assertInitializationAllowed();
  +        this.defaultMaxIdle = defaultMaxIdle;
  +    }
  +
       /**
  -     * Get the number of database connections to cache per user.  The keys
  -     * are usernames and the value is the maximum connections.  Any username
  -     * specified here will override the value of defaultMaxConnections.
  -     *
  -     * @return value of perUserMaxConnections.
  +     * The maximum number of milliseconds that the pool will wait (when there
  +     * are no available connections) for a connection to be returned before
  +     * throwing an exception, or -1 to wait indefinitely.
  +     * This value is used for any username which is not specified
  +     * in perUserMaxWait.  The default is -1.
  +     */
  +    private int defaultMaxWait = -1;
  +
  +    public int getDefaultMaxWait() {
  +        return (this.defaultMaxWait);
  +    }
  +
  +    public void setDefaultMaxWait(int defaultMaxWait) {
  +        assertInitializationAllowed();
  +        this.defaultMaxWait = defaultMaxWait;
  +    }
  +
  +    private Properties perUserMaxActive;    
  +    /**
  +     * The maximum number of active connections that can be allocated from
  +     * this pool at the same time, or zero for no limit.
  +     * The keys are usernames and the value is the maximum connections.  Any 
  +     * username specified here will override the value of defaultMaxActive.
        */
  -    public Properties getPerUserMaxConnections() 
  +    public Properties getPerUserMaxActive() 
       {
  -        return perUserMaxConnections;
  +        return perUserMaxActive;
       }
       
       /**
  -     * Set the number of database connections to cache per user.  The keys
  -     * are usernames and the value is the maximum connections.  Any username
  -     * specified here will override the value of defaultMaxConnections.
  -     * 
  -     * @param v  Value to assign to perUserMaxConnections.
  +     * The maximum number of active connections that can be allocated from
  +     * this pool at the same time, or zero for no limit.
  +     * The keys are usernames and the value is the maximum connections.  Any 
  +     * username specified here will override the value of defaultMaxActive.
        */
  -    public void setPerUserMaxConnections(Properties  v) 
  +    public void setPerUserMaxActive(Properties  v) 
       {
  -        this.perUserMaxConnections = v;
  +        assertInitializationAllowed();
  +        this.perUserMaxActive = v;
       }
  -    
  -    
  +
  +    private Properties perUserMaxIdle;    
       /**
  -     * Get the amount of time (in seconds) that database connections 
  -     * will be cached.  The default is 3600 (1 hour).
  -     * 
  -     * @return value of expiryTime.
  +     * The maximum number of active connections that can remain idle in the
  +     * pool, without extra ones being released, or zero for no limit.
  +     * The keys are usernames and the value is the maximum connections.  Any 
  +     * username specified here will override the value of defaultMaxIdle.
        */
  -    public int getMaxExpiryTime() 
  +    public Properties getPerUserMaxIdle() 
       {
  -        return maxExpiryTime;
  +        return perUserMaxIdle;
       }
       
       /**
  -     * Set the amount of time (in seconds) that database connections 
  -     * will be cached.  The default is 3600 (1 hour).
  -     *
  -     * @param v  Value to assign to expiryTime.
  +     * The maximum number of active connections that can remain idle in the
  +     * pool, without extra ones being released, or zero for no limit.
  +     * The keys are usernames and the value is the maximum connections.  Any 
  +     * username specified here will override the value of defaultMaxIdle.
        */
  -    public void setMaxExpiryTime(int  v) 
  +    public void setPerUserMaxIdle(Properties  v) 
       {
  -        this.maxExpiryTime = v;
  +        assertInitializationAllowed();
  +        this.perUserMaxIdle = v;
       }
       
  -    
  +    private Properties perUserMaxWait;
       /**
  -     * Get the amount of time (in seconds) a connection request will  
  -     * have to wait before a time out occurs and an error is thrown.
  -     * The default is 10 seconds.
  -     *
  -     * @return value of connectionWaitTimeout.
  +     * The maximum number of milliseconds that the pool will wait (when there
  +     * are no available connections) for a connection to be returned before
  +     * throwing an exception, or -1 to wait indefinitely.
  +     * The keys are usernames and the value is the maximum connections.  Any 
  +     * username specified here will override the value of defaultMaxWait.
        */
  -    public int getConnectionWaitTimeout() 
  +    public Properties getPerUserMaxWait() 
       {
  -        return connectionWaitTimeout;
  +        return perUserMaxWait;
       }
       
       /**
  -     * Eet the amount of time (in seconds) a connection request will
  -     * have to wait before a time out occurs and an error is thrown.
  -     * The default is 10 seconds.
  -     *
  -     * @param v  Value to assign to connectionWaitTimeout.
  +     * The maximum number of milliseconds that the pool will wait (when there
  +     * are no available connections) for a connection to be returned before
  +     * throwing an exception, or -1 to wait indefinitely.
  +     * The keys are usernames and the value is the maximum connections.  Any 
  +     * username specified here will override the value of defaultMaxWait.
        */
  -    public void setConnectionWaitTimeout(int  v) 
  +    public void setPerUserMaxWait(Properties  v) 
       {
  -        this.connectionWaitTimeout = v;
  +        assertInitializationAllowed();
  +        this.perUserMaxWait = v;
       }
  -    
  -    
  +
       /**
        * Get the interval (in seconds) between which the ConnectionPool logs 
        * the status of it's Connections. Default is 0 which indicates no 
  @@ -273,9 +321,32 @@
        */
       public void setDefaultAutoCommit(boolean  v) 
       {
  +        assertInitializationAllowed();
           this.defaultAutoCommit = v;
       }
  +
  +    private Properties perUserDefaultAutoCommit;    
  +    /**
  +     * The keys are usernames and the value is the --.  Any 
  +     * username specified here will override the value of defaultAutoCommit.
  +     */
  +    public Properties getPerUserDefaultAutoCommit() 
  +    {
  +        return perUserDefaultAutoCommit;
  +    }
  +    
  +    /**
  +     * The keys are usernames and the value is the --.  Any 
  +     * username specified here will override the value of defaultAutoCommit.
  +     */
  +    public void setPerUserDefaultAutoCommit(Properties  v) 
  +    {
  +        assertInitializationAllowed();
  +        this.perUserDefaultAutoCommit = v;
  +    }
  +
           
  +    private Properties perUserDefaultReadOnly;    
       /**
        * Get the value of defaultReadOnly, which defines the state of 
        * connections handed out from this pool.  The value can be changed
  @@ -299,10 +370,217 @@
        */
       public void setDefaultReadOnly(boolean  v) 
       {
  +        assertInitializationAllowed();
           this.defaultReadOnly = v;
       }
       
       /**
  +     * The keys are usernames and the value is the --.  Any 
  +     * username specified here will override the value of defaultReadOnly.
  +     */
  +    public Properties getPerUserDefaultReadOnly() 
  +    {
  +        return perUserDefaultReadOnly;
  +    }
  +    
  +    /**
  +     * The keys are usernames and the value is the --.  Any 
  +     * username specified here will override the value of defaultReadOnly.
  +     */
  +    public void setPerUserDefaultReadOnly(Properties  v) 
  +    {
  +        assertInitializationAllowed();
  +        this.perUserDefaultReadOnly = v;
  +    }
  +
  +    boolean _testOnBorrow;
  +    /**
  +     * When <tt>true</tt>, objects will be
  +     * {*link PoolableObjectFactory#validateObject validated}
  +     * before being returned by the {*link #borrowObject}
  +     * method.  If the object fails to validate,
  +     * it will be dropped from the pool, and we will attempt
  +     * to borrow another.
  +     *
  +     * *see #setTestOnBorrow
  +     */
  +    public boolean getTestOnBorrow() {
  +        return _testOnBorrow;
  +    }
  +
  +    /**
  +     * When <tt>true</tt>, objects will be
  +     * {*link PoolableObjectFactory#validateObject validated}
  +     * before being returned by the {*link #borrowObject}
  +     * method.  If the object fails to validate,
  +     * it will be dropped from the pool, and we will attempt
  +     * to borrow another.
  +     *
  +     * *see #getTestOnBorrow
  +     */
  +    public void setTestOnBorrow(boolean testOnBorrow) {
  +        assertInitializationAllowed();
  +        _testOnBorrow = testOnBorrow;
  +    }
  +
  +    boolean _testOnReturn;
  +    /**
  +     * When <tt>true</tt>, objects will be
  +     * {*link PoolableObjectFactory#validateObject validated}
  +     * before being returned to the pool within the
  +     * {*link #returnObject}.
  +     *
  +     * *see #setTestOnReturn
  +     */
  +    public boolean getTestOnReturn() {
  +        return _testOnReturn;
  +    }
  +
  +    /**
  +     * When <tt>true</tt>, objects will be
  +     * {*link PoolableObjectFactory#validateObject validated}
  +     * before being returned to the pool within the
  +     * {*link #returnObject}.
  +     *
  +     * *see #getTestOnReturn
  +     */
  +    public void setTestOnReturn(boolean testOnReturn) {
  +        assertInitializationAllowed();
  +        _testOnReturn = testOnReturn;
  +    }
  +
  +    long _timeBetweenEvictionRunsMillis;
  +    /**
  +     * Returns the number of milliseconds to sleep between runs of the
  +     * idle object evictor thread.
  +     * When non-positive, no idle object evictor thread will be
  +     * run.
  +     *
  +     * *see #setTimeBetweenEvictionRunsMillis
  +     */
  +    public synchronized long getTimeBetweenEvictionRunsMillis() {
  +        return _timeBetweenEvictionRunsMillis;
  +    }
  +
  +    /**
  +     * Sets the number of milliseconds to sleep between runs of the
  +     * idle object evictor thread.
  +     * When non-positive, no idle object evictor thread will be
  +     * run.
  +     *
  +     * *see #getTimeBetweenEvictionRunsMillis
  +     */
  +    public synchronized void 
  +        setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) {
  +        assertInitializationAllowed();
  +            _timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
  +    }
  +
  +    int _numTestsPerEvictionRun;
  +    /**
  +     * Returns the number of objects to examine during each run of the
  +     * idle object evictor thread (if any).
  +     *
  +     * *see #setNumTestsPerEvictionRun
  +     * *see #setTimeBetweenEvictionRunsMillis
  +     */
  +    public int getNumTestsPerEvictionRun() {
  +        return _numTestsPerEvictionRun;
  +    }
  +
  +    /**
  +     * Sets the number of objects to examine during each run of the
  +     * idle object evictor thread (if any).
  +     * <p>
  +     * When a negative value is supplied, <tt>ceil({*link #numIdle})/abs({*link #getNumTestsPerEvictionRun})</tt>
  +     * tests will be run.  I.e., when the value is <i>-n</i>, roughly one <i>n</i>th of the
  +     * idle objects will be tested per run.
  +     *
  +     * *see #getNumTestsPerEvictionRun
  +     * *see #setTimeBetweenEvictionRunsMillis
  +     */
  +    public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) {
  +        assertInitializationAllowed();
  +        _numTestsPerEvictionRun = numTestsPerEvictionRun;
  +    }
  +
  +    int _minEvictableIdleTimeMillis;
  +    /**
  +     * Returns the minimum amount of time an object may sit idle in the pool
  +     * before it is eligable for eviction by the idle object evictor
  +     * (if any).
  +     *
  +     * *see #setMinEvictableIdleTimeMillis
  +     * *see #setTimeBetweenEvictionRunsMillis
  +     */
  +    public synchronized int getMinEvictableIdleTimeMillis() {
  +        return _minEvictableIdleTimeMillis;
  +    }
  +
  +    /**
  +     * Sets the minimum amount of time an object may sit idle in the pool
  +     * before it is eligable for eviction by the idle object evictor
  +     * (if any).
  +     * When non-positive, no objects will be evicted from the pool
  +     * due to idle time alone.
  +     *
  +     * *see #getMinEvictableIdleTimeMillis
  +     * *see #setTimeBetweenEvictionRunsMillis
  +     */
  +    public synchronized void 
  +        setMinEvictableIdleTimeMillis(int minEvictableIdleTimeMillis) {
  +        assertInitializationAllowed();
  +        _minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
  +    }
  +
  +    boolean _testWhileIdle;
  +    /**
  +     * When <tt>true</tt>, objects will be
  +     * {*link PoolableObjectFactory#validateObject validated}
  +     * by the idle object evictor (if any).  If an object
  +     * fails to validate, it will be dropped from the pool.
  +     *
  +     * *see #setTestWhileIdle
  +     * *see #setTimeBetweenEvictionRunsMillis
  +     */
  +    public boolean getTestWhileIdle() {
  +        return _testWhileIdle;
  +    }
  +
  +    /**
  +     * When <tt>true</tt>, objects will be
  +     * {*link PoolableObjectFactory#validateObject validated}
  +     * by the idle object evictor (if any).  If an object
  +     * fails to validate, it will be dropped from the pool.
  +     *
  +     * *see #getTestWhileIdle
  +     * *see #setTimeBetweenEvictionRunsMillis
  +     */
  +    public void setTestWhileIdle(boolean testWhileIdle) {
  +        assertInitializationAllowed();
  +        _testWhileIdle = testWhileIdle;
  +    }
  +
  +
  +    /**
  +     * The SQL query that will be used to validate connections from this pool
  +     * before returning them to the caller.  If specified, this query
  +     * <strong>MUST</strong> be an SQL SELECT statement that returns at least
  +     * one row.
  +     */
  +    private String validationQuery = null;
  +
  +    public String getValidationQuery() {
  +        return (this.validationQuery);
  +    }
  +
  +    public void setValidationQuery(String validationQuery) {
  +        assertInitializationAllowed();
  +        this.validationQuery = validationQuery;
  +    }
  +
  +
  +    /**
        * Get the name of the ConnectionPoolDataSource which backs this pool.
        * This name is used to look up the datasource from a jndi service 
        * provider.
  @@ -414,14 +692,15 @@
                                                    String password)
           throws SQLException
       {
  +        getConnectionCalled = true;
           String key = getKey(username);
  -        ConnectionPool pool = (ConnectionPool)pools.get(key);
  +        ObjectPool pool = (ObjectPool)pools.get(key);
           if ( pool == null ) 
           {
               try
               {
                   registerPool(username, password);
  -                pool = (ConnectionPool)pools.get(key);
  +                pool = (ObjectPool)pools.get(key);
               }
               catch (Exception e)
               {
  @@ -430,7 +709,32 @@
           }
   
           Connection con = 
  -            pool.getConnection(username, password).getConnection();
  +            ((PooledConnection)pool.borrowObject()).getConnection();
  +
  +        // FIXME! this could be more efficient
  +        boolean defaultAutoCommit = isDefaultAutoCommit();
  +        if ( username != null ) 
  +        {
  +            String userMax = 
  +                (String)getPerUserDefaultAutoCommit().get(username);
  +            if ( userMax != null ) 
  +            {
  +                defaultAutoCommit = Boolean.getBoolean(userMax);
  +            }
  +        }    
  +
  +        // FIXME! this could be more efficient
  +        boolean defaultReadOnly = isDefaultReadOnly();
  +        if ( username != null ) 
  +        {
  +            String userMax = 
  +                (String)getPerUserDefaultReadOnly().get(username);
  +            if ( userMax != null ) 
  +            {
  +                defaultReadOnly = Boolean.getBoolean(userMax);
  +            }
  +        }    
  +
           con.setAutoCommit(defaultAutoCommit);
           con.setReadOnly(defaultReadOnly);
           return con;
  @@ -452,6 +756,46 @@
           String key = getKey(username);
           if ( !pools.containsKey(key) ) 
           {
  +            int maxActive = getDefaultMaxActive();
  +            if ( username != null ) 
  +            {
  +                String userMax = 
  +                    (String)getPerUserMaxActive().get(username);
  +                if ( userMax != null ) 
  +                {
  +                    maxActive = Integer.parseInt(userMax);
  +                }
  +            }    
  +
  +            int maxIdle = getDefaultMaxIdle();
  +            if ( username != null ) 
  +            {
  +                String userMax = 
  +                    (String)getPerUserMaxIdle().get(username);
  +                if ( userMax != null ) 
  +                {
  +                    maxIdle = Integer.parseInt(userMax);
  +                }
  +            }    
  +
  +            int maxWait = getDefaultMaxWait();
  +            if ( username != null ) 
  +            {
  +                String userMax = 
  +                    (String)getPerUserMaxIdle().get(username);
  +                if ( userMax != null ) 
  +                {
  +                    maxWait = Integer.parseInt(userMax);
  +                }
  +            }    
  +
  +            // Create an object pool to contain our active connections
  +            GenericObjectPool pool = new GenericObjectPool(null);
  +            pool.setMaxActive(maxActive);
  +            pool.setMaxIdle(maxIdle);
  +            pool.setMaxWait(maxWait);
  +            // FIXME! set the rest of the properties
  +                        
               ConnectionPoolDataSource cpds = this.cpds;
               if ( cpds == null ) 
               {            
  @@ -467,21 +811,11 @@
                   cpds = (ConnectionPoolDataSource)ctx.lookup(dataSourceName);
               }
   
  -            int maxConnections = getDefaultMaxConnections();
  -            if ( username != null ) 
  -            {
  -                String userMaxCon = 
  -                    (String)getPerUserMaxConnections().get(username);
  -                if ( userMaxCon != null ) 
  -                {
  -                    maxConnections = Integer.parseInt(userMaxCon);
  -                }
  -            }    
  -        
  -            ConnectionPool pool = new ConnectionPool(cpds, username, password,
  -                maxConnections, maxExpiryTime, connectionWaitTimeout, 
  -                logInterval, logWriter);
  -
  +            // Set up the factory we will use
  +            CPDSConnectionFactory connectionFactory =
  +                new CPDSConnectionFactory(cpds, pool, validationQuery,
  +                                          username, password);
  +            
               // avoid ConcurrentModificationException
               Map newPools = new HashMap(pools);
               newPools.put(key, pool);
  @@ -533,25 +867,26 @@
           
           Reference ref = new Reference(getClass().getName(), factory, null);
   
  -        ref.add(new StringRefAddr("defaultMaxConnections", 
  -                                  String.valueOf(getDefaultMaxConnections())));
  -        ref.add(new StringRefAddr("maxExpiryTime", 
  -                                  String.valueOf(getMaxExpiryTime())));
  -        ref.add(new StringRefAddr("connectionWaitTimeout", 
  -                                  String.valueOf(getConnectionWaitTimeout())));
  +        ref.add(new StringRefAddr("defaultMaxActive", 
  +                                  String.valueOf(getDefaultMaxActive())));
  +        ref.add(new StringRefAddr("defaultMaxIdle", 
  +                                  String.valueOf(getDefaultMaxIdle())));
  +        ref.add(new StringRefAddr("defaultMaxWait", 
  +                                  String.valueOf(getDefaultMaxWait())));
  +        // FIXME! more properties
           ref.add(new StringRefAddr("logInterval", 
                                     String.valueOf(getLogInterval())));
           ref.add(new StringRefAddr("dataSourceName", getDataSourceName()));
           ref.add(new StringRefAddr("description", getDescription()));
   
  -        byte[] serJndiEnv = null;
  +        byte[] ser = null;
           // BinaryRefAddr does not allow null byte[].
           if ( getJndiEnvironment() != null ) 
           {
               try
               {
  -                serJndiEnv = serialize(getJndiEnvironment());
  -                ref.add(new BinaryRefAddr("jndiEnvironment", serJndiEnv));
  +                ser = serialize(getJndiEnvironment());
  +                ref.add(new BinaryRefAddr("jndiEnvironment", ser));
               }
               catch (IOException ioe)
               {
  @@ -560,14 +895,13 @@
               }
           }
   
  -        byte[] serPUMC = null;
           // BinaryRefAddr does not allow null byte[].
  -        if ( getPerUserMaxConnections() != null ) 
  +        if ( getPerUserMaxActive() != null ) 
           {
               try
               {
  -                serPUMC = serialize(getPerUserMaxConnections());
  -                ref.add(new BinaryRefAddr("perUserMaxConnections", serPUMC));
  +                ser = serialize(getPerUserMaxActive());
  +                ref.add(new BinaryRefAddr("perUserMaxActive", ser));
               }
               catch (IOException ioe)
               {
  @@ -575,6 +909,21 @@
                      "serializing the perUserMaxConnections properties.");
               }
           }
  +
  +        // BinaryRefAddr does not allow null byte[].
  +        if ( getPerUserMaxActive() != null ) 
  +        {
  +            try
  +            {
  +                ser = serialize(getPerUserMaxActive());
  +                ref.add(new BinaryRefAddr("perUserMaxActive", ser));
  +            }
  +            catch (IOException ioe)
  +            {
  +                throw new NamingException("An IOException prevented " + 
  +                   "serializing the perUserMaxActive properties.");
  +            }
  +        }
           
           return ref;
       }
  @@ -591,12 +940,8 @@
   	
           if (ref.getClassName().equals(getClass().getName())) 
           {   
  -            setDefaultMaxConnections(Integer.parseInt(
  -                (String)ref.get("defaultMaxConnections").getContent()));
  -            setMaxExpiryTime(Integer.parseInt(
  -                (String)ref.get("maxExpiryTime").getContent()));
  -            setConnectionWaitTimeout(Integer.parseInt(
  -                (String)ref.get("connectionWaitTimeout").getContent()));
  +            setDefaultMaxActive(Integer.parseInt(
  +                (String)ref.get("defaultMaxActive").getContent()));
               setLogInterval(Integer.parseInt(
                   (String)ref.get("logInterval").getContent()));
               setDataSourceName((String)ref.get("dataSourceName").getContent());
  @@ -610,11 +955,11 @@
                       (Properties)ObjectUtils.deserialize(serialized) );
               }
   
  -            refAddr = ref.get("perUserMaxConnections");
  +            refAddr = ref.get("perUserMaxActive");
               if ( refAddr != null ) 
               {
                   byte[] serialized = (byte[])refAddr.getContent();
  -                setPerUserMaxConnections( 
  +                setPerUserMaxActive( 
                       (Properties)ObjectUtils.deserialize(serialized) );
               }
               
  
  
  
  1.1                  jakarta-commons-sandbox/jdbc2pool/src/java/org/apache/commons/jdbc2pool/CPDSConnectionFactory.java
  
  Index: CPDSConnectionFactory.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons-sandbox/jdbc2pool/src/java/org/apache/commons/jdbc2pool/CPDSConnectionFactory.java,v 1.1 2002/03/04 07:52:37 jmcnally Exp $
   * $Revision: 1.1 $
   * $Date: 2002/03/04 07:52:37 $
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999-2001 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Commons", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   */
  
  package org.apache.commons.jdbc2pool;
  
  import java.util.Map;
  import java.util.HashMap;
  import java.sql.*;
  import javax.sql.ConnectionPoolDataSource;
  import javax.sql.PooledConnection;
  import javax.sql.ConnectionEvent;
  import javax.sql.ConnectionEventListener;
  
  import org.apache.commons.pool.*;
  import org.apache.commons.dbcp.*;
  
  /**
   * A {*link PoolableObjectFactory} that creates
   * {*link PoolableConnection}s.
   *
   * @author <a href="mailto:jmcnally@collab.net">John D. McNally</a>
   * @version $Id: CPDSConnectionFactory.java,v 1.1 2002/03/04 07:52:37 jmcnally Exp $
   */
  public class CPDSConnectionFactory 
      implements PoolableObjectFactory, ConnectionEventListener {
      /**
       * Create a new <tt>PoolableConnectionFactory</tt>.
       * @param connFactory the {*link ConnectionFactory} from which to obtain base {*link Connection}s
       * @param pool the {*link ObjectPool} in which to pool those {*link Connection}s
       * @param stmtPoolFactory the {*link KeyedObjectPoolFactory} to use to create {*link KeyedObjectPool}s for pooling {*link PreparedStatement}s, or <tt>null</tt> to disable {*link PreparedStatement} pooling
       * @param validationQuery a query to use to {*link #validateObject validate} {*link Connection}s.  Should return at least one row. May be <tt>null</tt>
       * @param defaultReadOnly the default "read only" setting for borrowed {*link Connection}s
       * @param defaultAutoCommit the default "auto commit" setting for returned {*link Connection}s
       */
      public CPDSConnectionFactory(ConnectionPoolDataSource cpds, 
                                   ObjectPool pool, 
                                   String validationQuery,
                                   String username,
                                   String password) {
          _cpds = cpds;
          _pool = pool;
          _pool.setFactory(this);
          _validationQuery = validationQuery;
          _username = username;
          _password = password;
      }
  
      /**
       * Sets the {*link ConnectionFactory} from which to obtain base {*link Connection}s.
       * @param connFactory the {*link ConnectionFactory} from which to obtain base {*link Connection}s
       */
      synchronized public void setCPDS(ConnectionPoolDataSource cpds) {
          _cpds = cpds;
      }
  
      /**
       * Sets the query I use to {*link #validateObject validate} {*link Connection}s.
       * Should return at least one row.
       * May be <tt>null</tt>
       * @param validationQuery a query to use to {*link #validateObject validate} {*link Connection}s.
       */
      synchronized public void setValidationQuery(String validationQuery) {
          _validationQuery = validationQuery;
      }
  
      /**
       * Sets the {*link ObjectPool} in which to pool {*link Connection}s.
       * @param pool the {*link ObjectPool} in which to pool those {*link Connection}s
       */
      synchronized public void setPool(ObjectPool pool) {
          if(null != _pool && pool != _pool) {
              _pool.close();
          }
          _pool = pool;
      }
  
      public ObjectPool getPool() {
          return _pool;
      }
  
  
      synchronized public Object makeObject() {
          PooledConnection pc = null;
          try
          {
              if ( _username == null ) 
              {
                  pc = _cpds.getPooledConnection();
              }
              else 
              {
                  pc = _cpds.getPooledConnection(_username, _password);
              }
              // should we add this object as a listener or the pool.
              // consider the validateObject method in decision
              pc.addConnectionEventListener(this);
          }
          catch (SQLException e)
          {
              throw new RuntimeException(e.getMessage());
          }
          return pc;
      }
  
      public void destroyObject(Object obj) {
          if(obj instanceof PooledConnection) {
              try {
                  ((PooledConnection)obj).close();
              } catch(RuntimeException e) {
                  throw e;
              } catch(SQLException e) {
                  ; // ignored
              }
          }
      }
  
      // FIXME! Connection from the PooledConnection must be closed before
      // another one can be requested and closing it will send an event
      // to the pool
      synchronized public boolean validateObject(Object obj) {
          boolean valid = false;
          if(obj instanceof PooledConnection) {
              PooledConnection pconn = (PooledConnection)obj;
              String query = _validationQuery;
              if(null != query) {
                  Connection conn = null;
                  Statement stmt = null;
                  ResultSet rset = null;
                  validatingMap.put(pconn, null);
                  try {
                      conn = pconn.getConnection();
                      stmt = conn.createStatement();
                      rset = stmt.executeQuery(query);
                      if(rset.next()) {
                          valid = true;
                      } else {
                          valid = false;
                      }
                  } catch(Exception e) {
                      valid = false;
                  }
                  finally 
                  {
                      try {
                          rset.close();
                      } catch(Throwable t) {
                          // ignore
                      }
                      try {
                          stmt.close();
                      } catch(Throwable t) {
                          // ignore
                      }
                      try {
                          conn.close();
                      } catch(Throwable t) {
                          // ignore
                      }
                      validatingMap.remove(pconn);
                  }
              } else {
                  valid = true;
              }
          } else {
              valid = false;
          }
          return valid;
      }
  
      public void passivateObject(Object obj) {
      }
  
      public void activateObject(Object obj) {
      }
  
      // ***********************************************************************
      // java.sql.ConnectionEventListener implementation
      // ***********************************************************************
  
      /**
       * This will be called if the Connection returned by the getConnection
       * method came from a PooledConnection, and the user calls the close()
       * method of this connection object. What we need to do here is to
       * release this PooledConnection from our pool...
       */
      public void connectionClosed(ConnectionEvent event) 
      {
          PooledConnection pc = (PooledConnection)event.getSource();
          // if this event occured becase we were validating, ignore it
          // otherwise return the connection to the pool.
          if (!validatingMap.containsKey(pc)) 
          {
              _pool.returnObject(pc);
          }
      }
  
      /**
       * If a fatal error occurs, close the underlying physical connection so as
       * not to be returned in the future
       */
      public void connectionErrorOccurred(ConnectionEvent event) 
      {
          PooledConnection pc = (PooledConnection)event.getSource();
          try 
          {
              System.err
                  .println("CLOSING DOWN CONNECTION DUE TO INTERNAL ERROR");
              //remove this from the listener list because we are no more 
              //interested in errors since we are about to close this connection
              pc.removeConnectionEventListener(this);
          }
          catch (Exception ignore) 
          {
              // ignore
          }
  
          destroyObject(pc);
      }
  
  
      protected ConnectionPoolDataSource _cpds = null;
      protected String _validationQuery = null;
      protected ObjectPool _pool = null;
      protected String _username = null;
      protected String _password = null;
      private Map validatingMap = new HashMap();
  }
  
  
  
  1.1                  jakarta-commons-sandbox/jdbc2pool/src/java/org/apache/commons/jdbc2pool/TorqueClassicDataSource.java
  
  Index: TorqueClassicDataSource.java
  ===================================================================
  package org.apache.commons.jdbc2pool;
  
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2001 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" and 
   *    "Apache Turbine" must not be used to endorse or promote products 
   *    derived from this software without prior written permission. For 
   *    written permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    "Apache Turbine", nor may "Apache" appear in their name, without 
   *    prior written permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
   
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.Map;
  import java.util.Properties;
  
  import java.util.Hashtable;
  import java.io.PrintWriter;
  import java.io.Serializable;
  import java.io.ByteArrayOutputStream;
  import java.io.ObjectOutputStream;
  import java.io.IOException;
  import java.sql.Connection;
  import java.sql.SQLException;
  import javax.sql.DataSource;
  import javax.sql.ConnectionPoolDataSource;
  import javax.naming.Name;
  import javax.naming.Context;
  import javax.naming.InitialContext;
  import javax.naming.Referenceable;
  import javax.naming.Reference;
  import javax.naming.RefAddr;
  import javax.naming.BinaryRefAddr;
  import javax.naming.StringRefAddr;
  import javax.naming.NamingException;
  import javax.naming.spi.ObjectFactory;
  
  import org.apache.commons.util.ObjectUtils;
  
  /**
   * Torque's default connection pool DataSource
   *
   * @author <a href="mailto:jmcnally@collab.net">John D. McNally</a>
   * @version $Id: TorqueClassicDataSource.java,v 1.1 2002/03/04 07:52:37 jmcnally Exp $
   */
  public class TorqueClassicDataSource
      implements DataSource, Referenceable, Serializable, ObjectFactory
  {
      /** Pools keyed by username. */
      private static Map pools = new HashMap(); 
  
      /** DataSource Name used to find the ConnectionPoolDataSource */
      private String dataSourceName;
      /** Description */
      private String description;
  
      /** Login TimeOut in seconds */
      private int loginTimeout;
  
      private ConnectionPoolDataSource cpds;
  
      /** Log stream */
      private PrintWriter logWriter;
  
      /** Environment that may be used to set up a jndi initial context. */
      private Properties jndiEnvironment;
  
      private int defaultMaxConnections;
      private Properties perUserMaxConnections;
      private int maxExpiryTime;
      private int connectionWaitTimeout;
      private int logInterval;
      private boolean defaultAutoCommit;
      private boolean defaultReadOnly;
  
      /**
       * Default no-arg constructor for Serialization
       */
      public TorqueClassicDataSource() 
      {
          defaultAutoCommit = true;
      }
  
      // Properties
          
      /**
       * Get the number of database connections to cache per user.
       * This value is used for any username which is not specified
       * in perUserMaxConnections.  The default is 1.
       *
       * @return value of maxConnections.
       */
      public int getDefaultMaxConnections() 
      {
          return defaultMaxConnections;
      }
      
      /**
       * Set the number of database connections to cache per user.
       * This value is used for any username which is not specified
       * in perUserMaxConnections.  The default is 1.
       *
       * @param v  Value to assign to maxConnections.
       */
      public void setDefaultMaxConnections(int  v) 
      {
          this.defaultMaxConnections = v;
      }
      
      
      /**
       * Get the number of database connections to cache per user.  The keys
       * are usernames and the value is the maximum connections.  Any username
       * specified here will override the value of defaultMaxConnections.
       *
       * @return value of perUserMaxConnections.
       */
      public Properties getPerUserMaxConnections() 
      {
          return perUserMaxConnections;
      }
      
      /**
       * Set the number of database connections to cache per user.  The keys
       * are usernames and the value is the maximum connections.  Any username
       * specified here will override the value of defaultMaxConnections.
       * 
       * @param v  Value to assign to perUserMaxConnections.
       */
      public void setPerUserMaxConnections(Properties  v) 
      {
          this.perUserMaxConnections = v;
      }
      
      
      /**
       * Get the amount of time (in seconds) that database connections 
       * will be cached.  The default is 3600 (1 hour).
       * 
       * @return value of expiryTime.
       */
      public int getMaxExpiryTime() 
      {
          return maxExpiryTime;
      }
      
      /**
       * Set the amount of time (in seconds) that database connections 
       * will be cached.  The default is 3600 (1 hour).
       *
       * @param v  Value to assign to expiryTime.
       */
      public void setMaxExpiryTime(int  v) 
      {
          this.maxExpiryTime = v;
      }
      
      
      /**
       * Get the amount of time (in seconds) a connection request will  
       * have to wait before a time out occurs and an error is thrown.
       * The default is 10 seconds.
       *
       * @return value of connectionWaitTimeout.
       */
      public int getConnectionWaitTimeout() 
      {
          return connectionWaitTimeout;
      }
      
      /**
       * Eet the amount of time (in seconds) a connection request will
       * have to wait before a time out occurs and an error is thrown.
       * The default is 10 seconds.
       *
       * @param v  Value to assign to connectionWaitTimeout.
       */
      public void setConnectionWaitTimeout(int  v) 
      {
          this.connectionWaitTimeout = v;
      }
      
      
      /**
       * Get the interval (in seconds) between which the ConnectionPool logs 
       * the status of it's Connections. Default is 0 which indicates no 
       * logging.
       *
       * @return value of logInterval.
       */
      public int getLogInterval() 
      {
          return logInterval;
      }
      
      /**
       * Set the interval (in seconds) between which the ConnectionPool logs 
       * the status of it's Connections. Default is 0 which indicates no 
       * logging.
       *
       * @param v  Value to assign to logInterval.
       */
      public void setLogInterval(int  v) 
      {
          this.logInterval = v;
      }
      
      /** 
       * Get the value of defaultAutoCommit, which defines the state of 
       * connections handed out from this pool.  The value can be changed
       * on the Connection using Connection.setAutoCommit(boolean).
       * The default is true.
       *
       * @return value of defaultAutoCommit.
       */
      public boolean isDefaultAutoCommit() 
      {
          return defaultAutoCommit;
      }
      
      /**
       * Set the value of defaultAutoCommit, which defines the state of 
       * connections handed out from this pool.  The value can be changed
       * on the Connection using Connection.setAutoCommit(boolean).
       * The default is true.
       *
       * @param v  Value to assign to defaultAutoCommit.
       */
      public void setDefaultAutoCommit(boolean  v) 
      {
          this.defaultAutoCommit = v;
      }
          
      /**
       * Get the value of defaultReadOnly, which defines the state of 
       * connections handed out from this pool.  The value can be changed
       * on the Connection using Connection.setReadOnly(boolean).
       * The default is false.
       *
       * @return value of defaultReadOnly.
       */
      public boolean isDefaultReadOnly() 
      {
          return defaultReadOnly;
      }
      
      /**
       * Set the value of defaultReadOnly, which defines the state of 
       * connections handed out from this pool.  The value can be changed
       * on the Connection using Connection.setReadOnly(boolean).
       * The default is false.
       *
       * @param v  Value to assign to defaultReadOnly.
       */
      public void setDefaultReadOnly(boolean  v) 
      {
          this.defaultReadOnly = v;
      }
      
      /**
       * Get the name of the ConnectionPoolDataSource which backs this pool.
       * This name is used to look up the datasource from a jndi service 
       * provider.
       *
       * @return value of dataSourceName.
       */
      public String getDataSourceName() 
      {
          return dataSourceName;
      }
      
      /**
       * Set the name of the ConnectionPoolDataSource which backs this pool.
       * This name is used to look up the datasource from a jndi service 
       * provider.
       *
       * @param v  Value to assign to dataSourceName.
       */
      public void setDataSourceName(String  v) 
      {
          this.dataSourceName = v;
      }
      
      
      /**
       * Get the description.  This property is defined by jdbc as for use with
       * GUI (or other) tools that might deploy the datasource.  It serves no
       * internal purpose.
       *
       * @return value of description.
       */
      public String getDescription() 
      {
          return description;
      }
      
      /**
       * Set the description.  This property is defined by jdbc as for use with
       * GUI (or other) tools that might deploy the datasource.  It serves no
       * internal purpose.
       * 
       * @param v  Value to assign to description.
       */
      public void setDescription(String  v) 
      {
          this.description = v;
      }
          
      /**
       * Get the value of jndiEnvironment which is used when instantiating
       * a jndi InitialContext.  This InitialContext is used to locate the
       * backend ConnectionPoolDataSource.
       *
       * @return value of jndiEnvironment.
       */
      public Properties getJndiEnvironment() 
      {
          return jndiEnvironment;
      }
      
      /**
       * Set the value of jndiEnvironment which is used when instantiating
       * a jndi InitialContext.  This InitialContext is used to locate the
       * backend ConnectionPoolDataSource.
       *
       * @param v  Value to assign to jndiEnvironment.
       */
      public void setJndiEnvironment(Properties  v) 
      {
          this.jndiEnvironment = v;
      }
      
      /**
       * Get the value of connectionPoolDataSource.  This method will return
       * null, if the backing datasource is being accessed via jndi.
       *
       * @return value of connectionPoolDataSource.
       */
      public ConnectionPoolDataSource getConnectionPoolDataSource() 
      {
          return cpds;
      }
      
      /**
       * Set the backend ConnectionPoolDataSource.  This property should not be
       * set if using jndi to access the datasource.
       *
       * @param v  Value to assign to connectionPoolDataSource.
       */
      public void setConnectionPoolDataSource(ConnectionPoolDataSource  v) 
      {
          this.cpds = v;
      }
      
  
      /**
       * Attempt to establish a database connection.
       */
      public Connection getConnection() 
          throws SQLException
      {
          return getConnection(null, null);
      }
                       
      /**
       * Attempt to establish a database connection.
       */
      synchronized public Connection getConnection(String username, 
                                                   String password)
          throws SQLException
      {
          String key = getKey(username);
          ConnectionPool pool = (ConnectionPool)pools.get(key);
          if ( pool == null ) 
          {
              try
              {
                  registerPool(username, password);
                  pool = (ConnectionPool)pools.get(key);
              }
              catch (Exception e)
              {
                  throw new SQLException(e.getMessage());
              }
          }
  
          Connection con = 
              pool.getConnection(username, password).getConnection();
          con.setAutoCommit(defaultAutoCommit);
          con.setReadOnly(defaultReadOnly);
          return con;
      }
  
      private String getKey(String suffix)
      {
          String key = getDataSourceName();
          if ( suffix != null ) 
          {
              key += suffix;            
          }
          return key;
      }
  
      synchronized private void registerPool(String username, String password)
           throws javax.naming.NamingException
      {
          String key = getKey(username);
          if ( !pools.containsKey(key) ) 
          {
              ConnectionPoolDataSource cpds = this.cpds;
              if ( cpds == null ) 
              {            
                  Context ctx = null;
                  if ( jndiEnvironment == null ) 
                  {
                      ctx = new InitialContext();                
                  }
                  else 
                  {
                      ctx = new InitialContext(jndiEnvironment);
                  }
                  cpds = (ConnectionPoolDataSource)ctx.lookup(dataSourceName);
              }
  
              int maxConnections = getDefaultMaxConnections();
              if ( username != null ) 
              {
                  String userMaxCon = 
                      (String)getPerUserMaxConnections().get(username);
                  if ( userMaxCon != null ) 
                  {
                      maxConnections = Integer.parseInt(userMaxCon);
                  }
              }    
          
              ConnectionPool pool = new ConnectionPool(cpds, username, password,
                  maxConnections, maxExpiryTime, connectionWaitTimeout, 
                  logInterval, logWriter);
  
              // avoid ConcurrentModificationException
              Map newPools = new HashMap(pools);
              newPools.put(key, pool);
              pools = newPools;   
          }        
      }
      
      /**
       * Gets the maximum time in seconds that this data source can wait 
       * while attempting to connect to a database.
       */
      public int getLoginTimeout() 
      {
          return loginTimeout;
      }
                             
      /**
       * Get the log writer for this data source.
       */
      public PrintWriter getLogWriter() 
      {
          return logWriter;
      }
                             
      /**
       * Sets the maximum time in seconds that this data source will wait 
       * while attempting to connect to a database. NOT USED.
       */
      public void setLoginTimeout(int seconds)
      {
          loginTimeout = seconds;
      } 
                             
      /**
       * Set the log writer for this data source. NOT USED.
       */
      public void setLogWriter(java.io.PrintWriter out)
      {
          logWriter = out;
      } 
  
      /**
       * <CODE>Referenceable</CODE> implementation.
       */
      public Reference getReference() 
          throws NamingException
      {
          String factory = getClass().getName();
          
          Reference ref = new Reference(getClass().getName(), factory, null);
  
          ref.add(new StringRefAddr("defaultMaxConnections", 
                                    String.valueOf(getDefaultMaxConnections())));
          ref.add(new StringRefAddr("maxExpiryTime", 
                                    String.valueOf(getMaxExpiryTime())));
          ref.add(new StringRefAddr("connectionWaitTimeout", 
                                    String.valueOf(getConnectionWaitTimeout())));
          ref.add(new StringRefAddr("logInterval", 
                                    String.valueOf(getLogInterval())));
          ref.add(new StringRefAddr("dataSourceName", getDataSourceName()));
          ref.add(new StringRefAddr("description", getDescription()));
  
          byte[] serJndiEnv = null;
          // BinaryRefAddr does not allow null byte[].
          if ( getJndiEnvironment() != null ) 
          {
              try
              {
                  serJndiEnv = serialize(getJndiEnvironment());
                  ref.add(new BinaryRefAddr("jndiEnvironment", serJndiEnv));
              }
              catch (IOException ioe)
              {
                  throw new NamingException("An IOException prevented " + 
                     "serializing the jndiEnvironment properties.");
              }
          }
  
          byte[] serPUMC = null;
          // BinaryRefAddr does not allow null byte[].
          if ( getPerUserMaxConnections() != null ) 
          {
              try
              {
                  serPUMC = serialize(getPerUserMaxConnections());
                  ref.add(new BinaryRefAddr("perUserMaxConnections", serPUMC));
              }
              catch (IOException ioe)
              {
                  throw new NamingException("An IOException prevented " + 
                     "serializing the perUserMaxConnections properties.");
              }
          }
          
          return ref;
      }
  
  
      /**
       * implements ObjectFactory to create an instance of this class
       */ 
      public Object getObjectInstance(Object refObj, Name name, 
                                      Context context, Hashtable env) 
          throws Exception 
      {
          Reference ref = (Reference)refObj;
  	
          if (ref.getClassName().equals(getClass().getName())) 
          {   
              setDefaultMaxConnections(Integer.parseInt(
                  (String)ref.get("defaultMaxConnections").getContent()));
              setMaxExpiryTime(Integer.parseInt(
                  (String)ref.get("maxExpiryTime").getContent()));
              setConnectionWaitTimeout(Integer.parseInt(
                  (String)ref.get("connectionWaitTimeout").getContent()));
              setLogInterval(Integer.parseInt(
                  (String)ref.get("logInterval").getContent()));
              setDataSourceName((String)ref.get("dataSourceName").getContent());
              setDescription((String)ref.get("description").getContent());
  
              RefAddr refAddr = ref.get("jndiEnvironment");
              if ( refAddr != null ) 
              {
                  byte[] serialized = (byte[])refAddr.getContent();
                  setJndiEnvironment( 
                      (Properties)ObjectUtils.deserialize(serialized) );
              }
  
              refAddr = ref.get("perUserMaxConnections");
              if ( refAddr != null ) 
              {
                  byte[] serialized = (byte[])refAddr.getContent();
                  setPerUserMaxConnections( 
                      (Properties)ObjectUtils.deserialize(serialized) );
              }
              
              return this;
          }
          else 
          { 
              // We can't create an instance of the reference
              return null;
          }
      }
  
      /**
       * Converts a object to a byte array for storage/serialization.
       * FIXME! this method should be moved to commons.util.ObjectUtils
       *
       * @param hash The Hashtable to convert.
       * @return A byte[] with the converted Hashtable.
       * @exception Exception, a generic exception.
       */
      private static byte[] serialize(Serializable obj)
          throws IOException
      {
          byte[] byteArray = null;
          ByteArrayOutputStream baos = null;
          ObjectOutputStream out = null;
          try
          {
              // These objects are closed in the finally.
              baos = new ByteArrayOutputStream();
              out = new ObjectOutputStream(baos);
  
              out.writeObject(obj);
              byteArray = baos.toByteArray();
          }
          finally
          {
              if (out != null) 
              {
                  out.close();
              }
          }
          return byteArray;
      }
  
  }
  
  
  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>