package ddth.dasp.framework.dbc; import java.lang.reflect.Field; import java.sql.SQLException; import java.util.concurrent.TimeUnit; import javax.sql.DataSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.jolbox.bonecp.BoneCP; import com.jolbox.bonecp.BoneCPConfig; import com.jolbox.bonecp.BoneCPDataSource; import com.jolbox.bonecp.Statistics; /** * This implementation of {@link IJdbcFactory} utilizes BoneCP as the connection * pooling back-end. * * BoneCP homepape: http://jolbox.com/ * * @author NBThanh <btnguyen2k@gmail.com> * @since class available since v0.2.0 */ public class BoneCpJdbcFactory extends AbstractJdbcFactory { private final static Logger LOGGER = LoggerFactory.getLogger(BoneCpJdbcFactory.class); /** * {@inheritDoc} */ @Override protected void closeDataSource(DataSource ds) throws SQLException { if (ds instanceof BoneCPDataSource) { ((BoneCPDataSource) ds).close(); } } /** * {@inheritDoc} */ @Override protected DataSourceInfo internalGetDataSourceInfo(String name, DataSource ds) { DataSourceInfo dsInfo = internalGetDataSourceInfo(name); if (ds instanceof BoneCPDataSource) { BoneCPDataSource bonecpDs = (BoneCPDataSource) ds; try { // use reflection to get the internal pool // see http://forum.jolbox.com/viewtopic.php?f=3&t=310 Field field = BoneCPDataSource.class.getDeclaredField("pool"); field.setAccessible(true); BoneCP pool = (BoneCP) field.get(bonecpDs); Statistics stats = pool.getStatistics(); int numActives = stats.getTotalLeased(); int numIdles = stats.getTotalCreatedConnections() - numActives; dsInfo.setNumActives(numActives).setNumIdles(numIdles); } catch (Exception e) { throw new RuntimeException(e); } } return dsInfo; } /** * {@inheritDoc} */ @Override protected DataSource buildDataSource(String driver, String connUrl, String username, String password) throws SQLException { return buildDataSource(driver, connUrl, username, password, null); } /** * {@inheritDoc} */ @Override protected DataSource buildDataSource(String driver, String connUrl, String username, String password, DbcpInfo dbcpInfo) throws SQLException { int maxActive = dbcpInfo != null ? dbcpInfo.getMaxActive() : DbcpInfo.DEFAULT_MAX_ACTIVE; long maxWaitTime = dbcpInfo != null ? dbcpInfo.getMaxWaitTime() : DbcpInfo.DEFAULT_MAX_WAIT_TIME; int maxIdle = dbcpInfo != null ? dbcpInfo.getMaxIdle() : DbcpInfo.DEFAULT_MAX_IDLE; int minIdle = dbcpInfo != null ? dbcpInfo.getMinIdle() : DbcpInfo.DEFAULT_MIN_IDLE; if (LOGGER.isDebugEnabled()) { LOGGER.debug("Building a datasource {driver:" + driver + ";connUrl:" + connUrl + ";username:" + username + ";maxActive:" + maxActive + ";maxWait:" + maxWaitTime + ";minIdle:" + minIdle + ";maxIdle:" + maxIdle + "}..."); } try { /* * Note: we load the driver class here! */ Class.forName(driver); } catch (ClassNotFoundException e) { throw new SQLException(e); } BoneCPConfig bonecpConfig = new BoneCPConfig(); bonecpConfig.setStatisticsEnabled(true); bonecpConfig.setAcquireRetryAttempts(2); bonecpConfig.setAcquireRetryDelay(5000, TimeUnit.MILLISECONDS); bonecpConfig.setConnectionTestStatement(getValidationQuery(driver)); bonecpConfig.setConnectionTimeout(maxWaitTime, TimeUnit.MILLISECONDS); int numProcessors = Runtime.getRuntime().availableProcessors(); int numPartitions = Math.min(4, Math.max(2, numProcessors)); int maxConnsPerPartition = maxActive / numPartitions > 1 ? maxActive / numPartitions : 1; int minConnsPerPartition = minIdle / numPartitions; bonecpConfig.setPartitionCount(numPartitions); bonecpConfig.setMaxConnectionsPerPartition(maxConnsPerPartition); bonecpConfig.setMinConnectionsPerPartition(minConnsPerPartition); bonecpConfig.setJdbcUrl(connUrl); bonecpConfig.setUsername(username); bonecpConfig.setPassword(password); BoneCPDataSource bonecpDs = new BoneCPDataSource(bonecpConfig); if (bonecpDs != null) { String dsName = calcHash(driver, connUrl, username, password, dbcpInfo); DataSourceInfo dsInfo = internalGetDataSourceInfo(dsName); dsInfo.setMaxActives(numPartitions * maxConnsPerPartition) .setMaxIdles(numPartitions * maxConnsPerPartition).setMaxWait(maxWaitTime) .setMinIdles(numPartitions * minConnsPerPartition); } return bonecpDs; } }