package com.ctrip.platform.dal.dao.client;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.ctrip.platform.dal.dao.DalClientFactory;
import com.ctrip.platform.dal.dao.DalCommand;
import com.ctrip.platform.dal.dao.DalEventEnum;
import com.ctrip.platform.dal.dao.DalHintEnum;
import com.ctrip.platform.dal.dao.DalHints;
import com.ctrip.platform.dal.dao.StatementParameters;
import com.ctrip.platform.dal.dao.Version;
import com.ctrip.platform.dal.exceptions.DalException;
public abstract class ConnectionAction<T> {
public DalEventEnum operation;
public String sql;
public String callString;
public String[] sqls;
public StatementParameters parameters;
public StatementParameters[] parametersList;
public DalCommand command;
public List<DalCommand> commands;
public DalConnection connHolder;
public Set<String> usedDbs = new HashSet<>();
public Connection conn;
public Statement statement;
public PreparedStatement preparedStatement;
public CallableStatement callableStatement;
public ResultSet rs;
public long start;
public DalLogger logger = DalClientFactory.getDalLogger();
public LogEntry entry;
void populate(DalEventEnum operation, String sql, StatementParameters parameters) {
this.operation = operation;
this.sql = this.wrapAPPID(sql);
this.parameters = parameters;
}
void populate(String[] sqls) {
this.operation = DalEventEnum.BATCH_UPDATE;
this.sqls = sqls;
for(int i = 0; i < this.sqls.length; i++){
this.sqls[i] = this.wrapAPPID(this.sqls[i]);
}
}
void populate(String sql, StatementParameters[] parametersList) {
this.operation = DalEventEnum.BATCH_UPDATE_PARAM;
this.sql = this.wrapAPPID(sql);
this.parametersList = parametersList;
}
void populate(DalCommand command) {
this.operation = DalEventEnum.EXECUTE;
this.command = command;
}
void populate(List<DalCommand> commands) {
this.operation = DalEventEnum.EXECUTE;
this.commands = commands;
}
void populateSp(String callString, StatementParameters parameters) {
this.operation = DalEventEnum.CALL;
this.callString = callString;
this.parameters = parameters;
}
void populateSp(String callString, StatementParameters []parametersList) {
this.operation = DalEventEnum.BATCH_CALL;
this.callString = callString;
this.parametersList = parametersList;
}
public void populateDbMeta() {
DbMeta meta = null;
entry.setTransactional(DalTransactionManager.isInTransaction());
if(DalTransactionManager.isInTransaction()) {
meta = DalTransactionManager.getCurrentDbMeta();
} else {
if(connHolder != null)
meta = connHolder.getMeta();
}
if(meta != null)
meta.populate(entry);
}
public void initLogEntry(String logicDbName, DalHints hints) {
this.entry = logger.createLogEntry();
entry.setClientVersion(Version.getVersion());
entry.setSensitive(hints.is(DalHintEnum.sensitive));
entry.setEvent(operation);
entry.setCallString(callString);
if(sqls != null)
entry.setSqls(sqls);
else
entry.setSqls(sql);
if (null != parametersList) {
String[] params = new String[parametersList.length];
for (int i = 0; i < parametersList.length; i++) {
params[i] = parametersList[i].toLogString();
}
entry.setPramemters(params);
} else if (parameters != null) {
entry.setPramemters(parameters.toLogString());
hints.setParameters(parameters);
}
}
public void start() {
start = System.currentTimeMillis();
logger.start(entry);
}
public void end(Object result, Throwable e) throws SQLException {
log(result, e);
handleException(e);
}
private void log(Object result, Throwable e) {
try {
entry.setDuration(System.currentTimeMillis() - start);
if(e == null) {
logger.success(entry, fetchQueryRows(result));
}else{
logger.fail(entry, e);
}
} catch (Throwable e1) {
logger.error("Can not log", e1);
}
}
private int fetchQueryRows(Object result) {
return null != result && result instanceof Collection<?> ? ((Collection<?>)result).size() : 0;
}
public void cleanup() {
closeResultSet();
closeStatement();
closeConnection();
}
private void closeResultSet() {
if(rs != null) {
try {
rs.close();
} catch (Throwable e) {
logger.error("Close result set failed.", e);
}
}
rs = null;
}
private void closeStatement() {
Statement _statement = statement != null?
statement : preparedStatement != null?
preparedStatement : callableStatement;
statement = null;
preparedStatement = null;
callableStatement = null;
if(_statement != null) {
try {
_statement.close();
} catch (Throwable e) {
logger.error("Close statement failed.", e);
}
}
}
private void closeConnection() {
//do nothing for connection in transaction
if(DalTransactionManager.isInTransaction())
return;
// For list of nested commands, the top level action will not hold any connHolder
if(connHolder == null)
return;
connHolder.close();
connHolder = null;
conn = null;
}
private void handleException(Throwable e) throws SQLException {
if(e != null)
throw e instanceof SQLException ? (SQLException)e : DalException.wrap(e);
}
private String wrapAPPID(String sql){
return "/*" + DalClientFactory.getDalLogger().getAppID() + "*/" + sql;
}
public abstract T execute() throws Exception;
}