/************************************************************************************** * 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.definition; import org.codehaus.aspectwerkz.expression.ExpressionInfo; import org.codehaus.aspectwerkz.aspect.AdviceType; import org.codehaus.aspectwerkz.reflect.MethodInfo; import org.codehaus.aspectwerkz.util.Strings; import org.codehaus.aspectwerkz.DeploymentModel; import org.codehaus.aspectwerkz.cflow.CflowBinding; import java.util.List; /** * Holds the meta-data for the advices. * * @author <a href="mailto:jboner@codehaus.org">Jonas Boner </a> */ public class AdviceDefinition { /** * The name of the advice. * It is the advice method name and optionnaly the call signature. * e.g. advice or advice() or advice(JoinPoint jp) or myadvice(JoinPoint myJp , java.lang.String foo) ... */ private String m_name; /** * The type of the advice. */ private AdviceType m_type; /** * The aspect class name. */ private final String m_aspectClassName; /** * The aspect name. */ private final String m_aspectName; /** * The pointcut expression. */ private ExpressionInfo m_expressionInfo; /** * The method for the advice. */ private final MethodInfo m_method; /** * The attribute for the advice. */ private String m_attribute = ""; /** * The aspect definition holding this advice definition. */ private AspectDefinition m_aspectDefinition; /** * The special arg type, such as returning(TYPE) or throwing(TYPE). */ private String m_specialArgumentType; /** * Indicates if this advice will need a cflow or cflowbelow runtime check */ private boolean m_hasCflowOrCflowBelow = false; /** * TODO only use this method and make ctor private? * <p/> * Creates a new advice definition. * * @param adviceName the advice name * @param adviceType the advice type * @param expression the advice expression * @param specialArgumentType the arg * @param aspectName the aspect name * @param aspectClassName the aspect class name * @param method the advice method * @param aspectDef the aspect definition * @return the new advice definition */ public static AdviceDefinition newInstance(final String adviceName, final AdviceType adviceType, final String expression, final String specialArgumentType, final String aspectName, final String aspectClassName, final MethodInfo method, final AspectDefinition aspectDef) { ExpressionInfo expressionInfo = new ExpressionInfo( expression, aspectDef.getQualifiedName() ); // support for pointcut signature String adviceCallSignature = null; String resolvedSpecialArgumentType = specialArgumentType; if (adviceName.indexOf('(') > 0) { adviceCallSignature = adviceName.substring(adviceName.indexOf('(') + 1, adviceName.lastIndexOf(')')); String[] parameters = Strings.splitString(adviceCallSignature, ","); for (int i = 0; i < parameters.length; i++) { String[] parameterInfo = Strings.splitString( Strings.replaceSubString(parameters[i].trim(), " ", " "), " " ); // skip the parameter if this ones is a after returning / throwing binding if (parameterInfo[1].equals(specialArgumentType)) { resolvedSpecialArgumentType = parameterInfo[0]; expressionInfo.setSpecialArgumentName(parameterInfo[1]); } else { expressionInfo.addArgument( parameterInfo[1], parameterInfo[0], aspectDef.getClassInfo().getClassLoader() ); } } } return new AdviceDefinition( adviceName, adviceType, resolvedSpecialArgumentType, aspectName, aspectClassName, expressionInfo, method, aspectDef ); } /** * Creates a new advice meta-data instance. * * @param name the name of the expressionInfo * @param type the type of the advice * @param specialArgumentType the special arg type, such as returning(TYPE) or throwing(TYPE) * @param aspectName the name of the aspect * @param aspectClassName the class name of the aspect * @param expressionInfo the expressionInfo * @param methodInfo the methodInfo */ public AdviceDefinition(final String name, final AdviceType type, final String specialArgumentType, final String aspectName, final String aspectClassName, final ExpressionInfo expressionInfo, final MethodInfo methodInfo, final AspectDefinition aspectDef) { if (name == null) { throw new IllegalArgumentException("name can not be null"); } if (type == null) { throw new IllegalArgumentException("illegal advice type"); } if (aspectName == null) { throw new IllegalArgumentException("aspect name can not be null"); } if (aspectClassName == null) { throw new IllegalArgumentException("class name can not be null"); } if (methodInfo == null) { throw new IllegalArgumentException("methodInfo can not be null"); } if (aspectDef == null) { throw new IllegalArgumentException("aspect definition can not be null"); } m_name = name; m_type = type; m_specialArgumentType = specialArgumentType; m_aspectName = aspectName; m_aspectClassName = aspectClassName; m_expressionInfo = expressionInfo; m_method = methodInfo; m_aspectDefinition = aspectDef; // get the cflow Advice bindings to know if this advice binding is using cflow or cflowbelow List cflowBindings = CflowBinding.getCflowBindingsForCflowOf(m_expressionInfo); m_hasCflowOrCflowBelow = (cflowBindings.size() > 0); } /** * Returns the advice type. * * @return the advice type */ public AdviceType getType() { return m_type; } /** * Returns the name of the advice. * * @return the name */ public String getName() { return m_name; } /** * Returns the fully qualified name for the advice * * @return the fully qualified name */ public String getQualifiedName() { return m_aspectDefinition.getQualifiedName() + '.' + m_name; } /** * Sets the name of the advice. * * @param name the name */ public void setName(final String name) { m_name = name.trim(); } /** * Returns the expression. * <p/> * TODO should return NULL object if null * * @return the expression */ public ExpressionInfo getExpressionInfo() { return m_expressionInfo; } /** * Sets the expression info. * * @param newExpression the new expression info */ public void setExpressionInfo(final ExpressionInfo newExpression) { m_expressionInfo = newExpression; // update the hasCflow caracteristic List cflowBindings = CflowBinding.getCflowBindingsForCflowOf(m_expressionInfo); m_hasCflowOrCflowBelow = (cflowBindings.size() > 0); } /** * Returns the class name. * * @return the class name */ public String getAspectClassName() { return m_aspectClassName; } /** * Returns the aspect name. * * @return the aspect name */ public String getAspectName() { return m_aspectName; } /** * Returns the special arg type, such as returning(TYPE) or throwing(TYPE). * * @return */ public String getSpecialArgumentType() { return m_specialArgumentType; } /** * Returns the method. * * @return the method */ public MethodInfo getMethodInfo() { return m_method; } /** * Returns the the deployment model for the advice * * @return the deployment model */ public DeploymentModel getDeploymentModel() { return m_aspectDefinition.getDeploymentModel(); } /** * Returns the attribute. * * @return the attribute */ public String getAttribute() { return m_attribute; } /** * Sets the attribute. * * @param attribute the attribute */ public void setAttribute(final String attribute) { m_attribute = attribute; } /** * Returns the definition for the aspect that defines this advice. * * @return the aspect definition */ public AspectDefinition getAspectDefinition() { return m_aspectDefinition; } /** * Check if the advice is bound to a pointcut with cflow or cflowbelow * * @return */ public boolean hasCflowOrCflowBelow() { return m_hasCflowOrCflowBelow; } /** * Deep copy of the definition. * * @param expressionInfo * @return */ public AdviceDefinition copyAt(final ExpressionInfo expressionInfo) { return new AdviceDefinition( getName(), getType(), getSpecialArgumentType(), getAspectName(), getAspectClassName(), expressionInfo, getMethodInfo(), m_aspectDefinition ); } /** * Equals and hashcode means we have the same advice if the aspect qualified name (not classname) and * advice name (may include signature) are the same. [AW-439 fix] * * @param o * @return */ public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof AdviceDefinition)) return false; final AdviceDefinition adviceDefinition = (AdviceDefinition) o; if (!m_aspectName.equals(adviceDefinition.m_aspectName)) return false; if (!m_name.equals(adviceDefinition.m_name)) return false; return true; } public int hashCode() { int result; result = m_name.hashCode(); result = 29 * result + m_aspectName.hashCode(); return result; } }