package org.skywalking.apm.agent.core.plugin.interceptor.enhance;
import net.bytebuddy.implementation.bind.annotation.AllArguments;
import net.bytebuddy.implementation.bind.annotation.Origin;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.SuperCall;
import org.skywalking.apm.agent.core.plugin.interceptor.loader.InterceptorInstanceLoader;
import org.skywalking.apm.logging.ILog;
import org.skywalking.apm.logging.LogManager;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;
/**
* The actual byte-buddy's interceptor to intercept class instance methods.
* In this class, it provide a bridge between byte-buddy and sky-walking plugin.
*
* @author wusheng
*/
public class ClassStaticMethodsInterceptor {
private static final ILog logger = LogManager.getLogger(ClassStaticMethodsInterceptor.class);
/**
* A class full name, and instanceof {@link StaticMethodsAroundInterceptor}
* This name should only stay in {@link String}, the real {@link Class} type will trigger classloader failure.
* If you want to know more, please check on books about Classloader or Classloader appointment mechanism.
*/
private String staticMethodsAroundInterceptorClassName;
/**
* Set the name of {@link ClassStaticMethodsInterceptor#staticMethodsAroundInterceptorClassName}
*
* @param staticMethodsAroundInterceptorClassName class full name.
*/
public ClassStaticMethodsInterceptor(String staticMethodsAroundInterceptorClassName) {
this.staticMethodsAroundInterceptorClassName = staticMethodsAroundInterceptorClassName;
}
/**
* Intercept the target static method.
*
* @param clazz target class
* @param allArguments all method arguments
* @param method method description.
* @param zuper the origin call ref.
* @return the return value of target static method.
* @throws Exception only throw exception because of zuper.call() or unexpected exception in sky-walking ( This is a
* bug, if anything triggers this condition ).
*/
@RuntimeType
public Object intercept(@Origin Class<?> clazz, @AllArguments Object[] allArguments, @Origin Method method,
@SuperCall Callable<?> zuper) throws Throwable {
StaticMethodsAroundInterceptor interceptor = InterceptorInstanceLoader
.load(staticMethodsAroundInterceptorClassName, clazz.getClassLoader());
StaticMethodInvokeContext interceptorContext = new StaticMethodInvokeContext(clazz, method.getName(), allArguments, method.getParameterTypes());
MethodInterceptResult result = new MethodInterceptResult();
try {
interceptor.beforeMethod(interceptorContext, result);
} catch (Throwable t) {
logger.error(t, "class[{}] before static method[{}] intercept failure", clazz, method.getName());
}
Object ret = null;
try {
if (!result.isContinue()) {
ret = result._ret();
} else {
ret = zuper.call();
}
} catch (Throwable t) {
try {
interceptor.handleMethodException(t, interceptorContext);
} catch (Throwable t2) {
logger.error(t2, "class[{}] handle static method[{}] exception failure", clazz, method.getName(), t2.getMessage());
}
throw t;
} finally {
try {
ret = interceptor.afterMethod(interceptorContext, ret);
} catch (Throwable t) {
logger.error(t, "class[{}] after static method[{}] intercept failure:{}", clazz, method.getName(), t.getMessage());
}
}
return ret;
}
}