/******************************************************************************
* WebJavin - Java Web Framework. *
* *
* Copyright (c) 2011 - Sergey "Frosman" Lukjanov, me@frostman.ru *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); *
* you may not use this file except in compliance with the License. *
* You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, software *
* distributed under the License is distributed on an "AS IS" BASIS, *
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
* See the License for the specific language governing permissions and *
* limitations under the License. *
******************************************************************************/
package ru.frostman.web.aop;
import com.google.common.collect.Lists;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.Modifier;
import ru.frostman.web.aop.thr.AopException;
import java.util.List;
/**
* @author slukjanov aka Frostman
*/
public class AopEnhancer {
private static final String METHOD_INVOCATION = "ru.frostman.web.aop.MethodInvocation";
private static final String METHOD_INTERCEPTOR = "ru.frostman.web.aop.AopMethodInterceptor";
private static final String METHOD_INTERCEPTORS = "ru.frostman.web.aop.MethodInterceptors";
public static void enhance(CtClass ctClass, List<MethodInterceptor> methodInterceptors) {
try {
for (CtMethod method : ctClass.getDeclaredMethods()) {
if (method.getAnnotation(Interceptor.class) != null) {
continue;
}
List<MethodInterceptor> interceptors = Lists.newLinkedList();
for (MethodInterceptor interceptor : methodInterceptors) {
if (interceptor.matches(method)) {
interceptors.add(interceptor);
}
}
if (interceptors.size() == 0) {
continue;
}
CtMethod wrappedMethod = new CtMethod(method, ctClass, null);
String wrappedName = "$javin$" + method.getName();
wrappedMethod.setName(wrappedName);
ctClass.addMethod(wrappedMethod);
StringBuilder body = new StringBuilder("{");
body.append(METHOD_INVOCATION).append(" mi = new ").append(METHOD_INVOCATION).append("(")
.append("\"").append(ctClass.getName()).append("\", ");
if (Modifier.isStatic(method.getModifiers())) {
body.append("null");
} else {
body.append("$0");
}
body.append(", \"").append(method.getName()).append("\", new Class");
CtClass[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length != 0) {
body.append("[]{");
int i = 0;
for (CtClass argType : parameterTypes) {
body.append(argType.getName()).append(".class");
if (i < parameterTypes.length - 1) {
body.append(", ");
}
i++;
}
body.append("}");
} else {
body.append("[0]");
}
body.append(", $args, new ").append(METHOD_INTERCEPTOR).append("[]{");
int i = 0;
for (MethodInterceptor methodInterceptor : interceptors) {
body.append(METHOD_INTERCEPTORS).append(".getInterceptor(\"")
.append(methodInterceptor.getName()).append("\")");
if (i < interceptors.size() - 1) {
body.append(", ");
}
i++;
}
body.append("});");
if (!method.getReturnType().equals(CtClass.voidType)) {
body.append("return ");
}
body.append("($r) mi.proceed();}");
method.setBody(body.toString());
}
} catch (Exception e) {
throw new AopException("Exception while aop enhancing: " + ctClass, e);
}
}
}