org.apache.avalon.excalibur.datasource.ResourceLimitingJdbcDataSource Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied.
*
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.avalon.excalibur.datasource;
import java.sql.Connection;
import java.sql.SQLException;
import org.apache.avalon.framework.activity.Disposable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.excalibur.instrument.AbstractLogEnabledInstrumentable;
import org.apache.avalon.excalibur.pool.TraceableResourceLimitingPool;
/**
* The ResourceLimiting implementation for DataSources in Avalon.
* This uses the normal java.sql.Connection
object and
* java.sql.DriverManager
.
*
* This datasource pool implementation is designed to make as many
* database connections as are needed available without placing
* undo load on the database server.
*
* If an application under normal load needs 3 database connections
* for example, then the max
pool size should be set
* to a value like 10. This will allow the pool to grow to accomodate
* a sudden spike in load without allowing the pool to grow to such
* a large size as to place undo load on the database server. The
* pool's trimming features will keep track of how many connections
* are actually needed and close those connections which are no longer
* required.
*
* Configuration Example:
*
* <rl-jdbc>
* <pool-controller max="10" max-strict="true"
* blocking="true" timeout="-1"
* trim-interval="60000"
* connection-class="my.overrided.ConnectionClass">
* <keep-alive disable="false" age="5000">select 1</keep-alive>
* </pool-controller>
* <auto-commit>true</auto-commit>
* <driver>com.database.jdbc.JdbcDriver</driver>
* <dburl>jdbc:driver://host/mydb</dburl>
* <user>username</user>
* <password>password</password>
* </rl-jdbc>
*
*
* Roles Example:
*
* <role name="org.apache.avalon.excalibur.datasource.DataSourceComponentSelector"
* shorthand="datasources"
* default-class="org.apache.avalon.excalibur.component.ExcaliburComponentSelector">
* <hint shorthand="rl-jdbc"
* class="org.apache.avalon.excalibur.datasource.ResourceLimitingJdbcDataSource"/>
* </role>
*
*
* Configuration Attributes:
*
* - The
max
attribute is used to set the maximum
* number of connections which will be opened. See the
* blocking
attribute. (Defaults to "3")
*
* - The
max-strict
attribute is used to determine whether
* or not the maximum number of connections can be exceeded. If true,
* then an exception will be thrown if more than max connections are
* requested and blocking is false. (Defaults to "true")
* WARNING: In most cases, this value
* should always be set to true. Setting it to false means that under
* heavy load, your application may open a very large number of
* connections to the database. Some database servers behave very poorly
* under large connection loads and can even crash.
*
* - The
blocking
attributes is used to specify the
* behavior of the DataSource pool when an attempt is made to allocate
* more than max
concurrent connections. If true, the
* request will block until a connection is released, otherwise, a
* NoAvailableConnectionException will be thrown. Ignored if
* max-strict
is false. (Defaults to "true")
*
* - The
timeout
attribute is used to specify the
* maximum amount of time in milliseconds that a request for a
* connection will be allowed to block before a
* NoAvailableConnectionException is thrown. A value of "0" specifies
* that the block will never timeout. (Defaults to "0")
*
* - The
trim-interval
attribute is used to specify how
* long idle connections will be maintained in the pool before being
* closed. For a complete explanation on how this works, see {@link
* org.apache.avalon.excalibur.pool.ResourceLimitingPool#trim()}
* (Defaults to "60000", 1 minute)
*
* - The
connection-class
attribute is used to override
* the Connection class returned by the DataSource from calls to
* getConnection(). Set this to
* "org.apache.avalon.excalibur.datasource.Jdbc3Connection" to gain
* access to JDBC3 features. Jdbc3Connection does not exist if your
* JVM does not support JDBC3. (Defaults to
* "org.apache.avalon.excalibur.datasource.JdbcConnection")
*
* - The
keep-alive
element is used to override the
* query used to monitor the health of connections. If a connection
* has not been used for 5 seconds then before returning the
* connection from a call to getConnection(), the connection is first
* used to ping the database to make sure that it is still alive.
* Setting the disable
attribute to true will disable
* this feature. Setting the age
allows the 5 second age to
* be overridden. (Defaults to a query of "SELECT 1" and being enabled)
*
* - The
auto-commit
element is used to determine the
* default auto-commit mode for the Connection
s returned
* by this DataSource
.
*
* - The
driver
element is used to specify the driver
* to use when connecting to the database. The specified class must
* be in the classpath. (Required)
*
* - The
dburl
element is the JDBC connection string
* which will be used to connect to the database. (Required)
*
* - The
user
and password
attributes are
* used to specify the user and password for connections to the
* database. (Required)
*
*
* @avalon.component
* @avalon.service type=DataSourceComponent
* @avalon.service type=TraceableDataSourceComponent
* @x-avalon.info name=rl-jdbc
* @x-avalon.lifestyle type=singleton
*
* @author Avalon Development Team
* @version CVS $Revision: 1.5 $ $Date: 2004/03/30 15:58:50 $
* @since 4.1
*/
public class ResourceLimitingJdbcDataSource
extends AbstractLogEnabledInstrumentable
implements TraceableDataSourceComponent, Disposable
{
private boolean m_configured;
private boolean m_disposed;
protected TraceableResourceLimitingPool m_pool;
/*---------------------------------------------------------------
* Constructors
*-------------------------------------------------------------*/
public ResourceLimitingJdbcDataSource()
{
}
/*---------------------------------------------------------------
* DataSourceComponent Methods
*-------------------------------------------------------------*/
/**
* Gets the Connection to the database
*
* @throws NoValidConnectionException when there is no valid Connection wrapper
* available in the classloader.
*
* @throws NoAvailableConnectionException when there are no more available
* Connections in the pool.
*/
public Connection getConnection()
throws SQLException
{
if( !m_configured ) throw new IllegalStateException( "Not Configured" );
if( m_disposed ) throw new IllegalStateException( "Already Disposed" );
Object connection;
try
{
connection = m_pool.get();
if (null == connection)
{
throw new SQLException("Could not return Connection");
}
}
catch( SQLException e )
{
if( getLogger().isWarnEnabled() )
{
getLogger().warn( "Could not return Connection", e );
}
throw e;
}
catch( Exception e )
{
if( getLogger().isWarnEnabled() )
{
getLogger().warn( "Could not return Connection", e );
}
throw new NoAvailableConnectionException( e.getMessage() );
}
return (Connection)connection;
}
/**
* Returns a snapshot of the current state of the pool.
*
* @return A snapshot of the current pool state.
*/
public TraceableResourceLimitingPool.State getState()
{
return m_pool.getState();
}
/*---------------------------------------------------------------
* DataSourceComponent (Configurable) Methods
*-------------------------------------------------------------*/
/**
* Pass the Configuration
to the Configurable
* class. This method must always be called after the constructor
* and before any other method.
*
* @param configuration the class configurations.
*/
public void configure( Configuration configuration ) throws ConfigurationException
{
if( m_configured ) throw new IllegalStateException( "Already Configured" );
final String driver = configuration.getChild( "driver" ).getValue( "" );
final String dburl = configuration.getChild( "dburl" ).getValue( null );
final String user = configuration.getChild( "user" ).getValue( null );
final String passwd = configuration.getChild( "password" ).getValue( null );
final Configuration controller = configuration.getChild( "pool-controller" );
final int keepAliveAge = controller.getChild( "keep-alive" ).getAttributeAsInteger( "age", 5000 );
String keepAlive = controller.getChild( "keep-alive" ).getValue( "SELECT 1" );
final boolean disableKeepAlive =
controller.getChild( "keep-alive" ).getAttributeAsBoolean( "disable", false );
final int max = controller.getAttributeAsInteger( "max", 3 );
final boolean maxStrict = controller.getAttributeAsBoolean( "max-strict", true );
final boolean blocking = controller.getAttributeAsBoolean( "blocking", true );
final long timeout = controller.getAttributeAsLong( "timeout", 0 );
final long trimInterval = controller.getAttributeAsLong( "trim-interval", 60000 );
final boolean trace = controller.getAttributeAsBoolean( "trace", false );
final boolean oradb = controller.getAttributeAsBoolean( "oradb", false );
final boolean autoCommit = configuration.getChild( "auto-commit" ).getValueAsBoolean( true );
// Get the JdbcConnection class. The factory will resolve one if null.
final String connectionClass = controller.getAttribute( "connection-class", null );
final int l_max;
// If driver is specified....
if( !"".equals( driver ) )
{
if( getLogger().isDebugEnabled() )
{
getLogger().debug( "Loading new driver: " + driver );
}
try
{
Class.forName( driver, true, Thread.currentThread().getContextClassLoader() );
}
catch( ClassNotFoundException cnfe )
{
if( getLogger().isWarnEnabled() )
{
getLogger().warn( "Could not load driver: " + driver, cnfe );
}
}
}
// Validate the max pool size values.
if( max < 1 )
{
if( getLogger().isWarnEnabled() )
{
getLogger().warn( "Maximum number of connections specified must be at least 1." );
}
l_max = 1;
}
else
{
l_max = max;
}
// If the keepAlive disable attribute was set, then set the keepAlive query to null,
// disabling it.
if( disableKeepAlive )
{
keepAlive = null;
}
// If the oradb attribute was set, then override the keepAlive query.
// This will override any specified keepalive value even if disabled.
// (Deprecated, but keep this for backwards-compatability)
if( oradb )
{
keepAlive = "SELECT 1 FROM DUAL";
if( getLogger().isWarnEnabled() )
{
getLogger().warn( "The oradb attribute is deprecated, please use the" +
"keep-alive element instead." );
}
}
final JdbcConnectionFactory factory = new JdbcConnectionFactory
( dburl, user, passwd, autoCommit, keepAlive, keepAliveAge, connectionClass );
factory.enableLogging( getLogger() );
try
{
m_pool = new ResourceLimitingJdbcConnectionPool(
factory, l_max, maxStrict, blocking, timeout, trimInterval, trace, autoCommit );
m_pool.enableLogging( getLogger() );
addChildInstrumentable( m_pool );
}
catch( Exception e )
{
if( getLogger().isDebugEnabled() )
{
getLogger().debug( "Error configuring ResourceLimitingJdbcDataSource", e );
}
throw new ConfigurationException( "Error configuring ResourceLimitingJdbcDataSource", e );
}
m_configured = true;
}
/*---------------------------------------------------------------
* Disposable Methods
*-------------------------------------------------------------*/
/**
* The dispose operation is called at the end of a components lifecycle.
* This method will be called after Startable.stop() method (if implemented
* by component). Components use this method to release and destroy any
* resources that the Component owns.
*/
public void dispose()
{
m_disposed = true;
m_pool.dispose();
m_pool = null;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy