
com.day.commons.datasource.jdbcpool.JdbcPoolService Maven / Gradle / Ivy
/* Copyright 1997-2006 Day Management AG
* Barfuesserplatz 6, 4001 Basel, Switzerland
* All Rights Reserved.
*
* This software is the confidential and proprietary information of
* Day Management AG, ("Confidential Information"). You shall not
* disclose such Confidential Information and shall use it only in
* accordance with the terms of the license agreement you entered into
* with Day.
*/
package com.day.commons.datasource.jdbcpool;
import java.util.Dictionary;
import java.util.Hashtable;
import javax.sql.DataSource;
import org.apache.commons.dbcp.ConnectionFactory;
import org.apache.commons.dbcp.DriverManagerConnectionFactory;
import org.apache.commons.dbcp.PoolableConnectionFactory;
import org.apache.commons.dbcp.PoolingDataSource;
import org.apache.commons.pool.KeyedObjectPoolFactory;
import org.apache.commons.pool.impl.GenericObjectPool;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.ConfigurationPolicy;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.commons.osgi.PropertiesUtil;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.log.LogService;
import com.day.commons.datasource.poolservice.DataSourcePoolProvider;
/**
* A DataSourcePoolProvider that manages pooled j2ee DataSources.
*
* Declared as a configuration factory - we want one instance of this component
* for each configured DataSource
*/
@Component(
label = "%pool.component.name",
description = "%pool.component.description",
metatype = true,
configurationFactory = true,
policy = ConfigurationPolicy.REQUIRE
)
@Service(value = DataSourcePoolProvider.class)
@Properties({
@Property(name = "service.description", value="Day Commons Data Source Pool implementation"),
@Property(name="service.vendor", value="Day Management AG")
})
public class JdbcPoolService implements DataSourcePoolProvider {
@Reference
private LogService log;
/**
* Default size of our pools
*/
public static final int DEFAULT_POOL_SIZE = 10;
/**
* Default time to wait for an available connection, in msec
*/
public static final int DEFAULT_MAX_WAIT_MSEC = 1000;
/**
* If DataSourceConfig.maxWaitMsec has this value, fail immediately on empty pool
*/
public static final int MAX_WAIT_DONT_WAIT = 0;
/**
* If DataSourceConfig.maxWaitMsec has this value, block forever on empty pool
*/
public static final int MAX_WAIT_BLOCK = -1;
@Property(value = "com.somevendor.somedriver.Driver")
public static final String OSGI_PROPERTY_JDBC_DRIVER_CLASS = "jdbc.driver.class";
@Property(value = "jdbc:somedriver:someDB;param=value")
public static final String OSGI_PROPERTY_JDBC_CONNECTION_URI = "jdbc.connection.uri";
@Property(value = "")
public static final String OSGI_PROPERTY_JDBC_USERNAME = "jdbc.username";
@Property(value = "")
public static final String OSGI_PROPERTY_JDBC_PASSWORD = "jdbc.password";
@Property(value = "")
public static final String OSGI_PROPERTY_JDBC_VALIDATION_QUERY = "jdbc.validation.query";
@Property(boolValue = false)
public static final String OSGI_PROPERTY_DEFAULT_READ_ONLY = "default.readonly";
@Property(boolValue = true)
public static final String OSGI_PROPERTY_DEFAULT_AUTO_COMMIT = "default.autocommit";
@Property(longValue = DEFAULT_POOL_SIZE)
public static final String OSGI_PROPERTY_POOL_SIZE = "pool.size";
@Property(longValue = DEFAULT_MAX_WAIT_MSEC)
public static final String OSGI_PROPERTY_MAX_WAIT_MSEC = "pool.max.wait.msec";
@Property(value = "")
public static final String OSGI_PROPERTY_DATASOURCE_NAME = "datasource.name";
@Property(value = {}, cardinality = 1024)
public static final String OSGI_PROPERTY_DATASOURCE_SVC_PROPS = "datasource.svc.properties";
/**
* name of our DataSource
*/
private String name;
/**
* our pooled DataSource
*/
private PoolingDataSource dataSource;
private GenericObjectPool connectionPool;
private ServiceRegistration dsRegistration;
static class DataSourceConfig {
String driverClassToLoad;
String connectionURI;
String username;
String password;
String validationQuery;
boolean defaultReadOnly;
boolean defaultAutoCommit;
long poolSize = DEFAULT_POOL_SIZE;
long maxWaitMsec = DEFAULT_MAX_WAIT_MSEC;
}
/**
* @inheritDoc
*/
public Object getDataSource(String name) {
if (name.equals(this.name)) {
return dataSource;
}
return null;
}
public String[] getNames() {
if (name == null) {
return new String[0];
} else {
return new String[]{name};
}
}
protected void activate(ComponentContext componentContext) throws Exception {
if (name != null) {
throw new IllegalStateException("Already activated with name=" + name);
}
@SuppressWarnings("unchecked")
Dictionary properties = componentContext.getProperties();
final String newName = (String) properties.get(OSGI_PROPERTY_DATASOURCE_NAME);
if (newName == null || newName.trim().length() == 0) {
throw new Exception("Missing configuration property " + OSGI_PROPERTY_DATASOURCE_NAME);
}
if (log != null) {
log.log(LogService.LOG_INFO, "Configuring and activating data source with name=" + newName);
}
setupDataSource(newName, createConfig(properties));
Dictionary dsProps = new Hashtable();
dsProps.put(OSGI_PROPERTY_DATASOURCE_NAME, newName);
String[] dsCfgProps = (String[]) componentContext.getProperties().get(OSGI_PROPERTY_DATASOURCE_SVC_PROPS);
if (dsCfgProps != null) {
for (String nv: dsCfgProps) {
int idx = nv.indexOf('=');
if (idx > 0) {
dsProps.put(nv.substring(0, idx).trim(), nv.substring(idx+1).trim());
}
}
}
if (dataSource != null) {
dsRegistration = componentContext.getBundleContext().registerService(DataSource.class.getName(), dataSource, dsProps);
}
}
protected void deactivate(ComponentContext componentContext) {
if (log != null) {
log.log(LogService.LOG_INFO, "deactivating data source with name=" + name);
}
// TODO any cleanup to do on the datasource?
name = null;
if (dsRegistration != null) {
dsRegistration.unregister();
dsRegistration = null;
}
if (connectionPool != null) {
try {
connectionPool.close();
} catch (Exception e) {
if (log != null) {
log.log(LogService.LOG_ERROR, "Error while closing connection pool", e);
}
}
connectionPool = null;
}
dataSource = null;
}
/**
* Setup our pooled DataSource
*/
void setupDataSource(String newName, DataSourceConfig cfg) {
if (name != null) {
throw new IllegalStateException("Already configured with name '" + name + "'");
}
// Load JDBC driver class if needed, to activate it
initalizeDriver(cfg.driverClassToLoad);
// This is based on the
// http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/doc/ManualPoolingDataSourceExample.java?view=markup
// example
connectionPool = new GenericObjectPool(null);
connectionPool.setMaxActive((int) cfg.poolSize);
// Setup strategy to handle the "pool is empty" case
// TODO - for now we only support positive maxWait values
if (cfg.maxWaitMsec <= 0) {
throw new IllegalArgumentException("For now, DataSourceConfig.maxWaitMsec must be >= 0");
}
connectionPool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_BLOCK);
connectionPool.setMaxWait(cfg.maxWaitMsec);
ConnectionFactory connectionFactory =
new DriverManagerConnectionFactory(cfg.connectionURI, cfg.username, cfg.password);
final KeyedObjectPoolFactory kopf = null;
new PoolableConnectionFactory(connectionFactory, connectionPool, kopf,
cfg.validationQuery, cfg.defaultReadOnly, cfg.defaultAutoCommit);
dataSource = new PoolingDataSource(connectionPool);
if (log != null) {
log.log(LogService.LOG_INFO,
"Datasource configured, name=" + newName
+ ", connectionURI=" + cfg.connectionURI
+ ", default readonly=" + cfg.defaultReadOnly
+ ", default autocommit=" + cfg.defaultAutoCommit
+ ", validation query=" + cfg.validationQuery
);
}
// set name only if no exception up to now
name = newName;
}
protected static String nullIfEmpty(String str) {
if (str == null || str.trim().length() == 0) {
return null;
}
return str;
}
/**
* Create a config object from the Dictionary that our ComponentContext provides
*/
static DataSourceConfig createConfig(Dictionary params) {
final DataSourceConfig result = new DataSourceConfig();
result.driverClassToLoad = PropertiesUtil.toString(params.get(OSGI_PROPERTY_JDBC_DRIVER_CLASS), null);
result.connectionURI = PropertiesUtil.toString(params.get(OSGI_PROPERTY_JDBC_CONNECTION_URI), null);
result.username = nullIfEmpty(PropertiesUtil.toString(params.get(OSGI_PROPERTY_JDBC_USERNAME), null));
result.password = nullIfEmpty(PropertiesUtil.toString(params.get(OSGI_PROPERTY_JDBC_PASSWORD), null));
result.validationQuery = nullIfEmpty(PropertiesUtil.toString(params.get(OSGI_PROPERTY_JDBC_VALIDATION_QUERY), null));
result.defaultReadOnly = PropertiesUtil.toBoolean(params.get(OSGI_PROPERTY_DEFAULT_READ_ONLY), false);
result.defaultAutoCommit = PropertiesUtil.toBoolean(params.get(OSGI_PROPERTY_DEFAULT_AUTO_COMMIT), true);
result.poolSize = PropertiesUtil.toLong(params.get(OSGI_PROPERTY_POOL_SIZE), DEFAULT_POOL_SIZE);
result.maxWaitMsec = PropertiesUtil.toLong(params.get(OSGI_PROPERTY_MAX_WAIT_MSEC), DEFAULT_MAX_WAIT_MSEC);
return result;
}
private void initalizeDriver(final String driverClassName) {
if (driverClassName != null) {
try {
/*
* Class must be initialized for it to register itself with the
* JDBC driver manager. Thus we create a throw-away instance
* assuming the class initialization side-effect
*/
final ClassLoader loader = getClass().getClassLoader();
final Class> driverClass = loader.loadClass(driverClassName);
driverClass.newInstance();
} catch (Throwable t) {
throw new IllegalArgumentException("Cannot initialize driver '"
+ driverClassName + "'", t);
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy