package org.logicalcobwebs.proxool;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Properties;
import java.util.StringTokenizer;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.RefAddr;
import javax.naming.Reference;
import javax.naming.StringRefAddr;
import javax.naming.spi.ObjectFactory;
import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class ProxoolDataSource
implements DataSource, ObjectFactory
{
private static final Log LOG = LogFactory.getLog(ProxoolDataSource.class);
private int loginTimeout;
private PrintWriter logWriter;
private String alias;//是连接池的别名
private String driver;//数据库驱动
private String fatalSqlExceptionWrapperClass;
private long houseKeepingSleepTime;//保留线程处于睡眠状态的最长时间,house keeper 的职责就是检查各个连接的状态,并判断是否需要销毁或者创建.
//自动侦察各个连接状态的时间间隔(毫秒),侦察到空闲的连接就马上回收,超时的销毁 默认30秒,视乎不允许被赋值;
private String houseKeepingTestSql;// 如果发现了空闲的数据库连接.house keeper 将会用这个语句来测试.这个语句最好非常快的被执行.如果没有定义,测试过程将会被忽略。
private long maximumActiveTime;//如果housekeeper 检测到某个线程的活动时间大于这个数值.它将会杀掉这个线程.所以确认一下你的服务器的带宽.然后定一个合适的值.默认是5分钟
private int maximumConnectionCount;//最大连接数
private long maximumConnectionLifetime;//一个线程的最大寿命.
private int minimumConnectionCount;//最小链接数
private long overloadWithoutRefusalLifetime;//这可以帮助我们确定连接池的状态。如果我们已经拒绝了一个连接在这个设定值(毫秒),然后被认为是超载。默认为60秒。
private String password;//数据库密码
private int prototypeCount;//最少保持的空闲连接数 (默认5个)-->
private long recentlyStartedThreshold;//这可以帮助我们确定连接池的状态,连接数少还是多或超载。只要至少有一个连接已开始在此值(毫秒)内,或者有一些多余的可用连接,那么我们假设连接池是开启的。默认为60秒
private int simultaneousBuildThrottle;//这是我们可一次建立的最大连接数。那就是新增的连接请求,但还没有可供使用的连接。由于连接可以使用多线程,在有限的时间之间建立联系从而带来可用连接,但是我们需要通过一些方式确认一些线程并不是立即响应连接请求的,默认是10。
private String statistics;//连接池使用状况统计。 参数“10s,1m,1d”
private String statisticsLogLevel;//日志统计跟踪类型。 参数“ERROR”或 “INFO”
private boolean trace;// 如果为true,那么每个被执行的SQL语句将会在执行期被log记录(DEBUG LEVEL).你也可以注册一个ConnectionListener (参看ProxoolFacade)得到这些信息.
private String driverUrl;//数据库链接字符串
private String user;//数据库用户名
private boolean verbose;
private boolean jmx;
private String jmxAgentId;
private boolean testBeforeUse;//如果为true,在每个连接被测试前都会服务这个连接,如果一个连接失败,那么将被丢弃,另一个连接将会被处理,如果所有连接都失败,一个新的连接将会被建立。否则将会抛出一个SQLException异常。
private boolean testAfterUse;//如果为true,在每个连接被测试后都会服务这个连接,使其回到连接池中,如果连接失败,那么将被废弃
private Properties delegateProperties = new Properties();
private String fatalSqlExceptionsAsString;
public ProxoolDataSource()
{
reset();
}
public ProxoolDataSource(String alias) {
this.alias = alias;
}
public Connection getConnection()
throws SQLException
{
ConnectionPool cp = null;
try {
if (!ConnectionPoolManager.getInstance().isPoolExists(this.alias)) {
registerPool();
}
cp = ConnectionPoolManager.getInstance().getConnectionPool(this.alias);
return cp.getConnection();
} catch (ProxoolException e) {
LOG.error("Problem getting connection", e);
}throw new SQLException(e.toString());
}
private synchronized void registerPool()
throws ProxoolException
{
if (!ConnectionPoolManager.getInstance().isPoolExists(this.alias)) {
ConnectionPoolDefinition cpd = new ConnectionPoolDefinition();
cpd.setAlias(getAlias());
cpd.setDriver(getDriver());
cpd.setFatalSqlExceptionsAsString(getFatalSqlExceptionsAsString());
cpd.setFatalSqlExceptionWrapper(getFatalSqlExceptionWrapperClass());
cpd.setHouseKeepingSleepTime(getHouseKeepingSleepTime());
cpd.setHouseKeepingTestSql(getHouseKeepingTestSql());
cpd.setMaximumActiveTime(getMaximumActiveTime());
cpd.setMaximumConnectionCount(getMaximumConnectionCount());
cpd.setMaximumConnectionLifetime(getMaximumConnectionLifetime());
cpd.setMinimumConnectionCount(getMinimumConnectionCount());
cpd.setOverloadWithoutRefusalLifetime(getOverloadWithoutRefusalLifetime());
cpd.setPrototypeCount(getPrototypeCount());
cpd.setRecentlyStartedThreshold(getRecentlyStartedThreshold());
cpd.setSimultaneousBuildThrottle(getSimultaneousBuildThrottle());
cpd.setStatistics(getStatistics());
cpd.setStatisticsLogLevel(getStatisticsLogLevel());
cpd.setTrace(isTrace());
cpd.setUrl(getDriverUrl());
cpd.setVerbose(isVerbose());
cpd.setJmx(isJmx());
cpd.setJmxAgentId(getJmxAgentId());
cpd.setTestAfterUse(isTestAfterUse());
cpd.setTestBeforeUse(isTestBeforeUse());
cpd.setDelegateProperties(this.delegateProperties);
cpd.setUser(getUser());
cpd.setPassword(getPassword());
ProxoolFacade.registerConnectionPool(cpd);
}
}
public Object getObjectInstance(Object refObject, Name name, Context context, Hashtable hashtable)
throws Exception
{
if (!(refObject instanceof Reference)) {
return null;
}
Reference reference = (Reference)refObject;
if (!ConnectionPoolManager.getInstance().isPoolExists(reference.get("proxool.alias").toString())) {
populatePropertiesFromReference(reference);
}
return this;
}
public String getAlias()
{
return this.alias;
}
public void setAlias(String alias)
{
this.alias = alias;
}
public String getDriverUrl()
{
return this.driverUrl;
}
public void setDriverUrl(String url)
{
this.driverUrl = url;
}
public String getDriver()
{
return this.driver;
}
public void setDriver(String driver)
{
this.driver = driver;
}
public long getMaximumConnectionLifetime()
{
return this.maximumConnectionLifetime;
}
public void setMaximumConnectionLifetime(int maximumConnectionLifetime)
{
this.maximumConnectionLifetime = maximumConnectionLifetime;
}
public int getPrototypeCount()
{
return this.prototypeCount;
}
public void setPrototypeCount(int prototypeCount)
{
this.prototypeCount = prototypeCount;
}
public int getMinimumConnectionCount()
{
return this.minimumConnectionCount;
}
public void setMinimumConnectionCount(int minimumConnectionCount)
{
this.minimumConnectionCount = minimumConnectionCount;
}
public int getMaximumConnectionCount()
{
return this.maximumConnectionCount;
}
public void setMaximumConnectionCount(int maximumConnectionCount)
{
this.maximumConnectionCount = maximumConnectionCount;
}
public long getHouseKeepingSleepTime()
{
return this.houseKeepingSleepTime;
}
public void setHouseKeepingSleepTime(int houseKeepingSleepTime)
{
this.houseKeepingSleepTime = houseKeepingSleepTime;
}
public int getSimultaneousBuildThrottle()
{
return this.simultaneousBuildThrottle;
}
public void setSimultaneousBuildThrottle(int simultaneousBuildThrottle)
{
this.simultaneousBuildThrottle = simultaneousBuildThrottle;
}
public long getRecentlyStartedThreshold()
{
return this.recentlyStartedThreshold;
}
public void setRecentlyStartedThreshold(int recentlyStartedThreshold)
{
this.recentlyStartedThreshold = recentlyStartedThreshold;
}
public long getOverloadWithoutRefusalLifetime()
{
return this.overloadWithoutRefusalLifetime;
}
public void setOverloadWithoutRefusalLifetime(int overloadWithoutRefusalLifetime)
{
this.overloadWithoutRefusalLifetime = overloadWithoutRefusalLifetime;
}
public long getMaximumActiveTime()
{
return this.maximumActiveTime;
}
public void setMaximumActiveTime(long maximumActiveTime)
{
this.maximumActiveTime = maximumActiveTime;
}
public boolean isVerbose()
{
return this.verbose;
}
public void setVerbose(boolean verbose)
{
this.verbose = verbose;
}
public boolean isTrace()
{
return this.trace;
}
public void setTrace(boolean trace)
{
this.trace = trace;
}
public String getStatistics()
{
return this.statistics;
}
public void setStatistics(String statistics)
{
this.statistics = statistics;
}
public String getStatisticsLogLevel()
{
return this.statisticsLogLevel;
}
public void setStatisticsLogLevel(String statisticsLogLevel)
{
this.statisticsLogLevel = statisticsLogLevel;
}
public String getFatalSqlExceptionsAsString()
{
return this.fatalSqlExceptionsAsString;
}
public void setFatalSqlExceptionsAsString(String fatalSqlExceptionsAsString)
{
this.fatalSqlExceptionsAsString = fatalSqlExceptionsAsString;
}
public String getFatalSqlExceptionWrapperClass()
{
return this.fatalSqlExceptionWrapperClass;
}
public void setFatalSqlExceptionWrapperClass(String fatalSqlExceptionWrapperClass)
{
this.fatalSqlExceptionWrapperClass = fatalSqlExceptionWrapperClass;
}
public String getHouseKeepingTestSql()
{
return this.houseKeepingTestSql;
}
public void setHouseKeepingTestSql(String houseKeepingTestSql)
{
this.houseKeepingTestSql = houseKeepingTestSql;
}
public String getUser()
{
return this.user;
}
public void setUser(String user)
{
this.user = user;
}
public String getPassword()
{
return this.password;
}
public void setPassword(String password)
{
this.password = password;
}
public boolean isJmx()
{
return this.jmx;
}
public void setJmx(boolean jmx)
{
this.jmx = jmx;
}
public String getJmxAgentId()
{
return this.jmxAgentId;
}
public void setJmxAgentId(String jmxAgentId)
{
this.jmxAgentId = jmxAgentId;
}
public boolean isTestBeforeUse()
{
return this.testBeforeUse;
}
public void setTestBeforeUse(boolean testBeforeUse)
{
this.testBeforeUse = testBeforeUse;
}
public boolean isTestAfterUse()
{
return this.testAfterUse;
}
public void setTestAfterUse(boolean testAfterUse)
{
this.testAfterUse = testAfterUse;
}
public void setDelegateProperties(String properties)
{
StringTokenizer stOuter = new StringTokenizer(properties, ",");
while (stOuter.hasMoreTokens()) {
StringTokenizer stInner = new StringTokenizer(stOuter.nextToken(), "=");
if (stInner.countTokens() == 1)
{
this.delegateProperties.put(stInner.nextToken().trim(), "");
} else if (stInner.countTokens() == 2)
this.delegateProperties.put(stInner.nextToken().trim(), stInner.nextToken().trim());
else
throw new IllegalArgumentException("Unexpected delegateProperties value: '" + properties + "'. Expected 'name=value'");
}
}
private void populatePropertiesFromReference(Reference reference)
{
RefAddr property = reference.get("proxool.alias");
if (property != null) {
setAlias(property.getContent().toString());
}
property = reference.get("proxool.driver-class");
if (property != null) {
setDriver(property.getContent().toString());
}
property = reference.get("proxool.fatal-sql-exception-wrapper-class");
if (property != null) {
setFatalSqlExceptionWrapperClass(property.getContent().toString());
}
property = reference.get("proxool.house-keeping-sleep-time");
if (property != null) {
setHouseKeepingSleepTime(Integer.valueOf(property.getContent().toString()).intValue());
}
property = reference.get("proxool.house-keeping-test-sql");
if (property != null) {
setHouseKeepingTestSql(property.getContent().toString());
}
property = reference.get("proxool.maximum-connection-count");
if (property != null) {
setMaximumConnectionCount(Integer.valueOf(property.getContent().toString()).intValue());
}
property = reference.get("proxool.maximum-connection-lifetime");
if (property != null) {
setMaximumConnectionLifetime(Integer.valueOf(property.getContent().toString()).intValue());
}
property = reference.get("proxool.maximum-active-time");
if (property != null) {
setMaximumActiveTime(Long.valueOf(property.getContent().toString()).intValue());
}
property = reference.get("proxool.minimum-connection-count");
if (property != null) {
setMinimumConnectionCount(Integer.valueOf(property.getContent().toString()).intValue());
}
property = reference.get("proxool.overload-without-refusal-lifetime");
if (property != null) {
setOverloadWithoutRefusalLifetime(Integer.valueOf(property.getContent().toString()).intValue());
}
property = reference.get("password");
if (property != null) {
setPassword(property.getContent().toString());
}
property = reference.get("proxool.prototype-count");
if (property != null) {
setPrototypeCount(Integer.valueOf(property.getContent().toString()).intValue());
}
property = reference.get("proxool.recently-started-threshold");
if (property != null) {
setRecentlyStartedThreshold(Integer.valueOf(property.getContent().toString()).intValue());
}
property = reference.get("proxool.simultaneous-build-throttle");
if (property != null) {
setSimultaneousBuildThrottle(Integer.valueOf(property.getContent().toString()).intValue());
}
property = reference.get("proxool.statistics");
if (property != null) {
setStatistics(property.getContent().toString());
}
property = reference.get("proxool.statistics-log-level");
if (property != null) {
setStatisticsLogLevel(property.getContent().toString());
}
property = reference.get("proxool.trace");
if (property != null) {
setTrace("true".equalsIgnoreCase(property.getContent().toString()));
}
property = reference.get("proxool.driver-url");
if (property != null) {
setDriverUrl(property.getContent().toString());
}
property = reference.get("user");
if (property != null) {
setUser(property.getContent().toString());
}
property = reference.get("proxool.verbose");
if (property != null) {
setVerbose("true".equalsIgnoreCase(property.getContent().toString()));
}
property = reference.get("proxool.jmx");
if (property != null) {
setJmx("true".equalsIgnoreCase(property.getContent().toString()));
}
property = reference.get("proxool.jmx-agent-id");
if (property != null) {
setJmxAgentId(property.getContent().toString());
}
property = reference.get("proxool.test-before-use");
if (property != null) {
setTestBeforeUse("true".equalsIgnoreCase(property.getContent().toString()));
}
property = reference.get("proxool.test-after-use");
if (property != null) {
setTestAfterUse("true".equalsIgnoreCase(property.getContent().toString()));
}
Enumeration e = reference.getAll();
while (e.hasMoreElements()) {
StringRefAddr stringRefAddr = (StringRefAddr)e.nextElement();
String name = stringRefAddr.getType();
String content = stringRefAddr.getContent().toString();
if (name.indexOf("proxool.") != 0)
this.delegateProperties.put(name, content);
}
}
private void reset()
{
this.driverUrl = null;
this.driver = null;
this.maximumConnectionLifetime = 14400000L;
this.prototypeCount = 0;//
this.minimumConnectionCount = 0;//最小链接数
this.maximumConnectionCount = 15;//最大链接数
this.houseKeepingSleepTime = 30000L;
this.houseKeepingTestSql = null;
this.simultaneousBuildThrottle = 10;
this.recentlyStartedThreshold = 60000L;//
this.overloadWithoutRefusalLifetime = 60000L;//
this.maximumActiveTime = 300000L;
this.verbose = false;
this.trace = false;
this.statistics = null;
this.statisticsLogLevel = null;
this.delegateProperties.clear();
}
public PrintWriter getLogWriter() throws SQLException {
return this.logWriter;
}
public int getLoginTimeout() throws SQLException {
return this.loginTimeout;
}
public void setLogWriter(PrintWriter logWriter) throws SQLException {
this.logWriter = logWriter;
}
public void setLoginTimeout(int loginTimeout) throws SQLException {
this.loginTimeout = loginTimeout;
}
public Connection getConnection(String s, String s1) throws SQLException {
throw new UnsupportedOperationException("You should configure the username and password within the proxool configuration and just call getConnection() instead.");
}
}