From dcd2b81f190199bb4c5be8ebaff1e43ed2884d03 Mon Sep 17 00:00:00 2001 From: Woonduk Kang Date: Thu, 7 Mar 2013 07:48:49 +0000 Subject: [PATCH] =?UTF-8?q?[=EA=B0=95=EC=9A=B4=EB=8D=95]=20[LUCYSUS-1744]?= =?UTF-8?q?=20jdk=EC=9D=98=20bootstrap=20=EB=A1=9C=EB=8D=94=EC=97=90=20?= =?UTF-8?q?=EB=A1=9C=EB=94=A9=EB=90=98=EB=8A=94=20=ED=8A=B9=EC=88=98?= =?UTF-8?q?=ED=95=9C=20=ED=81=B4=EB=9E=98=EC=8A=A4=EC=9D=98=20=EA=B2=BD?= =?UTF-8?q?=EC=9A=B0=20agent=EA=B0=80=20=EB=A1=9C=EB=93=9C=EB=90=98?= =?UTF-8?q?=EB=8A=94=20AppClassaLoader=EB=B3=B4=EB=8B=A4=20=EB=8D=94=20?= =?UTF-8?q?=EC=83=81=EC=9C=84=EB=9D=BC=EC=84=9C=20=EA=B8=B0=EC=A1=B4=20bci?= =?UTF-8?q?=EC=BD=94=EB=93=9C=EB=A1=9C=EB=8A=94=20=ED=95=98=EC=9C=84=20cla?= =?UTF-8?q?ss=20Loader=EC=97=90=20=EC=9C=84=EC=B9=98=ED=95=9C=20intercepto?= =?UTF-8?q?r=EC=97=90=20=EC=A0=91=EA=B7=BC=EC=9D=B4=20=EC=95=88=EB=90=98?= =?UTF-8?q?=EB=8A=94=20=EB=AC=B8=EC=A0=9C=EA=B0=80=20=EB=B0=9C=EC=83=9D?= =?UTF-8?q?=ED=95=9C=EB=8B=A4.=20=20=20-=20ContextClassLoader=EB=A5=BC=20?= =?UTF-8?q?=EC=9D=B4=EC=9A=A9=ED=95=98=EC=97=AC=20reflection=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EB=8F=99=EC=A0=81=20=ED=98=B8=EC=B6=9C=EB=90=98?= =?UTF-8?q?=EB=8A=94=20interceptor=EC=BD=94=EB=93=9C=EB=A5=BC=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=ED=95=9C=EB=8B=A4.=20=EC=9D=BC=EB=B0=98=EC=A0=81?= =?UTF-8?q?=EC=9D=B8=20was=ED=99=98=EA=B2=BD=EC=97=90=EC=84=9C=EB=8A=94=20?= =?UTF-8?q?ContextClassLoader=EB=8A=94=20WebAppClassLoader=EA=B0=80=20?= =?UTF-8?q?=EB=90=98=EC=96=B4=20Agent=EC=9D=98=20cl=EB=B3=B4=EB=8B=A4=20?= =?UTF-8?q?=EB=8D=94=20=ED=95=98=EC=9C=84=20cl=EC=9D=B4=EB=9D=BC=20?= =?UTF-8?q?=EB=AC=B8=EC=A0=9C=EA=B0=80=20=EB=B0=9C=EC=83=9D=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EC=9D=84=EA=B2=83=EC=9E=84.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://svn.bds.nhncorp.com/pe/hippo-tomcat-profiler/trunk@1301 84d0f5b1-2673-498c-a247-62c4ff18d310 --- .../interceptor/bci/InstrumentClass.java | 5 +- .../interceptor/bci/JavaAssistClass.java | 129 +++++++++++++----- .../modifier/DefaultModifierRegistry.java | 5 + .../connector/HttpURLConnectionModifier.java | 8 +- 4 files changed, 109 insertions(+), 38 deletions(-) diff --git a/src/main/java/com/profiler/interceptor/bci/InstrumentClass.java b/src/main/java/com/profiler/interceptor/bci/InstrumentClass.java index 2d8cebfad..7b63b7120 100644 --- a/src/main/java/com/profiler/interceptor/bci/InstrumentClass.java +++ b/src/main/java/com/profiler/interceptor/bci/InstrumentClass.java @@ -1,5 +1,6 @@ package com.profiler.interceptor.bci; +import javassist.CannotCompileException; import javassist.CtMethod; import com.profiler.interceptor.Interceptor; @@ -17,6 +18,8 @@ public interface InstrumentClass { int addInterceptor(String methodName, String[] args, Interceptor interceptor) throws InstrumentException, NotFoundInstrumentException; + int addInterceptorFromContextClassLoader(String methodName, String[] args, Interceptor interceptor) throws InstrumentException, NotFoundInstrumentException; + int addInterceptor(String methodName, String[] args, Interceptor interceptor, Type type) throws InstrumentException, NotFoundInstrumentException; boolean addDebugLogBeforeAfterMethod(); @@ -25,7 +28,7 @@ public interface InstrumentClass { byte[] toBytecode() throws InstrumentException ; - Class toClass() throws InstrumentException ; + Class toClass() throws InstrumentException; void addTraceVariable(String variableName, String setterName, String getterName, String variableType, String initValue) throws InstrumentException; diff --git a/src/main/java/com/profiler/interceptor/bci/JavaAssistClass.java b/src/main/java/com/profiler/interceptor/bci/JavaAssistClass.java index 241d6fe8c..157a2fd24 100644 --- a/src/main/java/com/profiler/interceptor/bci/JavaAssistClass.java +++ b/src/main/java/com/profiler/interceptor/bci/JavaAssistClass.java @@ -118,21 +118,29 @@ public class JavaAssistClass implements InstrumentClass { if (interceptor == null) { throw new IllegalArgumentException("interceptor is null"); } - return addInterceptor0(null, args, interceptor, -1, Type.auto); + return addInterceptor0(null, args, interceptor, -1, Type.auto, false); } + @Override + public int addInterceptorFromContextClassLoader(String methodName, String[] args, Interceptor interceptor) throws InstrumentException, NotFoundInstrumentException { + if (interceptor == null) { + throw new IllegalArgumentException("interceptor is null"); + } + return addInterceptor0(methodName, args, interceptor, -1, Type.auto, true); + } + @Override public int addInterceptor(String methodName, String[] args, Interceptor interceptor) throws InstrumentException, NotFoundInstrumentException { if (interceptor == null) { throw new IllegalArgumentException("interceptor is null"); } - return addInterceptor0(methodName, args, interceptor, -1, Type.auto); + return addInterceptor0(methodName, args, interceptor, -1, Type.auto, false); } @Override public int reuseInterceptor(String methodName, String[] args, int interceptorId) throws InstrumentException, NotFoundInstrumentException { - return addInterceptor0(methodName, args, null, interceptorId, Type.auto); + return addInterceptor0(methodName, args, null, interceptorId, Type.auto, false); } @Override @@ -140,7 +148,7 @@ public class JavaAssistClass implements InstrumentClass { if (interceptor == null) { throw new IllegalArgumentException("interceptor is null"); } - return addInterceptor0(methodName, args, interceptor, -1, type); + return addInterceptor0(methodName, args, interceptor, -1, type, false); } private CtBehavior getBehavior(String methodName, String[] args) throws NotFoundException { @@ -150,7 +158,7 @@ public class JavaAssistClass implements InstrumentClass { return getMethod(methodName, args); } - private int addInterceptor0(String methodName, String[] args, Interceptor interceptor, int interceptorId, Type type) throws InstrumentException, NotFoundInstrumentException { + private int addInterceptor0(String methodName, String[] args, Interceptor interceptor, int interceptorId, Type type, boolean useContextClassLoader) throws InstrumentException, NotFoundInstrumentException { CtBehavior behavior = null; try { behavior = getBehavior(methodName, args); @@ -177,20 +185,20 @@ public class JavaAssistClass implements InstrumentClass { if (type == Type.auto) { if (interceptor instanceof StaticAroundInterceptor) { - addStaticAroundInterceptor(methodName, interceptorId, behavior); + addStaticAroundInterceptor(methodName, interceptorId, behavior, useContextClassLoader); } else if (interceptor instanceof StaticBeforeInterceptor) { - addStaticBeforeInterceptor(methodName, interceptorId, behavior); + addStaticBeforeInterceptor(methodName, interceptorId, behavior, useContextClassLoader); } else if (interceptor instanceof StaticAfterInterceptor) { - addStaticAfterInterceptor(methodName, interceptorId, behavior); + addStaticAfterInterceptor(methodName, interceptorId, behavior, useContextClassLoader); } else { throw new IllegalArgumentException("unsupported"); } } else if (type == Type.around && interceptor instanceof StaticAroundInterceptor) { - addStaticAroundInterceptor(methodName, interceptorId, behavior); + addStaticAroundInterceptor(methodName, interceptorId, behavior, useContextClassLoader); } else if (type == Type.before && interceptor instanceof StaticBeforeInterceptor) { - addStaticBeforeInterceptor(methodName, interceptorId, behavior); + addStaticBeforeInterceptor(methodName, interceptorId, behavior, useContextClassLoader); } else if (type == Type.after && interceptor instanceof StaticAfterInterceptor) { - addStaticAfterInterceptor(methodName, interceptorId, behavior); + addStaticAfterInterceptor(methodName, interceptorId, behavior, useContextClassLoader); } else { throw new IllegalArgumentException("unsupported"); } @@ -236,12 +244,12 @@ public class JavaAssistClass implements InstrumentClass { interceptor.setMethodDescriptor(methodDescriptor); } - private void addStaticAroundInterceptor(String methodName, int id, CtBehavior method) throws NotFoundException, CannotCompileException { - addStaticBeforeInterceptor(methodName, id, method); - addStaticAfterInterceptor(methodName, id, method); + private void addStaticAroundInterceptor(String methodName, int id, CtBehavior method, boolean useContextClassLoader) throws NotFoundException, CannotCompileException { + addStaticBeforeInterceptor(methodName, id, method, useContextClassLoader); + addStaticAfterInterceptor(methodName, id, method, useContextClassLoader); } - private void addStaticAfterInterceptor(String methodName, int id, CtBehavior behavior) throws NotFoundException, CannotCompileException { + private void addStaticAfterInterceptor(String methodName, int id, CtBehavior behavior, boolean useContextClassLoader) throws NotFoundException, CannotCompileException { String target = getTarget(behavior); String returnType = getReturnType(behavior); @@ -249,10 +257,21 @@ public class JavaAssistClass implements InstrumentClass { String parameter = getParameter(behavior); CodeBuilder after = new CodeBuilder(); - after.begin(); - after.format(" %1$s interceptor = (%1$s) com.profiler.interceptor.InterceptorRegistry.getInterceptor(%2$d);", StaticAfterInterceptor.class.getName(), id); - after.format(" interceptor.after(%1$s, \"%2$s\", \"%3$s\", \"%4$s\", %5$s, %6$s);", target, ctClass.getName(), methodName, parameterTypeString, parameter, returnType); - after.end(); + if (useContextClassLoader) { + after.begin(); + beginAddFindInterceptorCode(id, after); + after.format(" java.lang.Class[] methodArgsClassParams = new Class[]{java.lang.Object.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.Object[].class, java.lang.Object.class};"); + after.format(" java.lang.reflect.Method method = interceptor.getClass().getMethod(\"%1$s\", methodArgsClassParams);", "after"); + after.format(" java.lang.Object[] methodParams = new java.lang.Object[] { %1$s, \"%2$s\", \"%3$s\", \"%4$s\", %5$s, %6$s };", target, ctClass.getName(), methodName, parameterTypeString, parameter, returnType); + after.format(" method.invoke(interceptor, methodParams);"); + endAddFindInterceptorCode(after); + after.end(); + } else { + after.begin(); + after.format(" %1$s interceptor = (%1$s) com.profiler.interceptor.InterceptorRegistry.getInterceptor(%2$d);", StaticAfterInterceptor.class.getName(), id); + after.format(" interceptor.after(%1$s, \"%2$s\", \"%3$s\", \"%4$s\", %5$s, %6$s);", target, ctClass.getName(), methodName, parameterTypeString, parameter, returnType); + after.end(); + } String buildAfter = after.toString(); if (logger.isLoggable(Level.INFO)) { logger.info("addStaticAfterInterceptor after behavior:" + behavior.getLongName() + " code:" + buildAfter); @@ -261,11 +280,23 @@ public class JavaAssistClass implements InstrumentClass { CodeBuilder catchCode = new CodeBuilder(); - catchCode.begin(); - catchCode.format(" %1$s interceptor = (%1$s) com.profiler.interceptor.InterceptorRegistry.getInterceptor(%2$d);", StaticAfterInterceptor.class.getName(), id); - catchCode.format(" interceptor.after(%1$s, \"%2$s\", \"%3$s\", \"%4$s\", %5$s, $e);", target, ctClass.getName(), methodName, parameterTypeString, parameter); - catchCode.append(" throw $e;"); - catchCode.end(); + if (useContextClassLoader) { + catchCode.begin(); + beginAddFindInterceptorCode(id, catchCode); + catchCode.format(" java.lang.Class[] methodArgsClassParams = new Class[]{java.lang.Object.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.Object[].class, java.lang.Object.class};"); + catchCode.format(" java.lang.reflect.Method method = interceptor.getClass().getMethod(\"%1$s\", methodArgsClassParams);", "after"); + catchCode.format(" java.lang.Object[] methodParams = new java.lang.Object[] { %1$s, \"%2$s\", \"%3$s\", \"%4$s\", %5$s, (java.lang.Object) $e };", target, ctClass.getName(), methodName, parameterTypeString, parameter); + catchCode.format(" method.invoke(interceptor, methodParams);"); + endAddFindInterceptorCode(catchCode); + catchCode.format(" throw $e;"); + catchCode.end(); + } else { + catchCode.begin(); + catchCode.format(" %1$s interceptor = (%1$s) com.profiler.interceptor.InterceptorRegistry.getInterceptor(%2$d);", StaticAfterInterceptor.class.getName(), id); + catchCode.format(" interceptor.after(%1$s, \"%2$s\", \"%3$s\", \"%4$s\", %5$s, $e);", target, ctClass.getName(), methodName, parameterTypeString, parameter); + catchCode.append(" throw $e;"); + catchCode.end(); + } String buildCatch = catchCode.toString(); if (logger.isLoggable(Level.INFO)) { logger.info("addStaticAfterInterceptor catch behavior:" + behavior.getLongName() + " code:" + buildCatch); @@ -275,6 +306,19 @@ public class JavaAssistClass implements InstrumentClass { } + private void endAddFindInterceptorCode(CodeBuilder catchCode) { + catchCode.format("}"); + } + + private void beginAddFindInterceptorCode(int id, CodeBuilder after) { + after.format("java.lang.ClassLoader contextClassLoader = java.lang.Thread.currentThread().getContextClassLoader();"); + after.format("if (contextClassLoader != null) {"); + after.format(" java.lang.Class interceptorRegistryClass = contextClassLoader.loadClass(\"com.profiler.interceptor.InterceptorRegistry\");"); + after.format(" java.lang.reflect.Method getInterceptorMethod = interceptorRegistryClass.getMethod(\"getInterceptor\", new java.lang.Class[]{ int.class });"); + after.format(" java.lang.Object[] interceptorParams = new java.lang.Object[] { java.lang.Integer.valueOf(%1$d) };", id); + after.format(" java.lang.Object interceptor = getInterceptorMethod.invoke(interceptorRegistryClass, interceptorParams);"); + } + private String getTarget(CtBehavior behavior) { boolean staticMethod = JavaAssistUtils.isStaticBehavior(behavior); if (staticMethod) { @@ -295,17 +339,35 @@ public class JavaAssistClass implements InstrumentClass { } - private void addStaticBeforeInterceptor(String methodName, int id, CtBehavior behavior) throws CannotCompileException, NotFoundException { + private void addStaticBeforeInterceptor(String methodName, int id, CtBehavior behavior, boolean useContextClassLoader) throws CannotCompileException, NotFoundException { String target = getTarget(behavior); // 인터셉터 호출시 최대한 연산량을 줄이기 위해서 정보는 가능한 정적 데이터로 생성한다. String parameterDescription = JavaAssistUtils.getParameterDescription(behavior.getParameterTypes()); String parameter = getParameter(behavior); CodeBuilder code = new CodeBuilder(); - code.begin(); - code.format(" %1$s interceptor = (%1$s) com.profiler.interceptor.InterceptorRegistry.getInterceptor(%2$d);", StaticBeforeInterceptor.class.getName(), id); - code.format(" interceptor.before(%1$s, \"%2$s\", \"%3$s\", \"%4$s\", %5$s);", target, ctClass.getName(), methodName, parameterDescription, parameter); - code.end(); + if (useContextClassLoader) { + code.begin(); +// java.lang.ClassLoader contextClassLoader = java.lang.Thread.currentThread().getContextClassLoader(); +// java.lang.Class interceptorRegistryClass = contextClassLoader.loadClass("com.profiler.interceptor.InterceptorRegistry"); +// java.lang.reflect.Method getInterceptorMethod = interceptorRegistryClass.getMethod("getInterceptor", int.class); +// java.lang.Object interceptor = getInterceptorMethod.invoke(interceptorRegistryClass, 1); +// java.lang.reflect.Method beforeMethod = interceptor.getClass().getMethod("before", java.lang.Object.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.Object[].class); +// beforeMethod.invoke(interceptor, null, null, null, null, null); +// + beginAddFindInterceptorCode(id, code); + code.format(" java.lang.Class[] beforeMethodParams = new Class[]{java.lang.Object.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.Object[].class};"); + code.format(" java.lang.reflect.Method beforeMethod = interceptor.getClass().getMethod(\"%1$s\", beforeMethodParams);", "before"); + code.format(" java.lang.Object[] beforeParams = new java.lang.Object[] { %1$s, \"%2$s\", \"%3$s\", \"%4$s\", %5$s };", target, ctClass.getName(), methodName, parameterDescription, parameter); + code.format(" beforeMethod.invoke(interceptor, beforeParams);"); + code.format("}"); + code.end(); + } else { + code.begin(); + code.format(" %1$s interceptor = (%1$s) com.profiler.interceptor.InterceptorRegistry.getInterceptor(%2$d);", StaticBeforeInterceptor.class.getName(), id); + code.format(" interceptor.before(%1$s, \"%2$s\", \"%3$s\", \"%4$s\", %5$s);", target, ctClass.getName(), methodName, parameterDescription, parameter); + code.end(); + } String buildBefore = code.toString(); if (logger.isLoggable(Level.INFO)) { logger.info("addStaticBeforeInterceptor catch behavior:" + behavior.getLongName() + " code:" + buildBefore); @@ -345,7 +407,7 @@ public class JavaAssistClass implements InstrumentClass { // TODO method의 prameter type을 interceptor에 별도 추가해야 될것으로 보임. String params = getParamsToString(method.getParameterTypes()); - addStaticAroundInterceptor(methodName, id, method); + addStaticAroundInterceptor(methodName, id, method, false); } return true; } catch (Exception e) { @@ -387,7 +449,7 @@ public class JavaAssistClass implements InstrumentClass { // constructorName + " Constructor:Param=(" + params + // ") is finished.\"); throw $e; }" // , instrumentor.getClassPool().get("java.lang.Throwable")); - addStaticAroundInterceptor(constructorName, id, constructor); + addStaticAroundInterceptor(constructorName, id, constructor, false); } return true; } catch (Exception e) { @@ -439,13 +501,12 @@ public class JavaAssistClass implements InstrumentClass { return null; } - public Class toClass() { + public Class toClass() throws InstrumentException { try { return ctClass.toClass(); } catch (CannotCompileException e) { - logger.log(Level.INFO, "CannotCompileException class:" + ctClass.getName() + " " + e.getMessage(), e); + throw new InstrumentException( "CannotCompileException class:" + ctClass.getName() + " " + e.getMessage(), e); } - return null; } public CtMethod[] getDeclaredMethods() { diff --git a/src/main/java/com/profiler/modifier/DefaultModifierRegistry.java b/src/main/java/com/profiler/modifier/DefaultModifierRegistry.java index f78c7b96e..ffcc1162c 100644 --- a/src/main/java/com/profiler/modifier/DefaultModifierRegistry.java +++ b/src/main/java/com/profiler/modifier/DefaultModifierRegistry.java @@ -12,6 +12,7 @@ import com.profiler.modifier.arcus.CacheManagerModifier; import com.profiler.modifier.arcus.MemcachedClientModifier; import com.profiler.modifier.bloc.handler.HTTPHandlerModifier; import com.profiler.modifier.connector.HTTPClientModifier; +import com.profiler.modifier.connector.HttpURLConnectionModifier; import com.profiler.modifier.db.cubrid.CubridPreparedStatementModifier; import com.profiler.modifier.db.cubrid.CubridResultSetModifier; import com.profiler.modifier.db.cubrid.CubridStatementModifier; @@ -90,6 +91,10 @@ public class DefaultModifierRegistry implements ModifierRegistry { CacheManagerModifier cacheManagerModifier = new CacheManagerModifier(byteCodeInstrumentor, agent); addModifier(cacheManagerModifier); + + // jdk HTTPUrlConnector + HttpURLConnectionModifier httpURLConnectionModifier = new HttpURLConnectionModifier(byteCodeInstrumentor, agent); + addModifier(httpURLConnectionModifier); } public void addBLOCModifier() { diff --git a/src/main/java/com/profiler/modifier/connector/HttpURLConnectionModifier.java b/src/main/java/com/profiler/modifier/connector/HttpURLConnectionModifier.java index 5324322da..4b87c8282 100644 --- a/src/main/java/com/profiler/modifier/connector/HttpURLConnectionModifier.java +++ b/src/main/java/com/profiler/modifier/connector/HttpURLConnectionModifier.java @@ -5,11 +5,11 @@ import java.util.logging.Level; import java.util.logging.Logger; import com.profiler.Agent; -import com.profiler.interceptor.Interceptor; import com.profiler.interceptor.bci.ByteCodeInstrumentor; import com.profiler.interceptor.bci.InstrumentClass; import com.profiler.interceptor.bci.InstrumentException; import com.profiler.modifier.AbstractModifier; +import com.profiler.modifier.connector.interceptors.ConnectMethodInterceptor; /** * TODO classloader문제 있음. @@ -36,8 +36,10 @@ public class HttpURLConnectionModifier extends AbstractModifier { byteCodeInstrumentor.checkLibrary(classLoader, javassistClassName); try { InstrumentClass aClass = byteCodeInstrumentor.getClass(javassistClassName); - Interceptor interceptor = byteCodeInstrumentor.newInterceptor(ClassLoader.getSystemClassLoader(), protectedDomain, "com.profiler.modifier.connector.interceptors.ConnectMethodInterceptor"); - aClass.addInterceptor("connect", null, interceptor); +// Interceptor interceptor = byteCodeInstrumentor.newInterceptor(ClassLoader.getSystemClassLoader(), protectedDomain, "com.profiler.modifier.connector.interceptors.ConnectMethodInterceptor"); + ConnectMethodInterceptor connectMethodInterceptor = new ConnectMethodInterceptor(); + aClass.addInterceptorFromContextClassLoader("connect", null, connectMethodInterceptor); + return aClass.toBytecode(); } catch (InstrumentException e) { e.printStackTrace();