/************************************************************************************** * 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.perx; import org.codehaus.aspectwerkz.AspectContext; import org.codehaus.aspectwerkz.DeploymentModel; import org.codehaus.aspectwerkz.reflect.ClassInfo; import org.codehaus.aspectwerkz.reflect.MethodInfo; import org.codehaus.aspectwerkz.reflect.impl.java.JavaClassInfo; import org.codehaus.aspectwerkz.expression.ExpressionInfo; import org.codehaus.aspectwerkz.definition.AspectDefinition; import org.codehaus.aspectwerkz.definition.SystemDefinition; import org.codehaus.aspectwerkz.definition.AdviceDefinition; import org.codehaus.aspectwerkz.aspect.management.HasInstanceLevelAspect; import org.codehaus.aspectwerkz.aspect.AdviceType; import org.codehaus.aspectwerkz.transform.TransformationConstants; /** * Generic aspect used by perX deployment modes to initialize the aspect instance. * It gets registered programatically when finding perX aspects. * fake * * @author <a href='mailto:the_mindstorm@evolva.ro'>Alexandru Popescu</a> */ public class PerObjectAspect { /** * PerObjectAspect class name */ public static final String PEROBJECT_ASPECT_NAME = PerObjectAspect.class.getName().replace('/', '.'); /** * Name of system advice that will bind the aspect to the perX X instance. * This advice is bound to the "X && target(aw_instance)" pointcut for pertarget(X) * and "X && this(aw_instance)" pointcut for perthis(X) and thus its signature * is a beforePerObjecr(HasInstanceLevelAspect aw_instance). */ private static final String BEFORE_ADVICE_NAME = "beforePerObject"; /** * Name of the advice argument where we bound the perX X instance. */ public static final String ADVICE_ARGUMENT_NAME = "aw_Instance"; /** * ClassInfo and method Info for the PerObjectAspect */ private static final ClassInfo PEROBJECT_CLASSINFO = JavaClassInfo.getClassInfo(PerObjectAspect.class); private static MethodInfo BEFORE_ADVICE_METHOD_INFO; static { MethodInfo[] methods = PEROBJECT_CLASSINFO.getMethods(); for(int i = 0; i < methods.length; i++) { if(PerObjectAspect.BEFORE_ADVICE_NAME.equals(methods[i].getName())) { BEFORE_ADVICE_METHOD_INFO = methods[i]; break; } } if (BEFORE_ADVICE_METHOD_INFO == null) { throw new Error("Could not find PerObjectAspect." + BEFORE_ADVICE_NAME); } } /** * One PerObjectAspect instance gets created for each X of perthis(X) / pertarget(X) and * is passed as aspect context parameters the Qname of the perX aspect for which it acts * and the container class name of that one. */ private static final String ASPECT_QNAME_PARAM = "perobject.aspect.qname"; private static final String CONTAINER_CLASSNAME_PARAM = "perobject.container.classname"; private static final String ADVICE_ARGUMENT_TYPE = TransformationConstants.HAS_INSTANCE_LEVEL_ASPECT_INTERFACE_NAME.replace('/', '.'); private static final String ADVICE_SIGNATURE = BEFORE_ADVICE_NAME + "(" + ADVICE_ARGUMENT_TYPE + " " + ADVICE_ARGUMENT_NAME + ")"; private final String m_aspectQName; private final String m_containerClassName; /** * PerObjectAspect constructor. * We keep track of the aspectQname and container class name to further call Aspects.aspectOf * * @param ctx */ public PerObjectAspect(AspectContext ctx) { m_aspectQName = ctx.getParameter(ASPECT_QNAME_PARAM); m_containerClassName = ctx.getParameter(CONTAINER_CLASSNAME_PARAM); } /** * Before perPointcut && this/target(targetInstance) bound that will associate the aspect and the instance. * Note: do not refactor the names here without refactoring the constants. */ public void beforePerObject(HasInstanceLevelAspect aw_instance) { if (aw_instance == null) { return; } aw_instance.aw$getAspect(getClass()); } /** * Creates the generic AspectDefinition for the PerObjectAspect * * @param systemDefinition * @param aspectDefinition * @return definition for the perObjectAspect for the given perX aspect */ public static AspectDefinition getAspectDefinition(SystemDefinition systemDefinition, AspectDefinition aspectDefinition) { DeploymentModel.PointcutControlledDeploymentModel deploymentModel = (DeploymentModel.PointcutControlledDeploymentModel)aspectDefinition.getDeploymentModel(); AspectDefinition perXSystemAspectDef = new AspectDefinition( getAspectName(aspectDefinition.getQualifiedName(), deploymentModel), PEROBJECT_CLASSINFO, systemDefinition); perXSystemAspectDef.setDeploymentModel(DeploymentModel.PER_JVM); perXSystemAspectDef.addParameter(PerObjectAspect.ASPECT_QNAME_PARAM, aspectDefinition.getQualifiedName()); perXSystemAspectDef.addParameter(PerObjectAspect.CONTAINER_CLASSNAME_PARAM, aspectDefinition.getContainerClassName()); ExpressionInfo expressionInfo = createExpressionInfo(deploymentModel, aspectDefinition.getQualifiedName(), PEROBJECT_CLASSINFO.getClassLoader() ); perXSystemAspectDef.addBeforeAdviceDefinition( new AdviceDefinition( PerObjectAspect.ADVICE_SIGNATURE, AdviceType.BEFORE, null, perXSystemAspectDef.getName(), PEROBJECT_ASPECT_NAME, expressionInfo, BEFORE_ADVICE_METHOD_INFO, perXSystemAspectDef ) ); return perXSystemAspectDef; } /** * Naming strategy depends on the perX(X) X pointcut. * One definition is created per perX X pointcut hashcode, thus perthis(X) and pertarget(X) * are sharing the same system aspect perObjectAspect definition. * Note: depends on perX aspect Qname to support pointcut references of the same name in 2 different aspect. * * @param perXAspectQName Qname of the perX deployed aspect * @param deploymentModel * @return */ private static String getAspectName(String perXAspectQName, DeploymentModel.PointcutControlledDeploymentModel deploymentModel) { return PEROBJECT_ASPECT_NAME + '_' + perXAspectQName.hashCode() + '_' + deploymentModel.hashCode(); } /** * Create the expression info where to bind the perObjectAspect for the given perX model * * @param deployModel * @param qualifiedName of the perX Aspect * @param cl * @return */ public static ExpressionInfo createExpressionInfo(final DeploymentModel.PointcutControlledDeploymentModel deployModel, final String qualifiedName, final ClassLoader cl) { ExpressionInfo expressionInfo = new ExpressionInfo(deployModel.getDeploymentExpression(), qualifiedName); expressionInfo.addArgument(PerObjectAspect.ADVICE_ARGUMENT_NAME, PerObjectAspect.ADVICE_ARGUMENT_TYPE, cl); return expressionInfo; } }