diff --git a/src/main/java/com/profiler/common/mapping/ApiMappingTable.java b/src/main/java/com/profiler/common/mapping/ApiMappingTable.java new file mode 100644 index 000000000..7513e8be4 --- /dev/null +++ b/src/main/java/com/profiler/common/mapping/ApiMappingTable.java @@ -0,0 +1,120 @@ +package com.profiler.common.mapping; + +import java.util.HashMap; +import java.util.Map; + +/** + * + */ +public class ApiMappingTable { + public static final String[] NULL = new String[]{}; + // 2147483 + public static final int MySqlDriverCode = 1000; + private static final ClassMapping MysqlDriver = new ClassMapping(MySqlDriverCode, "com.mysql.jdbc.NonRegisteringDriver", + new MethodMapping("connect", new String[]{"java.lang.String", "java.util.Properties"}, new String[]{"url", "info"})); + + + public static final int MySqlConnectionCode = 1001; + private static final ClassMapping MysqlConnection = new ClassMapping(MySqlConnectionCode, "com.mysql.jdbc.ConnectionImpl", + new MethodMapping("setAutoCommit", new String[]{"boolean"}, new String[]{"autoCommitFlag"}), + new MethodMapping("commit", NULL, NULL), + new MethodMapping("rollback", NULL, NULL), + new MethodMapping("prepareStatement", new String[]{"java.lang.String"}, new String[]{"sql"}) + ); + + public static final int MySqlPreparedStatementCode = 1002; + private static final ClassMapping MySqlPreparedStatement = new ClassMapping(MySqlPreparedStatementCode, "com.mysql.jdbc.PreparedStatement", + new MethodMapping("execute", NULL, NULL), + new MethodMapping("executeQuery", NULL, NULL), + new MethodMapping("executeUpdate", NULL, NULL) + ); + + public static final int MySqlStatementImplCode = 1003; + private static final ClassMapping MySqlStatementImpl = new ClassMapping(MySqlStatementImplCode, "com.mysql.jdbc.StatementImpl", + new MethodMapping("executeUpdate", new String[]{"java.lang.String"}, new String[]{"sql"}), + new MethodMapping("executeUpdate", new String[]{"java.lang.String", "boolean"}, new String[]{"sql", "returnGeneratedKeys"}), + new MethodMapping("execute", new String[]{"java.lang.String"}, new String[]{"sql"}), + new MethodMapping("execute", new String[]{"java.lang.String", "boolean"}, new String[]{"sql", "returnGeneratedKeys"}) + ); + + + public static final ApiMappingTable TABLE; + + static { + TABLE = new ApiMappingTable(); + TABLE.init(); + } + + // 2147483647 + // xxxxxxxxx - yy xxxx는 class 명, yy는 함수명매칭하자. 하자. + private Map classNameIndex; + private Map classIdIndex; + + public ApiMappingTable() { + this.classNameIndex = new HashMap(64); + this.classIdIndex = new HashMap(64); + } + + public void put(ClassMapping classMapping) { + this.classNameIndex.put(classMapping.getClassName(), classMapping); + this.classIdIndex.put(classMapping.getClassId(), classMapping); + } + + public void init() { + this.put(MysqlDriver); + this.put(MysqlConnection); + this.put(MySqlPreparedStatement); + this.put(MySqlStatementImpl); + } + + public int findMethodApiId0(String className, String methodName, String[] parameter) { + ClassMapping classMapping = classNameIndex.get(className); + if (classMapping == null) { + return -1; + } + int classId = classMapping.getClassId(); + MethodMapping methodMapping = classMapping.getMethodMapping(new MethodMapping(methodName, parameter)); + if (methodMapping == null) { + return -2; + } + int methodId = methodMapping.getMethodId(); + return ApiUtils.getApiId(classId, methodId); + } + + public MethodMapping findMethodMapping0(int apiId) { + final int classId = ApiUtils.parseClassId(apiId); + final int methodId = ApiUtils.parseMethodId(apiId); + ClassMapping classMapping = classIdIndex.get(classId); + if (classMapping == null) { + return classIdNotFound(classId); + } + MethodMapping methodMapping = classMapping.getMethodMapping(methodId); + if (methodMapping == null) { + return methodIdNotFound(classMapping, methodId); + } + return methodMapping; + } + + private MethodMapping methodIdNotFound(ClassMapping classMapping, int methodId) { + MethodMapping methodMapping = new MethodMapping("methodId not found:" + methodId, null, null); + new ClassMapping(classMapping.getClassId(), classMapping.getClassName(), methodMapping); + return methodMapping; + } + + private MethodMapping classIdNotFound(int classId) { + MethodMapping methodMapping = new MethodMapping("not found", null, null); + new ClassMapping(classId, "classId not found:" + classId, methodMapping); + return methodMapping; + } + + + public static int findApiId(String className, String methodName, String[] parameter) { + return TABLE.findMethodApiId0(className, methodName, parameter); + } + + public static MethodMapping findMethodMapping(int apiId) { + return TABLE.findMethodMapping0(apiId); + } + + +} diff --git a/src/main/java/com/profiler/common/mapping/ApiUtils.java b/src/main/java/com/profiler/common/mapping/ApiUtils.java new file mode 100644 index 000000000..1c8b32efa --- /dev/null +++ b/src/main/java/com/profiler/common/mapping/ApiUtils.java @@ -0,0 +1,52 @@ +package com.profiler.common.mapping; + +/** + * + */ +public class ApiUtils { + + private final static String EMTPY_ARRAY = "()"; + private static final int METHOD_RANGE = 100; + + public static int parseClassId(int apiId) { + if (apiId == 0) { + throw new IllegalArgumentException(); + } + return apiId / METHOD_RANGE; + } + + public static int parseMethodId(int apiId) { + int i = parseClassId(apiId) * METHOD_RANGE; + return apiId - i; + } + + public static int getApiId(int classId, int methodId) { + return classId * METHOD_RANGE + methodId; + } + + public static String mergeParameterVariableNameDescription(String[] paramterType, String[] variableName) { + if (paramterType == null && variableName == null) { + return EMTPY_ARRAY; + } + if (paramterType.length != variableName.length) { + throw new IllegalArgumentException("args size not equal"); + } + if (paramterType.length == 0) { + return EMTPY_ARRAY; + } + + StringBuilder sb = new StringBuilder(64); + sb.append('('); + int end = paramterType.length - 1; + for (int i = 0; i < paramterType.length; i++) { + sb.append(paramterType[i]); + sb.append(' '); + sb.append(variableName[i]); + if (i < end) { + sb.append(", "); + } + } + sb.append(')'); + return sb.toString(); + } +} diff --git a/src/main/java/com/profiler/common/mapping/ClassMapping.java b/src/main/java/com/profiler/common/mapping/ClassMapping.java new file mode 100644 index 000000000..d8abb93bc --- /dev/null +++ b/src/main/java/com/profiler/common/mapping/ClassMapping.java @@ -0,0 +1,44 @@ +package com.profiler.common.mapping; + +import java.util.HashMap; +import java.util.Map; + +/** + * + */ +public class ClassMapping { + private int classId; + private String className; + private Map methodIdIndex = new HashMap(); + private Map methodMapping = new HashMap(); + + public ClassMapping(int classId, String className, MethodMapping... methodIdIndex) { + this.classId = classId; + this.className = className; + + this.methodIdIndex = new HashMap(); + this.methodMapping = new HashMap(); + for (int i = 0; i < methodIdIndex.length; i++) { + this.methodIdIndex.put(i, methodIdIndex[i]); + this.methodMapping.put(methodIdIndex[i], methodIdIndex[i]); + methodIdIndex[i].setClassMapping(this); + methodIdIndex[i].setMethodId(i); + } + } + + public int getClassId() { + return classId; + } + + public String getClassName() { + return className; + } + + public MethodMapping getMethodMapping(int methodId) { + return methodIdIndex.get(methodId); + } + + public MethodMapping getMethodMapping(MethodMapping mapping) { + return methodMapping.get(mapping); + } +} diff --git a/src/main/java/com/profiler/common/mapping/MethodMapping.java b/src/main/java/com/profiler/common/mapping/MethodMapping.java new file mode 100644 index 000000000..307329f6f --- /dev/null +++ b/src/main/java/com/profiler/common/mapping/MethodMapping.java @@ -0,0 +1,87 @@ +package com.profiler.common.mapping; + +import java.util.Arrays; + +/** + * + */ +public class MethodMapping { + private String methodName; + private String[] parameterType; + private String[] parameterName; + + private int methodId; + private ClassMapping classMapping; + + public MethodMapping(String methodName, String[] parameterType) { + this.methodName = methodName; + this.parameterType = parameterType; + } + + public MethodMapping(String methodName, String[] parameterType, String[] parameterName) { + this.methodName = methodName; + this.parameterType = parameterType; + this.parameterName = parameterName; + } + + public ClassMapping getClassMapping() { + return classMapping; + } + + public void setClassMapping(ClassMapping classMapping) { + this.classMapping = classMapping; + } + + public String[] getParameterName() { + return parameterName; + } + + public void setParameterName(String[] parameterName) { + this.parameterName = parameterName; + } + + public String[] getParameterType() { + return parameterType; + } + + public void setParameterType(String[] parameterType) { + this.parameterType = parameterType; + } + + public String getMethodName() { + return methodName; + } + + public void setMethodName(String methodName) { + this.methodName = methodName; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + MethodMapping that = (MethodMapping) o; + + if (!Arrays.equals(parameterType, that.parameterType)) return false; + if (methodName != null ? !methodName.equals(that.methodName) : that.methodName != null) return false; + + return true; + } + + @Override + public int hashCode() { + int result = methodName != null ? methodName.hashCode() : 0; + result = 31 * result + (parameterType != null ? Arrays.hashCode(parameterType) : 0); + return result; + } + + public void setMethodId(int methodId) { + this.methodId = methodId; + } + + public int getMethodId() { + return methodId; + } +} +