avalon-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From tbenn...@apache.org
Subject cvs commit: avalon-components/facilities/dbcp/impl/src/java/org/apache/avalon/dbcp DbcpConnectionManager.java
Date Tue, 11 May 2004 21:24:24 GMT
tbennett    2004/05/11 14:24:24

  Modified:    facilities/dbcp/impl/src/java/org/apache/avalon/dbcp
                        DbcpConnectionManager.java
  Log:
  New database Connection Pooling facility
  
  Revision  Changes    Path
  1.2       +297 -37   avalon-components/facilities/dbcp/impl/src/java/org/apache/avalon/dbcp/DbcpConnectionManager.java
  
  Index: DbcpConnectionManager.java
  ===================================================================
  RCS file: /home/cvs/avalon-components/facilities/dbcp/impl/src/java/org/apache/avalon/dbcp/DbcpConnectionManager.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- DbcpConnectionManager.java	7 May 2004 23:21:23 -0000	1.1
  +++ DbcpConnectionManager.java	11 May 2004 21:24:24 -0000	1.2
  @@ -19,9 +19,11 @@
   
   import java.io.File;
   import java.sql.Connection;
  +import java.sql.DriverManager;
  +import java.sql.SQLException;
   
  +import org.apache.avalon.framework.activity.Disposable;
   import org.apache.avalon.framework.activity.Initializable;
  -import org.apache.avalon.framework.activity.Startable;
   import org.apache.avalon.framework.configuration.Configurable;
   import org.apache.avalon.framework.configuration.Configuration;
   import org.apache.avalon.framework.configuration.ConfigurationException;
  @@ -29,6 +31,12 @@
   import org.apache.avalon.framework.context.ContextException;
   import org.apache.avalon.framework.context.Contextualizable;
   import org.apache.avalon.framework.logger.Logger;
  +import org.apache.commons.dbcp.ConnectionFactory;
  +import org.apache.commons.dbcp.DriverManagerConnectionFactory;
  +import org.apache.commons.dbcp.PoolableConnectionFactory;
  +import org.apache.commons.dbcp.PoolingDriver;
  +import org.apache.commons.pool.ObjectPool;
  +import org.apache.commons.pool.impl.GenericObjectPool;
   
   /**
    * This is a JDBC Connection Manager implementation that uses the
  @@ -36,17 +44,19 @@
    * to serve up pooled connections to datasources.
    *
    * @avalon.component name="dbcp-manager" lifestyle="singleton"
  - * @avalon.service type="org.apache.avalon.sql.ConnectionManager"
  + * @avalon.service type="org.apache.avalon.dbcp.ConnectionManager"
  + * 
  + * @author <a href="mailto:dev@avalon.apache.org">Avalon Development Team</a>
  + * @version $Revision$ $Date$
    */
   public class DbcpConnectionManager
   	implements
   		Contextualizable,
   		Configurable,
   		Initializable,
  -		Startable,
  +        Disposable,
   		ConnectionManager
   {
  -
   	//---------------------------------------------------------
   	// state
   	//---------------------------------------------------------
  @@ -59,6 +69,14 @@
   	 * The working base directory.
   	 */
   	private File m_basedir;
  +    /**
  +     * Connection pool configuration parameters.
  +     */
  +    private Configuration m_pool;
  +    /**
  +     * Set of datasource configuration parameters.
  +     */
  +    private Configuration[] m_datasources;
   	
       //---------------------------------------------------------
       // constructor
  @@ -103,52 +121,293 @@
   	 * @param config the supplied server configuration
   	 * @exception ConfigurationException if a configuration error occurs
   	 */
  -	public void configure(Configuration config) throws ConfigurationException {
  -		// TODO Auto-generated method stub
  -		
  +	public void configure( final Configuration config )
  +        throws ConfigurationException
  +    {
  +        // cache away the connection pool settings...
  +        m_pool = config.getChild( "pool", false );
  +        
  +        // cache away the datasources settings...
  +        Configuration datasources = config.getChild( "datasources", false );
  +        if ( datasources == null )
  +        {
  +            throw new ConfigurationException( "The '<datasources>' " +
  +                    "directive is not included in the component's" +
  +                    "configuration." );
  +        }
  +        else
  +        {
  +            m_datasources = datasources.getChildren( "datasource" );
  +            if ( m_datasources == null)
  +            {
  +                throw new ConfigurationException( "One or more " +
  +                        "'<datasource>' directives are not included in the " +
  +                        "component's configuration." );
  +            }
  +            else
  +            {
  +                if ( m_datasources.length == 0 ) {
  +                    throw new ConfigurationException( "One or more " +
  +                            "'<datasource>' directives are not included in the "
+
  +                            "component's configuration." );
  +                }
  +            }
  +        }
   	}
   
  -	/* (non-Javadoc)
  -	 * @see org.apache.avalon.framework.activity.Initializable#initialize()
  -	 */
  -	public void initialize() throws Exception {
  -		// TODO Auto-generated method stub
  -		
  -	}
  +    //---------------------------------------------------------
  +    // Initializable
  +    //---------------------------------------------------------
   
  -	/* (non-Javadoc)
  -	 * @see org.apache.avalon.framework.activity.Startable#start()
  -	 */
  -	public void start() throws Exception {
  -		// TODO Auto-generated method stub
  -		
  +    /**
  +     * Initialization of the component by the container.
  +     * 
  +     * @throws Exception if an error occurs while initializing
  +     * the component
  +     */
  +	public void initialize() throws Exception {
  +        m_logger.debug( "Initializing..." );
  +        
  +        // First, let's load the DBCP's pooling driver class
  +        m_logger.debug( "Loading DBCP Pooling Driver class..." );
  +        Class.forName("org.apache.commons.dbcp.PoolingDriver");
  +        
  +        // loop through all the configured datasources...
  +        for ( int i = 0; i < m_datasources.length; i++ )
  +        {
  +            // this is the next datasource configuration object to process
  +            Configuration datasource = m_datasources[i];
  +            String name = datasource.getAttribute( "name" );
  +            boolean isDefault = datasource.getAttributeAsBoolean( "default", false );
  +            m_logger.debug( "Processing datasource [" + name + "]" +
  +                    " (default=" + isDefault + ")");
  +            
  +            // create an object pool that will actually hold our connections
  +            ObjectPool connectionPool = createObjectPool();
  +            m_logger.debug( "Object pool created..." );
  +            
  +            // load the underlying JDBC driver of the datasource
  +            loadJDBCDriver( datasource );
  +            m_logger.debug( "Underlying JDBC driver loaded..." );
  +            
  +            // create a driver manager connection factory that will be
  +            // used to actually create the database connection(s)
  +            ConnectionFactory connectionFactory = createConnectionFactory( datasource );
  +            m_logger.debug( "Connection factory created..." );
  +            
  +            // create a poolable connection factory wrapper
  +            PoolableConnectionFactory poolableConnectionFactory =
  +                createPoolableConnectionFactory( connectionFactory,
  +                                                 connectionPool,
  +                                                 datasource );
  +            m_logger.debug( "Poolable connection factory created..." );
  +            
  +            // get an instance of the DBCP pooling driver... 
  +            PoolingDriver driver = (PoolingDriver) DriverManager.getDriver("jdbc:apache:commons:dbcp:");
  +            m_logger.debug( "Pooling driver instance obtained..." );
  +            
  +            // register our pool with it...
  +            driver.registerPool( name, connectionPool );
  +            
  +            // is this the default datasource?
  +            if ( isDefault )
  +            {
  +                driver.registerPool( "default", connectionPool );
  +            }
  +        }
   	}
   
  -	/* (non-Javadoc)
  -	 * @see org.apache.avalon.framework.activity.Startable#stop()
  -	 */
  -	public void stop() throws Exception {
  -		// TODO Auto-generated method stub
  -		
  -	}
  +    //---------------------------------------------------------
  +    // Disposable
  +    //---------------------------------------------------------
   
  -	/* (non-Javadoc)
  -	 * @see org.apache.avalon.sql.ConnectionManager#getConnection()
  +    /**
  +     *  Cleans up the component. 
  +     */
  +    public void dispose() {
  +        try
  +        {
  +            PoolingDriver driver = (PoolingDriver) DriverManager.getDriver("jdbc:apache:commons:dbcp:");
  +            // loop through all the configured datasources...
  +            for ( int i = 0; i < m_datasources.length; i++ )
  +            {
  +                Configuration datasource = m_datasources[i];
  +                String name = datasource.getAttribute( "name" );
  +                driver.closePool( name );
  +            }
  +        }
  +        catch ( Exception e )
  +        {
  +            m_logger.warn( e.getMessage() );
  +        }
  +    }
  +    
  +	/**
  +     * Returns a <code>java.sql.Connection</code> to the default data source.
  +     * 
  +     * @return a <code>java.sql.Connection</code> to the default data source
   	 */
  -	public Connection getConnection() {
  -		// TODO Auto-generated method stub
  -		return null;
  +	public Connection getConnection() throws SQLException {
  +		return DriverManager.getConnection("jdbc:apache:commons:dbcp:default");
   	}
   
  -	/* (non-Javadoc)
  -	 * @see org.apache.avalon.sql.ConnectionManager#getConnection(java.lang.String)
  +	/**
  +     * Returns a <code>java.sql.Connection</code> to the specified data source.
  +     * 
  +     * @param name the name of the data source to obtain a connection to
  +     * @return a <code>java.sql.Connection</code> to the specified data source
   	 */
  -	public Connection getConnection(String datasource) {
  -		// TODO Auto-generated method stub
  -		return null;
  +	public Connection getConnection(String datasource) throws SQLException {
  +        return DriverManager.getConnection("jdbc:apache:commons:dbcp:" + datasource);
   	}
   
       /**
  +     * Returns an object pool configuration object populated with data
  +     * retrieved from the component's configuration.  Defaults correspond
  +     * to the <code>GenericObjectPool</code> default values.
  +     *   
  +     * @return <code>GenericObjectPool.Config</code> instance containing
  +     * the pool's configuration parameters
  +     */
  +    private GenericObjectPool.Config getPoolConfig()
  +    {
  +        GenericObjectPool.Config config = new GenericObjectPool.Config();
  +        if ( m_pool != null )
  +        {
  +            config.maxActive = m_pool.getAttributeAsInteger(
  +                    "max-active", GenericObjectPool.DEFAULT_MAX_ACTIVE );
  +            config.maxIdle = m_pool.getAttributeAsInteger(
  +                    "max-idle", GenericObjectPool.DEFAULT_MAX_IDLE );
  +            config.maxWait = m_pool.getAttributeAsLong(
  +                    "max-wait", GenericObjectPool.DEFAULT_MAX_WAIT );
  +            config.minEvictableIdleTimeMillis = m_pool.getAttributeAsLong(
  +                    "min-evict-idle-time", GenericObjectPool.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS
);
  +            config.minIdle = m_pool.getAttributeAsInteger(
  +                    "min-idle", GenericObjectPool.DEFAULT_MIN_IDLE );
  +            config.numTestsPerEvictionRun = m_pool.getAttributeAsInteger(
  +                    "num-evict-tests", GenericObjectPool.DEFAULT_NUM_TESTS_PER_EVICTION_RUN
);
  +            config.testOnBorrow = m_pool.getAttributeAsBoolean(
  +                    "test-on-borrow", GenericObjectPool.DEFAULT_TEST_ON_BORROW );
  +            config.testOnReturn = m_pool.getAttributeAsBoolean(
  +                    "test-on-return", GenericObjectPool.DEFAULT_TEST_ON_RETURN );
  +            config.testWhileIdle = m_pool.getAttributeAsBoolean(
  +                    "test-while-idle", GenericObjectPool.DEFAULT_TEST_WHILE_IDLE );
  +            config.timeBetweenEvictionRunsMillis = m_pool.getAttributeAsLong(
  +                    "time-between-evict-runs", GenericObjectPool.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS
);
  +            config.whenExhaustedAction = GenericObjectPool.DEFAULT_WHEN_EXHAUSTED_ACTION;
  +        }
  +        return config;
  +    }
  +    
  +    /**
  +     * Creates an <code>GenericObjectPool</code> instance that serves
  +     * as a the actual pool of connections.
  +     * 
  +     * @return <code>GenericObjectPool</code> instance.
  +     */
  +    private ObjectPool createObjectPool()
  +    {
  +        ObjectPool pool = null;
  +        
  +        // We'll need a ObjectPool that serves as the actual pool
  +        // of connections.  We'll use a GenericObjectPool instance.
  +        if ( m_pool == null )
  +        {
  +            pool = new GenericObjectPool( null );
  +        }
  +        else
  +        {
  +            pool = new GenericObjectPool( null, getPoolConfig() );
  +        }
  +        return pool;
  +    }
  +    
  +    /**
  +     * Loads the underlying JDBC driver defined for the datasource.
  +     * 
  +     * @param datasource the datasource
  +     * @throws DriverNotFoundException if the datasource directive is missing
  +     * the 'driver' directive in the configuration
  +     * @throws ConfigurationException if an error occurs while retrieving
  +     * configuration information about this datasource
  +     * @throws ClassNotFoundException if the underlying JDBC driver class
  +     * cannot be loaded
  +     */
  +    private void loadJDBCDriver( final Configuration datasource )
  +        throws DriverNotFoundException, ConfigurationException,
  +        ClassNotFoundException
  +    {
  +        if ( datasource.getChild( "driver", false) == null)
  +        {
  +            throw new DriverNotFoundException( "JDBC Driver not defined " +
  +                    "for datasource " + datasource.getAttribute( "name" ) );
  +        }
  +        else
  +        {
  +            String driver = datasource.getChild( "driver" ).getValue();
  +            Class.forName( driver );
  +        }
  +        
  +    }
  +    
  +    /**
  +     * 
  +     * @param datasource
  +     * @return
  +     * @throws DbUrlNotFoundException
  +     * @throws ConfigurationException
  +     */
  +    private ConnectionFactory createConnectionFactory(
  +            final Configuration datasource ) throws DbUrlNotFoundException,
  +            ConfigurationException
  +    {
  +        ConnectionFactory connectionFactory = null;
  +        String dbUrl = null;
  +        
  +        if ( datasource.getChild( "db-url", false ) == null)
  +        {
  +            throw new DbUrlNotFoundException( "Database URL not defined " +
  +                    "for datasource " + datasource.getAttribute( "name" ) );
  +        }
  +        else
  +        {
  +            dbUrl = datasource.getChild( "db-url" ).getValue();
  +        }
  +        String uname = datasource.getChild( "username" ).getValue( "" );
  +        String pword = datasource.getChild(" password" ).getValue( "" );
  +        
  +        connectionFactory = new DriverManagerConnectionFactory( dbUrl, uname, pword);
  +        
  +        return connectionFactory;
  +    }
  +    
  +    /**
  +     * 
  +     * @param connFactory
  +     * @param pool
  +     * @param datasource
  +     * @return
  +     * @throws ConfigurationException
  +     */
  +    private PoolableConnectionFactory createPoolableConnectionFactory(
  +            ConnectionFactory connFactory, ObjectPool pool,
  +            Configuration datasource ) throws ConfigurationException
  +    {
  +        PoolableConnectionFactory factory = null;
  +        String query = null;
  +        if ( datasource.getChild( "validation-query", false) != null )
  +        {
  +            query = datasource.getChild( "validation-query" ).getValue();
  +        }
  +        boolean readonly = datasource.getChild( "read-only" ).getValueAsBoolean( false
);
  +        boolean autocommit = datasource.getChild( "auto-commit" ).getValueAsBoolean( true
);
  +        
  +        factory = new PoolableConnectionFactory( connFactory, pool,
  +                null, query, readonly, autocommit );
  +        return factory;
  +    }
  +    
  +    /**
        * Return the working base directory.
        * 
        * @param context the supplied server context
  @@ -184,4 +443,5 @@
       {
           return m_logger;
       }
  +
   }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: cvs-unsubscribe@avalon.apache.org
For additional commands, e-mail: cvs-help@avalon.apache.org


Mime
View raw message