/**************************************************************************************
* 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.cflow;
import org.codehaus.aspectwerkz.expression.ExpressionInfo;
import org.codehaus.aspectwerkz.definition.SystemDefinition;
import org.codehaus.aspectwerkz.definition.AspectDefinition;
import org.codehaus.aspectwerkz.definition.AdviceDefinition;
import org.codehaus.aspectwerkz.reflect.impl.java.JavaClassInfo;
import org.codehaus.aspectwerkz.reflect.ClassInfo;
import org.codehaus.aspectwerkz.reflect.MethodInfo;
import org.codehaus.aspectwerkz.aspect.AdviceType;
import java.util.List;
import java.util.ArrayList;
/**
* A Cflow binding represents an extracted cflow or cflowbelow subexpression
* <p/>
* For a given pointcut "pcA and cflowA or cflowbelowB", we will extract two bindings.
* The m_cflowID must be unique on a per cflow sub expresion basis ie JVM wide.
*
* @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
*/
public class CflowBinding {
/**
* the base implementation that hosts the cflow advices
*/
private final static ClassInfo ABSTRACT_CFLOWCLASS = JavaClassInfo.getClassInfo(AbstractCflowSystemAspect.class);
private final static MethodInfo CFLOW_ENTER_ADVICE;
private final static MethodInfo CFLOW_EXIT_ADVICE;
static {
MethodInfo enter = null;
MethodInfo exit = null;
for (int i = 0; i < ABSTRACT_CFLOWCLASS.getMethods().length; i++) {
MethodInfo methodInfo = ABSTRACT_CFLOWCLASS.getMethods()[i];
if (methodInfo.getName().equals("enter")) {
enter = methodInfo;
} else if (methodInfo.getName().equals("exit")) {
exit = methodInfo;
}
}
if (enter == null || exit == null) {
throw new Error("Could not gather cflow advices from " + AbstractCflowSystemAspect.class);
} else {
CFLOW_ENTER_ADVICE = enter;
CFLOW_EXIT_ADVICE = exit;
}
}
/**
* cflow unique id
*/
private int m_cflowID;
/**
* pointcut that represents this cflow sub-expression
*/
private ExpressionInfo m_cflowSubExpression;
/**
* marker if this binding is a cflow below, not used at the moment
*/
private boolean m_isCflowBelow;
/**
* Cosntructs a new cflow binding
*
* @param cflowID
* @param cflowSubExpression
* @param isCflowBelow
*/
public CflowBinding(int cflowID, ExpressionInfo cflowSubExpression, boolean isCflowBelow) {
this.m_cflowID = cflowID;
this.m_cflowSubExpression = cflowSubExpression;
this.m_isCflowBelow = isCflowBelow;
}
/**
* @return the sub expression
*/
public ExpressionInfo getExpression() {
return m_cflowSubExpression;
}
/**
* Extract the cflow bindings from any pointcut
*
* @param expressionInfo the pointcut expression frow where to extract the cflow bindings
* @return a list of CflowBinding, can be empty
*/
public static List getCflowBindingsForCflowOf(ExpressionInfo expressionInfo) {
List cflowBindings = new ArrayList();
if (expressionInfo != null) {
expressionInfo.getCflowAspectExpression().populateCflowAspectBindings(cflowBindings);
}
return cflowBindings;
}
/**
* Create an aspect definition for this cflow binding in the given system.
* The cflow jit aspects will gets compiled and loaded
*
* @param systemDefinition
* @param loader
* @return the cflow aspect definition
*/
public AspectDefinition getAspectDefinition(SystemDefinition systemDefinition, ClassLoader loader) {
String aspectName = CflowCompiler.getCflowAspectClassName(m_cflowID);
// check if we have already register this aspect
// TODO: it may happen that the aspect gets register somewhere up in the hierarchy ??
// it is optim only
// TODO: how to do this class define lazyly and not pass in a classloader ?
// could be done in the JIT jp clinit when 1+ advice has a cflow binding
Class aspectClass = CflowCompiler.compileCflowAspectAndAttachToClassLoader(loader, m_cflowID);
ClassInfo cflowAspectInfo = JavaClassInfo.getClassInfo(aspectClass);
AspectDefinition aspectDef = new AspectDefinition(
aspectName.replace('/', '.'),
cflowAspectInfo,
systemDefinition
);
aspectDef.addBeforeAdviceDefinition(
new AdviceDefinition(
CFLOW_ENTER_ADVICE.getName(),
AdviceType.BEFORE,
null,
aspectName,
aspectName,
m_cflowSubExpression,
CFLOW_ENTER_ADVICE,
aspectDef
)
);
aspectDef.addAfterAdviceDefinition(
new AdviceDefinition(
CFLOW_EXIT_ADVICE.getName(),
AdviceType.AFTER_FINALLY,
null,
aspectName,
aspectName,
m_cflowSubExpression,
CFLOW_EXIT_ADVICE,
aspectDef
)
);
return aspectDef;
}
}