All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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