[강운덕] [LUCYSUS-1744] 바인딩 변수 api 할당 api의 아규먼트를 문자열로 치환하는 로직 부분 개발.

git-svn-id: http://svn.bds.nhncorp.com/pe/hippo-tomcat-profiler/trunk@626 84d0f5b1-2673-498c-a247-62c4ff18d310
This commit is contained in:
Woonduk Kang
2012-09-11 10:20:52 +00:00
parent 3b84111280
commit aea998cc03
14 changed files with 325 additions and 40 deletions
@@ -4,10 +4,7 @@ import java.lang.reflect.Method;
import java.security.ProtectionDomain;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.logging.Level;
@@ -57,7 +54,7 @@ public class MySQLPreparedStatementModifier extends AbstractModifier {
preparedStatement.addTraceVariable("__url", "__setUrl", "__getUrl", "java.lang.String");
preparedStatement.addTraceVariable("__sql", "__setSql", "__getSql", "java.lang.String");
preparedStatement.addTraceVariable("__bindValue", "__setBindValue", "__getBindValue", "java.util.List", "java.util.Collections.synchronizedList(new java.util.LinkedList());");
preparedStatement.addTraceVariable("__bindValue", "__setBindValue", "__getBindValue", "java.util.Map", "java.util.Collections.synchronizedMap(new java.util.HashMap());");
bindVariableIntercept(preparedStatement, classLoader, protectedDomain);
return preparedStatement.toBytecode();
@@ -90,14 +87,15 @@ public class MySQLPreparedStatementModifier extends AbstractModifier {
String methodName = method.getName();
String[] parameterType = JavaAssistUtils.getParameterType(method.getParameterTypes());
try {
preparedStatement.addInterceptor(methodName, parameterType , interceptor);
preparedStatement.addInterceptor(methodName, parameterType, interceptor);
} catch (NotFoundInstrumentException e) {
// bind variable setter메소드를 못찾을 경우는 그냥 경고만 표시
if (logger.isLoggable(Level.WARNING)) {
logger.log(Level.WARNING, "bindVariable api modify fail. Cause:" + e.getMessage(), e);
// bind variable setter메소드를 못찾을 경우는 그냥 경고만 표시, 에러 아님.
if (logger.isLoggable(Level.INFO)) {
logger.log(Level.INFO, "bindVariable api not found. Cause:" + e.getMessage(), e);
}
}
}
}
@@ -3,17 +3,19 @@ package com.profiler.modifier.db.mysql.interceptors;
import com.profiler.context.Trace;
import com.profiler.interceptor.StaticAfterInterceptor;
import com.profiler.util.MetaObject;
import com.profiler.util.NumberUtils;
import com.profiler.util.StringUtils;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
public class PreparedStatementBindVariableInterceptor implements StaticAfterInterceptor {
private final Logger logger = Logger.getLogger(PreparedStatementBindVariableInterceptor.class.getName());
private final MetaObject<List> getBindValue = new MetaObject<List>("__getBindValue");
private final MetaObject<Map> getBindValue = new MetaObject<Map>("__getBindValue");
@Override
public void after(Object target, String className, String methodName, String parameterDescription, Object[] args, Object result) {
@@ -23,9 +25,13 @@ public class PreparedStatementBindVariableInterceptor implements StaticAfterInte
if (Trace.getCurrentTraceId() == null) {
return;
}
List bindList = getBindValue.invoke(target);
String index = StringUtils.toString(args[0]);
Map bindList = getBindValue.invoke(target);
Integer index = NumberUtils.toInteger(args[0]);
if(index == null) {
// 어딘가 잘못됨.
return;
}
String value = StringUtils.toString(args[1]);
bindList.add(index + ":" + value);
bindList.put(index, value);
}
}
@@ -1,9 +1,7 @@
package com.profiler.modifier.db.mysql.interceptors;
import com.mysql.jdbc.PreparedStatement;
import com.profiler.context.Annotation;
import com.profiler.context.Trace;
import com.profiler.interceptor.StaticAfterInterceptor;
import com.profiler.interceptor.StaticAroundInterceptor;
import com.profiler.util.InterceptorUtils;
import com.profiler.util.MetaObject;
@@ -19,8 +17,8 @@ public class PreparedStatementMethodInterceptor implements StaticAroundIntercept
private final MetaObject<String> getSql = new MetaObject("__getSql");
private final MetaObject<String> getUrl = new MetaObject("__getUrl");
private final MetaObject<List<String>> getBindValue = new MetaObject("__getBindValue");
private final MetaObject<List<String>> setBindValue = new MetaObject("__setBindValue");
private final MetaObject<Map> getBindValue = new MetaObject("__getBindValue");
private final MetaObject<Map> setBindValue = new MetaObject("__setBindValue");
@Override
@@ -39,7 +37,8 @@ public class PreparedStatementMethodInterceptor implements StaticAroundIntercept
String sql = getSql.invoke(target);
Trace.recordAttibute("PreparedStatement", sql);
List<String> bindValue = getBindValue.invoke(target);
Map bindValue = getBindValue.invoke(target);
String bindString = toBindVariable(bindValue);
Trace.recordAttibute("BindValue", bindValue.toString());
setBindValue.invoke(target, Collections.synchronizedList(new LinkedList<String>()));
@@ -52,6 +51,14 @@ public class PreparedStatementMethodInterceptor implements StaticAroundIntercept
}
private String toBindVariable(Map bindValue) {
StringBuilder sb = new StringBuilder();
for(int i =0; i<bindValue.size(); i++) {
Object o = bindValue.get(i);
}
return null; //To change body of created methods use File | Settings | File Templates.
}
@Override
public void after(Object target, String className, String methodName, String parameterDescription, Object[] args, Object result) {
if (logger.isLoggable(Level.INFO)) {
@@ -0,0 +1,53 @@
package com.profiler.util;
public class ArrayUtils {
public static String dropToString(byte[] bytes) {
return dropToString(bytes, 10);
}
public static String dropToString(byte[] bytes, int limit) {
if (bytes == null) {
return "null";
}
// TODO limit음수일 경우 예외처리 필요.
// size 4인 배열의 경 3에서 멈춰야 하므로 -1
int iMax = bytes.length - 1;
int iLimit = limit - 1;
if (iMax > iLimit) {
iMax = iLimit;
}
if (iMax == -1) {
if (bytes.length == 0) {
return "[]";
} else {
return "[...(" + bytes.length + ")]";
}
}
StringBuilder sb = new StringBuilder();
sb.append('[');
for (int i = 0; ; i++) {
sb.append(bytes[i]);
if (i == iMax) {
if (iMax < iLimit) {
return sb.append(']').toString();
} else {
if (i > 0) {
}
sb.append(", ");
sb.append("...(");
sb.append(bytes.length);
sb.append(")]");
return sb.toString();
}
}
sb.append(", ");
}
}
}
@@ -23,4 +23,15 @@ public class NumberUtils {
}
}
public static Integer toInteger(Object integer) {
if(integer == null) {
return null;
}
if (integer instanceof Integer) {
return (Integer)integer;
} else {
return null;
}
}
}
@@ -12,4 +12,24 @@ public class StringUtils {
}
return object.toString();
}
public static String drop(String str) {
return drop(str, 20, getDropString(str));
}
public static String getDropString(String str) {
return "...(" + str.length() + ")";
}
public static String drop(String str, int length, String padding) {
if (str == null) {
return "null";
}
StringBuilder buffer = new StringBuilder(length + 10);
if(str.length() > length) {
buffer.append(str.substring(0, length));
buffer.append(padding);
}
return buffer.toString();
}
}
@@ -1,6 +1,6 @@
package com.profiler.util.bindvalue;
import com.profiler.util.StringUtils;
import com.profiler.util.bindvalue.converter.*;
import java.util.HashMap;
import java.util.Map;
@@ -8,6 +8,81 @@ import java.util.Map;
public class BindValueConverter {
public static final Map<String, Converter> convertermap = new HashMap<String, Converter>() ;
private void register() {
simpleType();
classNameType();
// null argument 가 3개인것도 있음.
convertermap.put("setNull", new NullTypeConterver());
BytesConverter bytesConverter = new BytesConverter();
convertermap.put("setBytes", bytesConverter);
// setObject
convertermap.put("setObject", null);
}
private void classNameType() {
// className 데이터를 까볼수 없는 객체의 경우 class명으로 치환
ClassNameConverter classNameConverter = new ClassNameConverter();
// 3개짜리 존재
convertermap.put("setAsciiStream", classNameConverter);
convertermap.put("setUnicodeStream", classNameConverter);
convertermap.put("setBinaryStream", classNameConverter);
//3개 짜리 존재
convertermap.put("setBlob", classNameConverter);
//3개 짜리 존재
convertermap.put("setClob", classNameConverter);
convertermap.put("setArray", classNameConverter);
convertermap.put("setNCharacterStream", classNameConverter);
// 3개 짜리 존재
convertermap.put("setNClob", classNameConverter);
convertermap.put("setCharacterStream", classNameConverter);
convertermap.put("setSQLXML", classNameConverter);
convertermap.put("setSQLXML", classNameConverter);
convertermap.put("setSQLXML", classNameConverter);
convertermap.put("setSQLXML", classNameConverter);
}
private void simpleType() {
SimpleTypeConverter simpleTypeConverter = new SimpleTypeConverter();
convertermap.put("setByte", simpleTypeConverter);
convertermap.put("setShort", simpleTypeConverter);
convertermap.put("setInt", simpleTypeConverter);
convertermap.put("setLong", simpleTypeConverter);
convertermap.put("setFloat", simpleTypeConverter);
convertermap.put("setDouble", simpleTypeConverter);
convertermap.put("setBigDecimal", simpleTypeConverter);
convertermap.put("setString", simpleTypeConverter);
convertermap.put("setDate", simpleTypeConverter);
// argument 가 3개 가능.
convertermap.put("setTime", simpleTypeConverter);
//convertermap.put("setTime", simpleTypeConverter);
// argument 가 3개 가능
convertermap.put("setTimestamp", simpleTypeConverter);
//convertermap.put("setTimestamp", simpleTypeConverter);
// 문자열로 치환 가능할것으로 보임.
convertermap.put("setURL", simpleTypeConverter);
// ref도 문자열로 치환 가능할것으로 보임
convertermap.put("setRef", simpleTypeConverter);
convertermap.put("setNString", simpleTypeConverter);
}
public String bindValueToString(String methodName, Object[] args) {
Converter converter = convertermap.get(methodName);
if (converter == null) {
@@ -16,26 +91,6 @@ public class BindValueConverter {
return converter.convert(args);
}
interface Converter {
String convert(Object[] args);
}
class CommonConverter implements Converter {
@Override
public String convert(Object[] args) {
if(args == null) {
return "null";
}
if (args.length == 1) {
return StringUtils.toString(args[1]);
}
else if(args.length == 2) {
return StringUtils.toString(args[0]) + ":" + StringUtils.toString(args[1]);
}
else if(args.length == 3) {
return StringUtils.toString(args[0]) + ":" + StringUtils.toString(args[1]);
}
return "error";
}
}
}
@@ -0,0 +1,23 @@
package com.profiler.util.bindvalue.converter;
import com.profiler.util.ArrayUtils;
import com.profiler.util.StringUtils;
public class BytesConverter implements Converter {
@Override
public String convert(Object[] args) {
if (args == null) {
return "null";
}
if (args.length == 2) {
byte[] bytes = (byte[]) args[1];
if (bytes == null) {
return "null";
} else {
return StringUtils.drop(ArrayUtils.dropToString(bytes));
}
}
return "error";
}
}
@@ -0,0 +1,28 @@
package com.profiler.util.bindvalue.converter;
import com.profiler.util.StringUtils;
public class ClassNameConverter implements Converter {
@Override
public String convert(Object[] args) {
if (args == null) {
return "null";
}
if (args.length == 2) {
String str = StringUtils.toString(args[0]) + ":" + StringUtils.toString(getClassName(args[1]));
return StringUtils.drop(str);
} else if (args.length == 3) {
// TODO 3일때 추가 처리?
String str = StringUtils.toString(args[0]) + ":" + StringUtils.toString(getClassName(args[1]));
return StringUtils.drop(str);
}
return "error";
}
private Object getClassName(Object args) {
if (args == null) {
return "null";
}
return args.getClass().getName();
}
}
@@ -0,0 +1,5 @@
package com.profiler.util.bindvalue.converter;
public interface Converter {
String convert(Object[] args);
}
@@ -0,0 +1,9 @@
package com.profiler.util.bindvalue.converter;
public class NullTypeConterver implements Converter {
@Override
public String convert(Object[] args) {
return "null";
}
}
@@ -0,0 +1,21 @@
package com.profiler.util.bindvalue.converter;
import com.profiler.util.StringUtils;
public class SimpleTypeConverter implements Converter {
@Override
public String convert(Object[] args) {
if (args == null) {
return "null";
}
if (args.length == 2) {
String str = StringUtils.toString(args[0]) + ":" + StringUtils.toString(args[1]);
return StringUtils.drop(str);
} else if (args.length == 3) {
// TODO 3일때 추가 처리?
String str = StringUtils.toString(args[0]) + ":" + StringUtils.toString(args[1]);
return StringUtils.drop(str);
}
return "error";
}
}