/**************************************************************************************
* 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.expression.ExpressionNamespace;
import org.codehaus.aspectwerkz.expression.regexp.Pattern;
import org.codehaus.aspectwerkz.util.Strings;
import org.codehaus.aspectwerkz.aspect.AdviceType;
import org.codehaus.aspectwerkz.DeploymentModel;
import org.codehaus.aspectwerkz.reflect.MethodInfo;
import org.codehaus.aspectwerkz.reflect.ClassInfo;
import org.codehaus.aspectwerkz.exception.DefinitionException;
import java.util.Iterator;
import java.util.Collection;
/**
* Helper class for the attribute and the XML definition parsers.
*
* @author <a href="mailto:jboner@codehaus.org">Jonas Bon�r </a>
* @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur </a>
*/
public class DefinitionParserHelper {
public static final String EXPRESSION_PREFIX = "AW_";
/**
* Creates and adds pointcut definition to aspect definition.
*
* @param name
* @param expression
* @param aspectDef
*/
public static void createAndAddPointcutDefToAspectDef(final String name,
final String expression,
final AspectDefinition aspectDef) {
PointcutDefinition pointcutDef = new PointcutDefinition(expression);
aspectDef.addPointcutDefinition(pointcutDef);
// name can be the "pcName(paramType paramName)"
// extract the parameter name to type map
// and register the pointcut using its name
//TODO: support for same pc name and different signature
String pointcutName = name;
String pointcutCallSignature = null;
if (name.indexOf("(") > 0) {
pointcutName = name.substring(0, name.indexOf("("));
pointcutCallSignature = name.substring(name.indexOf("(") + 1, name.lastIndexOf(")"));
}
// do a lookup first to avoid infinite recursion when:
// <pointcut name="pc" ...> [will be registered as pc]
// <advice bind-to="pc" ...> [will be registered as pc and should not override previous one !]
ExpressionNamespace namespace = ExpressionNamespace.getNamespace(aspectDef.getQualifiedName());
ExpressionInfo info = namespace.getExpressionInfoOrNull(pointcutName);
if (info == null) {
info = new ExpressionInfo(expression, aspectDef.getQualifiedName());
// extract the pointcut signature map
if (pointcutCallSignature != null) {
String[] parameters = Strings.splitString(pointcutCallSignature, ",");
for (int i = 0; i < parameters.length; i++) {
String[] parameterInfo = Strings.splitString(
Strings.replaceSubString(parameters[i].trim(), " ", " "),
" "
);
info.addArgument(parameterInfo[1], parameterInfo[0], aspectDef.getClassInfo().getClassLoader());
}
}
}
ExpressionNamespace.getNamespace(aspectDef.getQualifiedName()).addExpressionInfo(pointcutName, info);
}
/**
* Creates and adds a prepared pointcut definition to virtual aspect definition.
*
* @param name
* @param expression
* @param systemDef
*/
public static void createAndAddDeploymentScopeDef(final String name,
final String expression,
final SystemDefinition systemDef) {
AspectDefinition aspectDef = systemDef.getAspectDefinition(Virtual.class.getName());
aspectDef.addPointcutDefinition(new PointcutDefinition(expression));
systemDef.addDeploymentScope(new DeploymentScope(name, expression));
}
/**
* Creates and adds an advisable definition to virtual aspect definition.
*
* @param expression
* @param systemDef
*/
public static void createAndAddAdvisableDef(final String expression, final SystemDefinition systemDef) {
AspectDefinition virtualAspectDef = systemDef.getAspectDefinition(Virtual.class.getName());
virtualAspectDef.addPointcutDefinition(new PointcutDefinition(expression));
AdviceDefinition virtualAdviceDef = (AdviceDefinition) virtualAspectDef.getBeforeAdviceDefinitions().get(0);
ExpressionInfo oldExpressionInfo = virtualAdviceDef.getExpressionInfo();
String newExpression;
if (oldExpressionInfo != null) {
String oldExpression = oldExpressionInfo.toString();
newExpression = oldExpression + " || " + expression;
} else {
newExpression = expression;
}
virtualAdviceDef.setExpressionInfo(
new ExpressionInfo(
newExpression,
virtualAspectDef.getQualifiedName()
)
);
}
/**
* Attaches all deployment scopes in a system to the virtual advice.
*
* @param systemDef the system definition
*/
public static void attachDeploymentScopeDefsToVirtualAdvice(final SystemDefinition systemDef) {
final AspectDefinition virtualAspectDef = systemDef.getAspectDefinition(Virtual.class.getName());
final AdviceDefinition virtualAdviceDef = (AdviceDefinition) virtualAspectDef.getBeforeAdviceDefinitions().get(
0
);
final StringBuffer newExpression = new StringBuffer();
final ExpressionInfo oldExpressionInfo = virtualAdviceDef.getExpressionInfo();
if (oldExpressionInfo != null) {
String oldExpression = oldExpressionInfo.toString();
newExpression.append(oldExpression);
}
final Collection deploymentScopes = systemDef.getDeploymentScopes();
if (deploymentScopes.size() != 0 && oldExpressionInfo != null) {
newExpression.append(" || ");
}
for (Iterator it = deploymentScopes.iterator(); it.hasNext();) {
DeploymentScope deploymentScope = (DeploymentScope) it.next();
newExpression.append(deploymentScope.getExpression());
if (it.hasNext()) {
newExpression.append(" || ");
}
}
if (newExpression.length() != 0) {
virtualAdviceDef.setExpressionInfo(
new ExpressionInfo(
newExpression.toString(),
virtualAspectDef.getQualifiedName()
)
);
}
}
/**
* Creates and add mixin definition to system definition.
*
* @param mixinClassInfo
* @param expression
* @param deploymentModel
* @param isTransient
* @param systemDef
* @return the mixin definition
*/
public static MixinDefinition createAndAddMixinDefToSystemDef(final ClassInfo mixinClassInfo,
final String expression,
final DeploymentModel deploymentModel,
final boolean isTransient,
final SystemDefinition systemDef) {
final MixinDefinition mixinDef = createMixinDefinition(
mixinClassInfo,
expression,
deploymentModel,
isTransient,
systemDef
);
// check doublons - TODO change ArrayList to HashMap since NAME is a key
MixinDefinition doublon = null;
for (Iterator intros = systemDef.getMixinDefinitions().iterator(); intros.hasNext();) {
MixinDefinition intro = (MixinDefinition) intros.next();
if (intro.getMixinImpl().getName().equals(mixinDef.getMixinImpl().getName())) {
doublon = intro;
intro.addExpressionInfos(mixinDef.getExpressionInfos());
break;
}
}
if (doublon == null) {
systemDef.addMixinDefinition(mixinDef);
}
return mixinDef;
}
/**
* Creates and add interface introduction definition to aspect definition.
*
* @param expression
* @param introductionName
* @param interfaceClassName
* @param aspectDef
*/
public static void createAndAddInterfaceIntroductionDefToAspectDef(final String expression,
final String introductionName,
final String interfaceClassName,
final AspectDefinition aspectDef) {
// Introduction name is unique within an aspectDef only
InterfaceIntroductionDefinition introDef = createInterfaceIntroductionDefinition(
introductionName,
expression,
interfaceClassName,
aspectDef
);
aspectDef.addInterfaceIntroductionDefinition(introDef);
}
/**
* 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 methodInfo the advice methodInfo
* @param aspectDef the aspect definition
* @return the new advice definition
*/
public static AdviceDefinition createAdviceDefinition(final String adviceName,
final AdviceType adviceType,
final String expression,
final String specialArgumentType,
final String aspectName,
final String aspectClassName,
final MethodInfo methodInfo,
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(), " ", " "),
" "
);
// Note: for XML defined aspect, we support anonymous parameters like
// advice(JoinPoint, Rtti) as well as abbreviations, so we have to assign
// them a name here, as well as their real type
String paramName, paramType = null;
if (parameterInfo.length == 2) {
paramName = parameterInfo[1];
paramType = parameterInfo[0];
//FIXME -- ?? what ??
} else {
paramName = "anonymous_" + i;
paramType = (String) Pattern.ABBREVIATIONS.get(parameterInfo[0]);
}
// skip the parameter if this ones is a after returning / throwing binding
if (paramName.equals(specialArgumentType)) {
resolvedSpecialArgumentType = paramType;
expressionInfo.setSpecialArgumentName(paramName);
} else {
expressionInfo.addArgument(paramName, paramType, aspectDef.getClassInfo().getClassLoader());
}
}
}
// check that around advice return Object else the compiler will fail
if (adviceType.equals(AdviceType.AROUND)) {
if (!"java.lang.Object".equals(methodInfo.getReturnType().getName())) {
throw new DefinitionException(
"around advice must return java.lang.Object : " + aspectClassName + "." + methodInfo.getName()
);
}
}
final AdviceDefinition adviceDef = new AdviceDefinition(
adviceName,
adviceType,
resolvedSpecialArgumentType,
aspectName,
aspectClassName,
expressionInfo,
methodInfo,
aspectDef
);
return adviceDef;
}
/**
* Creates an introduction definition.
*
* @param mixinClassInfo
* @param expression
* @param deploymentModel
* @param isTransient
* @param systemDef
* @return
*/
public static MixinDefinition createMixinDefinition(final ClassInfo mixinClassInfo,
final String expression,
final DeploymentModel deploymentModel,
final boolean isTransient,
final SystemDefinition systemDef) {
final MixinDefinition mixinDef = new MixinDefinition(mixinClassInfo, deploymentModel, isTransient, systemDef);
if (expression != null) {
ExpressionInfo expressionInfo = new ExpressionInfo(expression, systemDef.getUuid());
// auto-name the pointcut which is anonymous for introduction
ExpressionNamespace.getNamespace(systemDef.getUuid()).addExpressionInfo(
EXPRESSION_PREFIX + expression.hashCode(),
expressionInfo
);
mixinDef.addExpressionInfo(expressionInfo);
}
return mixinDef;
}
/**
* Creates a new interface introduction definition.
*
* @param introductionName the introduction name
* @param expression the pointcut expression
* @param interfaceClassName the class name of the interface
* @param aspectDef the aspect definition
* @return the new introduction definition
*/
public static InterfaceIntroductionDefinition createInterfaceIntroductionDefinition(final String introductionName,
final String expression,
final String interfaceClassName,
final AspectDefinition aspectDef) {
final InterfaceIntroductionDefinition introDef = new InterfaceIntroductionDefinition(
introductionName, interfaceClassName
);
if (expression != null) {
ExpressionInfo expressionInfo = new ExpressionInfo(expression, aspectDef.getQualifiedName());
// auto-name the pointcut which is anonymous for introduction
ExpressionNamespace.getNamespace(aspectDef.getQualifiedName()).addExpressionInfo(
EXPRESSION_PREFIX + expression.hashCode(),
expressionInfo
);
introDef.addExpressionInfo(expressionInfo);
}
return introDef;
}
}