/**************************************************************************************
* 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.inlining.weaver;
import org.codehaus.aspectwerkz.joinpoint.management.JoinPointType;
import org.codehaus.aspectwerkz.reflect.ClassInfo;
import org.codehaus.aspectwerkz.transform.Context;
import org.codehaus.aspectwerkz.transform.TransformationConstants;
import org.codehaus.aspectwerkz.transform.TransformationUtil;
import org.codehaus.aspectwerkz.transform.inlining.AsmHelper;
import org.codehaus.aspectwerkz.transform.inlining.ContextImpl;
import org.codehaus.aspectwerkz.transform.inlining.EmittedJoinPoint;
import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Type;
import java.util.Set;
/**
* Adds a "proxy method" to the <tt><clinit></tt> that matches an
* <tt>staticinitialization</tt> pointcut as well as prefixing the "original method"
* (see {@link org.codehaus.aspectwerkz.transform.TransformationUtil#getPrefixedOriginalClinitName(String)}).
* <br/>
*
* @author <a href="mailto:the_mindstorm@evolva.ro">Alex Popescu</a>
*/
public class StaticInitializationVisitor extends ClassAdapter implements TransformationConstants {
private final ContextImpl m_ctx;
private String m_declaringTypeName;
private final Set m_addedMethods;
/**
* Creates a new class adapter.
*
* @param cv
* @param ctx
* @param addedMethods already added methods by AW
*/
public StaticInitializationVisitor( final ClassVisitor cv,
final Context ctx,
final Set addedMethods) {
super(cv);
m_ctx = (ContextImpl) ctx;
m_addedMethods = addedMethods;
}
/**
* Visits the class.
*
* @param access
* @param name
* @param signature
* @param superName
* @param interfaces
*/
public void visit( final int version,
final int access,
final String name,
final String signature,
final String superName,
final String[] interfaces) {
m_declaringTypeName = name;
super.visit(version, access, name, signature, superName, interfaces);
}
/**
* Visits the methods.
*
* @param access
* @param name
* @param desc
* @param signature
* @param exceptions
* @return
*/
public MethodVisitor visitMethod(final int access,
final String name,
final String desc,
final String signature,
final String[] exceptions) {
if(!CLINIT_METHOD_NAME.equals(name)) {
return super.visitMethod(access, name, desc, signature, exceptions);
}
String prefixedOriginalName = TransformationUtil.getPrefixedOriginalClinitName(m_declaringTypeName);
if (m_addedMethods.contains(AlreadyAddedMethodAdapter.getMethodKey(prefixedOriginalName, CLINIT_METHOD_SIGNATURE))) {
return super.visitMethod(access, name, desc, signature, exceptions);
}
m_ctx.markAsAdvised();
// create the proxy for the original method
createProxyMethod(access, name, desc, signature, exceptions);
// prefix the original method
return cv.visitMethod(access + ACC_PUBLIC, prefixedOriginalName, desc, signature, exceptions);
}
/**
* Creates the "proxy method", e.g. the method that has the same name and
* signature as the original method but a completely other implementation.
*
* @param access
* @param name
* @param desc
* @param signature
* @param exceptions
*/
private void createProxyMethod(final int access,
final String name,
final String desc,
final String signature,
final String[] exceptions) {
MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions);
//caller instance is null
mv.visitInsn(ACONST_NULL);
int joinPointHash = AsmHelper.calculateMethodHash(name, desc);
String joinPointClassName = TransformationUtil
.getJoinPointClassName( m_declaringTypeName,
name,
desc,
m_declaringTypeName,
JoinPointType.STATIC_INITIALIZATION_INT,
joinPointHash);
mv.visitMethodInsn(INVOKESTATIC,
joinPointClassName,
INVOKE_METHOD_NAME,
TransformationUtil.getInvokeSignatureForCodeJoinPoints( access,
desc,
m_declaringTypeName,
m_declaringTypeName));
AsmHelper.addReturnStatement(mv, Type.VOID_TYPE);
mv.visitMaxs(0, 0);
// emit the joinpoint
m_ctx.addEmittedJoinPoint(
new EmittedJoinPoint(JoinPointType.STATIC_INITIALIZATION_INT,
m_declaringTypeName,
name,
desc,
access,
m_declaringTypeName,
name,
desc,
access,
joinPointHash,
joinPointClassName,
EmittedJoinPoint.NO_LINE_NUMBER
)
);
}
}