/************************************************************************************** * 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. * <p/> * Note: CflowBinding hashcode depends on Cflow_ID (sub expr) + isCflowBelow only. * * @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; /** * pointcut that represents the containing expression */ private ExpressionInfo m_outerExpression; /** * 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, ExpressionInfo outerExpression, boolean isCflowBelow) { m_cflowID = cflowID; m_cflowSubExpression = cflowSubExpression; m_outerExpression = outerExpression; m_isCflowBelow = isCflowBelow; } /** * @return the sub expression */ public ExpressionInfo getExpression() { return m_cflowSubExpression; } /** * Extract the cflow bindings from any pointcut * This includes both cflow and cflowbelow * * @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; } public boolean isCflowBelow() { return m_isCflowBelow; } public int getCflowID() { return m_cflowID; } public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof CflowBinding)) return false; final CflowBinding cflowBinding = (CflowBinding) o; if (m_cflowID != cflowBinding.m_cflowID) return false; if (m_isCflowBelow != cflowBinding.m_isCflowBelow) return false; return true; } public int hashCode() { int result; result = m_cflowID; result = 29 * result + (m_isCflowBelow ? 1 : 0); return result; } }