/**************************************************************************************
* 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.transform.spring;
import org.codehaus.aspectwerkz.transform.aopalliance.AopAllianceAspectModel;
import org.codehaus.aspectwerkz.transform.inlining.spi.AspectModel;
import org.codehaus.aspectwerkz.transform.inlining.AdviceMethodInfo;
import org.codehaus.aspectwerkz.transform.inlining.AsmHelper;
import org.codehaus.aspectwerkz.transform.inlining.compiler.CompilerInput;
import org.codehaus.aspectwerkz.reflect.ClassInfo;
import org.codehaus.aspectwerkz.definition.AspectDefinition;
import org.aopalliance.intercept.MethodInterceptor;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.ThrowsAdvice;
import org.codehaus.aspectwerkz.org.objectweb.asm.MethodVisitor;
import org.codehaus.aspectwerkz.org.objectweb.asm.Type;
import org.codehaus.aspectwerkz.aspect.AdviceType;
/**
* Implementation of the AspectModel interface for Spring framework.
* <p/>
* Provides methods for definition of aspects and framework specific bytecode generation
* used by the join point compiler.
*
* @author <a href="mailto:jboner@codehaus.org">Jonas Bon�r </a>
*/
public class SpringAspectModel extends AopAllianceAspectModel {
protected static final String ASPECT_MODEL_TYPE = "spring";
/**
* Returns the aspect model type, which is an id for the the special aspect model, can be anything as long
* as it is unique.
*
* @return the aspect model type id
*/
public String getAspectModelType() {
return ASPECT_MODEL_TYPE;
}
/**
* Defines the aspect.
*
* @param classInfo
* @param aspectDef
* @param loader
*/
public void defineAspect(final ClassInfo classInfo,
final AspectDefinition aspectDef,
final ClassLoader loader) {
ClassInfo[] interfaces = classInfo.getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
ClassInfo anInterface = interfaces[i];
if (anInterface.getName().equals(MethodInterceptor.class.getName()) ||
anInterface.getName().equals(MethodBeforeAdvice.class.getName()) ||
anInterface.getName().equals(AfterReturningAdvice.class.getName()) ||
anInterface.getName().equals(ThrowsAdvice.class.getName())) {
aspectDef.setAspectModel(ASPECT_MODEL_TYPE);
aspectDef.setContainerClassName(null);
return;
}
}
}
/**
* Returns info about the closure class, name and type (interface or class).
*
* @return the closure class info
*/
public AroundClosureClassInfo getAroundClosureClassInfo() {
return new AspectModel.AroundClosureClassInfo(
null,
new String[]{
AOP_ALLIANCE_CLOSURE_CLASS_NAME,
MethodBeforeAdvice.class.getName().replace('.', '/'),
AfterReturningAdvice.class.getName().replace('.', '/')
}
);
}
public void createBeforeOrAfterAdviceArgumentHandling(MethodVisitor methodVisitor, CompilerInput compilerInput, Type[] types, AdviceMethodInfo adviceMethodInfo, int i) {
if (AdviceType.BEFORE.equals(adviceMethodInfo.getAdviceInfo().getType())) {
createBeforeAdviceArgumentHandling(
methodVisitor,
adviceMethodInfo,
compilerInput.joinPointInstanceIndex
);
} else {
// after advice no matter what
createAfterAdviceArgumentHandling(
methodVisitor,
adviceMethodInfo,
compilerInput.joinPointInstanceIndex
);
}
}
/**
* Handles the arguments to the before advice.
*
* @param cv
* @param adviceMethodInfo
* @param joinPointInstanceIndex
*/
public void createBeforeAdviceArgumentHandling(final MethodVisitor cv, final AdviceMethodInfo adviceMethodInfo, final int joinPointInstanceIndex) {
final String joinPointClassName = adviceMethodInfo.getJoinPointClassName();
final int joinPointIndex = joinPointInstanceIndex;
cv.visitFieldInsn(
GETSTATIC,
joinPointClassName,
SIGNATURE_FIELD_NAME,
METHOD_SIGNATURE_IMPL_CLASS_SIGNATURE
);
cv.visitMethodInsn(
INVOKEVIRTUAL,
METHOD_SIGNATURE_IMPL_CLASS_NAME,
GET_METHOD_METHOD_NAME,
GET_METHOD_METHOD_SIGNATURE
);
if (Type.getArgumentTypes(adviceMethodInfo.getCalleeMemberDesc()).length == 0) {
cv.visitInsn(ACONST_NULL);
} else {
cv.visitVarInsn(ALOAD, joinPointIndex);
cv.visitMethodInsn(
INVOKEVIRTUAL,
joinPointClassName,
GET_RTTI_METHOD_NAME,
GET_RTTI_METHOD_SIGNATURE
);
cv.visitTypeInsn(CHECKCAST, METHOD_RTTI_IMPL_CLASS_NAME);
cv.visitMethodInsn(
INVOKEVIRTUAL,
METHOD_RTTI_IMPL_CLASS_NAME,
GET_PARAMETER_VALUES_METHOD_NAME,
GET_ARGUMENTS_METHOD_SIGNATURE
);
}
cv.visitVarInsn(ALOAD, joinPointIndex);
cv.visitFieldInsn(
GETFIELD,
joinPointClassName,
CALLEE_INSTANCE_FIELD_NAME,
adviceMethodInfo.getCalleeClassSignature()
);
}
/**
* Handles the arguments to the after advice.
*
* @param cv
* @param adviceMethodInfo
* @param joinPointInstanceIndex
*/
public void createAfterAdviceArgumentHandling(final MethodVisitor cv, final AdviceMethodInfo adviceMethodInfo, final int joinPointInstanceIndex) {
final String joinPointClassName = adviceMethodInfo.getJoinPointClassName();
final int joinPointIndex = joinPointInstanceIndex;
final String specArgDesc = adviceMethodInfo.getSpecialArgumentTypeDesc();
if (specArgDesc == null) {
cv.visitInsn(ACONST_NULL);
} else {
cv.visitVarInsn(ALOAD, adviceMethodInfo.getSpecialArgumentIndex());
AsmHelper.wrapPrimitiveType(cv, Type.getType(specArgDesc));
}
cv.visitFieldInsn(
GETSTATIC,
joinPointClassName,
SIGNATURE_FIELD_NAME,
METHOD_SIGNATURE_IMPL_CLASS_SIGNATURE
);
cv.visitMethodInsn(
INVOKEVIRTUAL,
METHOD_SIGNATURE_IMPL_CLASS_NAME,
GET_METHOD_METHOD_NAME,
GET_METHOD_METHOD_SIGNATURE
);
if (Type.getArgumentTypes(adviceMethodInfo.getCalleeMemberDesc()).length == 0) {
cv.visitInsn(ACONST_NULL);
} else {
cv.visitVarInsn(ALOAD, joinPointIndex);
cv.visitMethodInsn(
INVOKEVIRTUAL,
joinPointClassName,
GET_RTTI_METHOD_NAME,
GET_RTTI_METHOD_SIGNATURE
);
cv.visitTypeInsn(CHECKCAST, METHOD_RTTI_IMPL_CLASS_NAME);
cv.visitMethodInsn(
INVOKEVIRTUAL,
METHOD_RTTI_IMPL_CLASS_NAME,
GET_PARAMETER_VALUES_METHOD_NAME,
GET_ARGUMENTS_METHOD_SIGNATURE
);
}
cv.visitVarInsn(ALOAD, joinPointIndex);
cv.visitFieldInsn(
GETFIELD,
joinPointClassName,
CALLEE_INSTANCE_FIELD_NAME,
adviceMethodInfo.getCalleeClassSignature()
);
}
}