package jef.database.test.jdbc;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import javax.sql.DataSource;
import jef.database.datasource.AbstractDataSource;
/**
* 用来进行测试的数据源,目的是分析在连接上执行的各项操作是否合法。
*
* 结果集关闭,连接关闭等是否正确。
*
* 如果框架操作不正确,就会出现事务未关闭、资源未释放等问题,因此用这样一个驱动来检查
*
* @author jiyi
*
*/
public class DebugDataSource extends AbstractDataSource{
private DataSource ds;
public final Map<OperType,AtomicLong> count=new IdentityHashMap<OperType,AtomicLong>();
public static final Map<OperType,Boolean> printStackCfg=new HashMap<OperType,Boolean>();
static{
printStackCfg.put(OperType.create_connection, true);
printStackCfg.put(OperType.close_connection, true);
printStackCfg.put(OperType.preapre_statement, true);
printStackCfg.put(OperType.close_prepared_statement, true);
printStackCfg.put(OperType.create_statement, true);
printStackCfg.put(OperType.close_statement, true);
printStackCfg.put(OperType.create_resultSet, true);
printStackCfg.put(OperType.close_resultSet, true);
printStackCfg.put(OperType.set_autocommit_false, true);
printStackCfg.put(OperType.commit, true);
printStackCfg.put(OperType.rollback, true);
printStackCfg.put(OperType.set_autocommit_true, true);
printStackCfg.put(OperType.set_connection_attr, true);
printStackCfg.put(OperType.set_statement_attr, false);
printStackCfg.put(OperType.set_resultset_attr, false);
printStackCfg.put(OperType.execute_batch, true);
printStackCfg.put(OperType.execute_update, true);
}
/**
* 构造
* @param ds
*/
public DebugDataSource(DataSource ds) {
this.ds=ds;
initCounter();
}
private void initCounter() {
count.put(OperType.create_connection, new AtomicLong());
count.put(OperType.close_connection, new AtomicLong());
count.put(OperType.preapre_statement, new AtomicLong());
count.put(OperType.close_prepared_statement, new AtomicLong());
count.put(OperType.create_statement, new AtomicLong());
count.put(OperType.close_statement, new AtomicLong());
count.put(OperType.create_resultSet, new AtomicLong());
count.put(OperType.close_resultSet, new AtomicLong());
count.put(OperType.set_autocommit_false, new AtomicLong());
count.put(OperType.commit, new AtomicLong());
count.put(OperType.rollback, new AtomicLong());
count.put(OperType.set_autocommit_true, new AtomicLong());
count.put(OperType.set_connection_attr, new AtomicLong());
count.put(OperType.set_statement_attr, new AtomicLong());
count.put(OperType.set_resultset_attr, new AtomicLong());
count.put(OperType.execute_batch, new AtomicLong());
count.put(OperType.execute_update, new AtomicLong());
}
/**
* 空构造
*/
public DebugDataSource() {
super();
initCounter();
}
/**
* 创建连接
*/
@Override
public Connection getConnection() throws SQLException {
Connection conn=ds.getConnection();
event(OperType.create_connection,conn);
return new DebugConnection(conn,this);
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
Connection conn=ds.getConnection(username,password);
event(OperType.create_connection, conn);
return new DebugConnection(conn,this);
}
@Override
protected Class<? extends DataSource> getWrappedClass() {
return null;
}
public DataSource getDs() {
return ds;
}
public void setDs(DataSource ds) {
this.ds = ds;
}
public void event(OperType type,Object message) {
//计数器累加
count.get(type).incrementAndGet();
StackTraceElement[] stacks=new Throwable().getStackTrace();
System.out.println(">> "+type.name()+"=== "+message+" ===");
Boolean printStack=printStackCfg.get(type);
if(printStack==null || printStack){
System.out.println(">>"+stacks[2]+"\n>>"+stacks[3]);
}
}
@Override
protected void finalize() throws Throwable {
super.finalize();
checkCount();
}
private void checkCount() {
List<String> errorMessages=new ArrayList<String>();
//检查连接打开和关闭数量
checkNumber(errorMessages,OperType.create_connection,OperType.close_connection);
//检查PreparedStatement次数
checkNumber(errorMessages,OperType.preapre_statement,OperType.close_prepared_statement);
//检查Statement次数
checkNumber(errorMessages,OperType.create_statement,OperType.close_statement);
//检查结果集关闭数量
checkNumber(errorMessages,OperType.create_resultSet,OperType.close_resultSet);
//检查事务开启关闭次数
checkNumber(errorMessages,OperType.set_autocommit_false,OperType.commit,OperType.rollback);
// count.put(OperType.set_autocommit_true, new AtomicLong());
// count.put(OperType.set_connection_attr, new AtomicLong());
// count.put(OperType.execute_batch, new AtomicLong());
// count.put(OperType.execute_update, new AtomicLong());
if(!errorMessages.isEmpty()){
System.err.println("********************** ERROR JDBC OPERATE DETLECTED *************************");
for(String s:errorMessages){
System.err.println(s);
}
}
}
private void checkNumber(List<String> msgs,OperType t1, OperType t2) {
long n1=count.get(t1).get();
long n2=count.get(t2).get();
if(n1!=n2){
msgs.add(t1.name()+"["+n1+"]!="+t2.name()+"["+n2+"]");
}
}
private void checkNumber(List<String> msgs,OperType t1, OperType t2,OperType t3) {
long n1=count.get(t1).get();
long n2=count.get(t2).get();
long n3=count.get(t3).get();
if(n1!=n2+n3){
msgs.add(t1.name()+"["+n1+"]!="+t2.name()+"["+n2+"]+"+t3.name()+"["+n3+"]");
}
}
}