net.ttddyy.dsproxy.proxy.StatementProxyLogic Maven / Gradle / Ivy
package net.ttddyy.dsproxy.proxy;
import net.ttddyy.dsproxy.ExecutionInfo;
import net.ttddyy.dsproxy.QueryInfo;
import net.ttddyy.dsproxy.listener.QueryExecutionListener;
import net.ttddyy.dsproxy.transform.QueryTransformer;
import net.ttddyy.dsproxy.transform.TransformInfo;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.Statement;
import java.util.*;
/**
* Proxy Logic implementation for {@link Statement} methods.
*
* @author Tadaya Tsuyukubo
* @since 1.2
*/
public class StatementProxyLogic {
private static final Set METHODS_TO_INTERCEPT = Collections.unmodifiableSet(
new HashSet() {
{
addAll(StatementMethodNames.BATCH_PARAM_METHODS);
addAll(StatementMethodNames.EXEC_METHODS);
addAll(StatementMethodNames.JDBC4_METHODS);
addAll(StatementMethodNames.GET_CONNECTION_METHOD);
add("getDataSourceName");
add("toString");
add("getTarget"); // from ProxyJdbcObject
}
}
);
private Statement stmt;
private InterceptorHolder interceptorHolder;
private String dataSourceName;
private List batchQueries = new ArrayList();
private JdbcProxyFactory jdbcProxyFactory = JdbcProxyFactory.DEFAULT;
public StatementProxyLogic() {
}
public StatementProxyLogic(
Statement stmt, InterceptorHolder interceptorHolder, String dataSourceName, JdbcProxyFactory jdbcProxyFactory) {
this.stmt = stmt;
this.interceptorHolder = interceptorHolder;
this.dataSourceName = dataSourceName;
this.jdbcProxyFactory = jdbcProxyFactory;
}
public Object invoke(Method method, Object[] args) throws Throwable {
final String methodName = method.getName();
if (!METHODS_TO_INTERCEPT.contains(methodName)) {
return MethodUtils.proceedExecution(method, stmt, args);
}
// special treat for toString method
if ("toString".equals(methodName)) {
final StringBuilder sb = new StringBuilder();
sb.append(stmt.getClass().getSimpleName());
sb.append(" [");
sb.append(stmt.toString());
sb.append("]");
return sb.toString(); // differentiate toString message.
} else if ("getDataSourceName".equals(methodName)) {
return dataSourceName;
} else if ("getTarget".equals(methodName)) {
// ProxyJdbcObject interface has method to return original object.
return stmt;
}
if (StatementMethodNames.JDBC4_METHODS.contains(methodName)) {
final Class clazz = (Class) args[0];
if ("unwrap".equals(methodName)) {
return stmt.unwrap(clazz);
} else if ("isWrapperFor".equals(methodName)) {
return stmt.isWrapperFor(clazz);
}
}
if (StatementMethodNames.GET_CONNECTION_METHOD.contains(methodName)) {
final Connection conn = (Connection) MethodUtils.proceedExecution(method, stmt, args);
return jdbcProxyFactory.createConnection(conn, interceptorHolder, dataSourceName);
}
if ("addBatch".equals(methodName) || "clearBatch".equals(methodName)) {
if ("addBatch".equals(methodName) && ObjectArrayUtils.isFirstArgString(args)) {
final QueryTransformer queryTransformer = interceptorHolder.getQueryTransformer();
final String query = (String) args[0];
final Class clazz = Statement.class;
final int batchCount = batchQueries.size();
final TransformInfo transformInfo = new TransformInfo(clazz, dataSourceName, query, true, batchCount);
final String transformedQuery = queryTransformer.transformQuery(transformInfo);
args[0] = transformedQuery; // replace to the new query
batchQueries.add(transformedQuery);
} else if ("clearBatch".equals(methodName)) {
batchQueries.clear();
}
// proceed execution, no need to call listener
try {
return method.invoke(stmt, args);
} catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
final List queries = new ArrayList();
boolean isBatchExecute = false;
int batchSize = 0;
if (StatementMethodNames.BATCH_EXEC_METHODS.contains(methodName)) {
for (String batchQuery : batchQueries) {
queries.add(new QueryInfo(batchQuery));
}
batchSize = batchQueries.size();
batchQueries.clear();
isBatchExecute = true;
} else if (StatementMethodNames.QUERY_EXEC_METHODS.contains(methodName)) {
if (ObjectArrayUtils.isFirstArgString(args)) {
final QueryTransformer queryTransformer = interceptorHolder.getQueryTransformer();
final String query = (String) args[0];
final TransformInfo transformInfo = new TransformInfo(Statement.class, dataSourceName, query, false, 0);
final String transformedQuery = queryTransformer.transformQuery(transformInfo);
args[0] = transformedQuery; // replace to the new query
queries.add(new QueryInfo(transformedQuery));
}
}
final ExecutionInfo execInfo = new ExecutionInfo(dataSourceName, this.stmt, isBatchExecute, batchSize, method, args);
final QueryExecutionListener listener = interceptorHolder.getListener();
listener.beforeQuery(execInfo, queries);
// Invoke method on original Statement.
try {
final long beforeTime = System.currentTimeMillis();
Object retVal = method.invoke(stmt, args);
final long afterTime = System.currentTimeMillis();
execInfo.setResult(retVal);
execInfo.setElapsedTime(afterTime - beforeTime);
execInfo.setSuccess(true);
return retVal;
} catch (InvocationTargetException ex) {
execInfo.setThrowable(ex.getTargetException());
execInfo.setSuccess(false);
throw ex.getTargetException();
} finally {
listener.afterQuery(execInfo, queries);
}
}
}