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: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]