package li.datasource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.sql.DataSource;
import li.util.Log;
import li.util.ThreadUtil;
/**
* DataSource的简单实现
*
* @author li (limingwei@mail.com)
* @version 0.1.2 (2012-05-08)
*/
public class SimpleDataSource implements DataSource {
private static final String[] JDBC_DRIVERS = { "com.mysql.jdbc.Driver", "org.sqlite.JDBC", "org.h2.Driver", "org.apache.derby.jdbc.EmbeddedDriver", "org.hsqldb.jdbcDriver" };
private static final Log log = Log.init();
private String url;
private String username;
private String password;
/**
* 获取链接的计数器
*/
private int times = 0;
/**
* 打印trace的正则表达式
*/
private String regex = "默认的全都不打印";
/**
* 是否打印trace
*/
private Boolean trace = false;// 默认页不显示链接个数提醒
/**
* 被代理dataSource
*/
private DataSource dataSource;
/**
* 当前持有未管理的链接
*/
private List<ConnectionWrapper> unclosedConnections = new ArrayList<ConnectionWrapper>();
/**
* 日志流
*/
private PrintWriter logWriter;
/**
* 静态初始化代码块,注册数据库驱动
*/
static {
for (String driver : JDBC_DRIVERS) {
registerDriver(driver);
}
}
/**
* 注册驱动
*/
private static void registerDriver(String driver) {
try {
Class.forName(driver);
} catch (Exception e) {}
}
/**
* 打印泄漏链接堆栈
*/
private void traceConnections() {
String string = "";
for (ConnectionWrapper connection : unclosedConnections) {
string += "\n" + connection + " Called by " + ThreadUtil.stackTrace(connection.getStackTrace(), this.regex);
}
log.debug(string);
}
/**
* 移除一个未关闭链接
*/
protected void removeConnection(Connection connection) {
unclosedConnections.remove(connection);
if (trace) {
log.debug("Closing a link, totally got " + (++times) + " links , there are " + unclosedConnections.size() + " unclosed links");
if (unclosedConnections.size() > 0) {
traceConnections();
}
}
}
/**
* 注册JDBC驱动
*/
public void setDriver(String driver) {
registerDriver(driver);
}
/**
* 是否打印链接获取日志
*/
public void setTrace(Boolean trace) {
this.trace = trace;
}
/**
* 打印泄漏链接时候类名方法名筛选
*/
public void setRegex(String regex) {
this.regex = regex;
this.trace = true;
}
public void setUrl(String url) {
this.url = url;
}
/**
* 配置 user 或 username 都可以
*/
public void setUser(String user) {
this.username = user;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
/**
* 设置被代理DataSource
*/
public void setDataSource(DataSource dataSource) {
log.info("Setting the to be agented dataSource ?", dataSource.getClass().getName() + "@" + Integer.toHexString(dataSource.hashCode()));
this.dataSource = dataSource;
}
/**
* 不支持切换用户
*/
public Connection getConnection(String username, String password) throws SQLException {
log.warn("Not supported to use another username and password after dataSource inited");
return this.getConnection();
}
public Connection getConnection() throws SQLException {
Connection connection = null == this.dataSource ? DriverManager.getConnection(this.url, this.username, this.password) : this.dataSource.getConnection();
ConnectionWrapper connectionWrapper = new ConnectionWrapper(this, connection);
this.unclosedConnections.add(connectionWrapper);
if (trace) {
log.debug("Getting a link, totally got " + (++times) + " links , there are " + this.unclosedConnections.size() + " unclosed links");
if (this.unclosedConnections.size() > 1) {
traceConnections();
}
}
return connectionWrapper;
}
public PrintWriter getLogWriter() throws SQLException {
if (null != this.dataSource) {
return this.dataSource.getLogWriter();
}
return this.logWriter;
}
public void setLogWriter(PrintWriter out) throws SQLException {
if (null != this.dataSource) {
this.dataSource.setLogWriter(out);
} else {
this.logWriter = out;
}
}
public int getLoginTimeout() throws SQLException {
if (null != this.dataSource) {
return this.dataSource.getLoginTimeout();
}
return DriverManager.getLoginTimeout();
}
public void setLoginTimeout(int seconds) throws SQLException {
if (null != this.dataSource) {
this.dataSource.setLoginTimeout(seconds);
} else {
DriverManager.setLoginTimeout(seconds);
}
}
public boolean isWrapperFor(Class<?> iface) throws SQLException {
if (null != this.dataSource) {
return this.dataSource.isWrapperFor(iface);
}
return null != iface && iface.isInstance(this);
}
public <T> T unwrap(Class<T> iface) throws SQLException {
if (null != this.dataSource) {
return this.dataSource.unwrap(iface);
}
return null != iface && iface.isInstance(this) ? (T) this : null;
}
public String toString() {
return super.toString() + " url=" + this.url;
}
}