/**************************************************************************************
* Copyright (c) Jonas Bon�r, Alexandre Vasseur. All rights reserved. *
* http://aspectwerkz.codehaus.org *
* ---------------------------------------------------------------------------------- *
* The software in this package is published under the terms of the LGPL license *
* a copy of which has been included with this distribution in the license.txt file. *
**************************************************************************************/
package org.codehaus.aspectwerkz.ejb3;
import org.codehaus.aspectwerkz.transform.inlining.spi.AspectModel;
import org.codehaus.aspectwerkz.transform.inlining.spi.AspectModel.AroundClosureClassInfo;
import org.codehaus.aspectwerkz.transform.inlining.AspectInfo;
import org.codehaus.aspectwerkz.transform.inlining.AdviceMethodInfo;
import org.codehaus.aspectwerkz.transform.inlining.compiler.CompilationInfo;
import org.codehaus.aspectwerkz.transform.inlining.compiler.CompilerInput;
import org.codehaus.aspectwerkz.transform.JoinPointCompiler;
import org.codehaus.aspectwerkz.transform.TransformationConstants;
import org.codehaus.aspectwerkz.reflect.ClassInfo;
import org.codehaus.aspectwerkz.definition.AspectDefinition;
import org.codehaus.aspectwerkz.joinpoint.MethodSignature;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
/**
* @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
*/
public class EJBInterceptorModel implements AspectModel, Opcodes, TransformationConstants {
public final static String TYPE = EJBInterceptorModel.class.getName();
private final static AroundClosureClassInfo EJB3_CLOSURE = new AroundClosureClassInfo(
"java.lang.Object",
new String[]{"javax.ejb.InvocationContext"}
);
/**
* Unique model ID
* @return
*/
public String getAspectModelType() {
return TYPE;
}
/**
* Singleton instance is enough
*
* @param compilationModel
* @return
*/
public AspectModel getInstance(CompilationInfo.Model compilationModel) {
return this;
}
/**
* Called at definition time.
*
* @param aspectClassInfo
* @param aspectDef
* @param loader
*/
public void defineAspect(ClassInfo aspectClassInfo, AspectDefinition aspectDef, ClassLoader loader) {
//TODO if we want to reuse the interceptor in some aop.xml
}
public AroundClosureClassInfo getAroundClosureClassInfo() {
return EJB3_CLOSURE;
}
public void createInvocationOfAroundClosureSuperClass(MethodVisitor cv) {
;//not needed, InvocationContext is an interface
}
public void createAndStoreStaticAspectInstantiation(ClassVisitor cw, MethodVisitor cv, AspectInfo aspectInfo, String joinPointClassName) {
// the spec does not define the interceptor life cycle
// this impl makes em one per EJB CLASS
cw.visitField(
ACC_PRIVATE + ACC_STATIC,
aspectInfo.getAspectFieldName(),
aspectInfo.getAspectClassSignature(),
null,
null
);
// new it and store it as part of the static initialization
cv.visitTypeInsn(NEW, aspectInfo.getAspectClassName());
cv.visitInsn(DUP);
cv.visitMethodInsn(INVOKESPECIAL, aspectInfo.getAspectClassName(), INIT_METHOD_NAME, NO_PARAM_RETURN_VOID_SIGNATURE);
cv.visitFieldInsn(PUTSTATIC, joinPointClassName, aspectInfo.getAspectFieldName(), aspectInfo.getAspectClassSignature());
}
public void loadAspect(MethodVisitor cv, CompilerInput input, AspectInfo aspectInfo) {
// interceptor was stored as a static field
cv.visitFieldInsn(GETSTATIC, input.joinPointClassName, aspectInfo.getAspectFieldName(), aspectInfo.getAspectClassSignature());
}
public void createBeforeOrAfterAdviceArgumentHandling(MethodVisitor cv, CompilerInput input, Type[] joinPointArgumentTypes, AdviceMethodInfo adviceMethodInfo, int specialArgIndex) {
;// cannot happen so lets skip it
}
public void createAroundAdviceArgumentHandling(MethodVisitor cv, CompilerInput input, Type[] joinPointArgumentTypes, AdviceMethodInfo adviceMethodInfo) {
// interceptor only accept the closure as sole argument ie "this" within proceed()
cv.visitVarInsn(ALOAD, 0);
}
public void createMandatoryMethods(ClassWriter cw, JoinPointCompiler compiler) {
//getBean
MethodVisitor getBean = cw.visitMethod(
ACC_PUBLIC,
"getBean",
"()Ljava/lang/Object;",
null,
EMPTY_STRING_ARRAY
);
getBean.visitVarInsn(ALOAD, 0);
getBean.visitFieldInsn(
GETFIELD,
compiler.getJoinPointClassName(),
CALLER_INSTANCE_FIELD_NAME,
compiler.getCallerClassSignature()
);
getBean.visitInsn(ARETURN);
getBean.visitMaxs(0, 0);
// getParameters
MethodVisitor getParameters = cw.visitMethod(
ACC_PUBLIC,
"getParameters",
"()[Ljava/lang/Object;",
null,
EMPTY_STRING_ARRAY
);
compiler.createArgumentArrayAt(getParameters, 1);
getParameters.visitVarInsn(ALOAD, 1);
getParameters.visitInsn(ARETURN);
getParameters.visitMaxs(0, 0);
// getMethod
MethodVisitor getMethod = cw.visitMethod(
ACC_PUBLIC,
"getMethod",
"()Ljava/lang/reflect/Method;",
null,
EMPTY_STRING_ARRAY
);
getMethod.visitFieldInsn(
GETSTATIC,
compiler.getJoinPointClassName(),
"SIGNATURE",
METHOD_SIGNATURE_IMPL_CLASS_SIGNATURE
);
getMethod.visitMethodInsn(
INVOKEINTERFACE,
Type.getInternalName(MethodSignature.class),
"getMethod",
"()Ljava/lang/reflect/Method;"
);
getMethod.visitInsn(ARETURN);
getMethod.visitMaxs(0, 0);
// TODO supposely setParameters, getEJBContext etc
}
public void createAndStoreRuntimeAspectInstantiation(MethodVisitor cv, CompilerInput input, AspectInfo aspectInfo) {
;// nothing needed
}
public boolean requiresReflectiveInfo() {
return true;// we want a new InvocationContext at each join point invocation
}
}