Here are some simple examples to get you going with the Model 2 - Self defined Aspects approach.
All examples together with ready to execute tests are to be found in the
source distribution under src/samples/examples/attribdef
. They are
all defined using the same definition file
samples-attribdef.xml
This aspect implements a simple caching service. It caches the results from the method invocations that are picked out by the pointcuts mapped to the advice.
To run the example type: maven aspectwerkz:attribdef:samples:caching
/** * @Aspect perInstance */ public class CachingAspect extends Aspect { // ============ Pointcuts ============ /** * @Call examples.attribdef.caching.*->int examples.attribdef.caching.Pi.getPiDecimal(int) */ Pointcut invocationCount; /** * @Execution int examples.attribdef.caching.Pi.getPiDecimal(int) */ Pointcut methodsToCache; // ============ Advices ============ /** * @Before invocationCount */ public void invocationCounter(final JoinPoint joinPoint) throws Throwable { CallerSideJoinPoint jp = (CallerSideJoinPoint)joinPoint; CacheStatistics.addMethodInvocation( jp.getCalleeMethodName(), jp.getCalleeMethodParameterTypes()); joinPoint.proceed(); } /** * @Around methodsToCache */ public Object cache(final JoinPoint joinPoint) throws Throwable { MethodJoinPoint jp = (MethodJoinPoint)joinPoint; final Long hash = new Long(calculateHash(jp)); final Object cachedResult = m_cache.get(hash); if (cachedResult != null) { System.out.println("using cache"); CacheStatistics.addCacheInvocation(jp.getMethodName(), jp.getParameterTypes()); System.out.println("parameter: timeout = " + ___AW_getParameter("timeout")); return cachedResult; } final Object result = joinPoint.proceed(); m_cache.put(hash, result); return result; } // ============ Utility methods ============ ... protected Map m_cache = new HashMap(); }
This aspect implements a simple logging service. It logs the entry and exit of the methods that are picked out by the pointcuts mapped to the advice. In this simple example we are only using a small subset of all the metadata available from the join point.
To run the example type:
maven aspectwerkz:attribdef:samples:logging
An abstract aspect is provided. By extending the abstract aspect we just need to define the pointcuts to refine the metadata that defines the pointcuts where logging concern has to be bounded. Note that no pointcut needs to be defined in the abstract aspect.
/** * The abstract Aspect * * @Aspect */ public abstract class AbstractLoggingAspect extends Aspect { private int m_level = 0; /** * @Around methodsToLog1 * @Around methodsToLog2 * @Around methodsToLog3 */ public Object logMethod(final JoinPoint joinPoint) throws Throwable { MethodJoinPoint jp = (MethodJoinPoint)joinPoint; indent(); System.out.println("--> " + jp.getTargetClass().getName() + "::" + jp.getMethodName()); m_level++; final Object result = joinPoint.proceed(); m_level--; indent(); System.out.println("<-- " + jp.getTargetClass().getName() + "::" + jp.getMethodName()); return result; } /** * @Before logSet * @Before logGet */ public void logEntry(final JoinPoint joinPoint) throws Throwable { FieldJoinPoint jp = (FieldJoinPoint)joinPoint; System.out.println("ENTER: " + jp.getTargetClass().getName() + "::" + jp.getFieldName()); } /** * @After logSet * @After logGet */ public void logExit(final JoinPoint joinPoint) throws Throwable { FieldJoinPoint jp = (FieldJoinPoint)joinPoint; System.out.println("EXIT: " + jp.getTargetClass().getName() + "::" + jp.getFieldName()); } } /** * The concrete Aspect just defines the pointcut following the naming convention * the absract Aspect has defined. * * @Aspect perJVM name=LoggingAspect */ public class LoggingAspect extends AbstractLoggingAspect { // ============ Pointcuts ============ /** * @Execution * examples.attribdef.logging.Target.toLog1(..) */ Pointcut methodsToLog1; /** * @Execution * examples.attribdef.logging.Target.toLog2(..) */ Pointcut methodsToLog2; /** * @Execution * examples.attribdef.logging.Target.toLog3(..) */ Pointcut methodsToLog3; /** * @Get int examples.attribdef.logging.Target.m_* */ Pointcut logGet; /** * @Set int examples.attribdef.logging.Target.m_* */ Pointcut logSet; }
This example shows both how an Mixin/Introduction is implemented.
To run the example type:
maven aspectwerkz:attribdef:samples:introduction
The example makes use of mixin inheritance within aspect
inheritance. Moreover, the concrete aspect hides the introduced interface by using
the implicit interface lookup (introduced interface are looked for in the mixin
implementation hierarchy).
You can also note the deployment models. The mixin is perInstance whereas the aspect is perClass,
thus you have to call the right methods to retrieve the target instance (since there is none attached to the aspect).
Note: if you add more than one Introduction
to a class
then you have to make sure that the names of the methods
do not collide.
/** * @Aspect perClass */ public class IntroductionAspect extends AbstractIntroductionAspect { /** * Here we have an anonymous pointcut instead of using [AT]Class metadata at Pointcut fields level. * * @Introduce examples.attribdef.introduction.Target deploymentModel=perInstance */ public class MyConcreteImpl extends MyImpl { public String sayHello2() { System.out.println("aspect target class: " + ___AW_getTargetClass()); System.out.println("aspect target instance: " + ___AW_getTargetInstance()); System.out.println("mixin target class: " + ___AW_getMixinTargetClass(this.getClass().getName(), this)); System.out.println("mixin target instance: " + ___AW_getMixinTargetInstance(this.getClass().getName(), this)); return "Hello World! Hello World!"; } } } }
Now you will be able to invoke your Introduction
like this:
public class Target { ... System.out.println("The mixin says: " + ((Mixin)this).sayHello2()); ... }
This example shows how control flow (cflow) pointcuts are implemented.
To run the example type:
maven aspectwerkz:attribdef:samples:cflow
In this example we have two methods step1
and step2
in which step1
calls step2
.
The advices at the step2 @Execution
pointcut will only be triggered if we are in the
control flow of the @cflow
pointcut called cflowPointcut, e.g. the
method step1
. Otherwise the advice should be skipped.
Note the &&
expression to express the cflow algebraic.
/** * @Aspect */ public class CFlowAspect extends Aspect { /** * @CFlow void examples.attribdef.cflow.Target.step1() */ Pointcut cflowPointcut; /** * @Execution void examples.attribdef.cflow.Target.step2() */ Pointcut methodsToLog; /** * @Around cflowPointcut && methodsToLog */ public Object logMethod(final JoinPoint joinPoint) throws Throwable { Object result = joinPoint.proceed(); System.out.println(" --> invoking advice triggered by step2"); return result; } } }
This example shows how exceptions throwned out of a method can be intercepted with
@Throws
pointcut.
To run the example type:
maven aspectwerkz:attribdef:samples:exception
/** * @Aspect */ public class CFlowAspect extends Aspect { /** * @CFlow void examples.attribdef.cflow.Target.step1() */ Pointcut cflowPointcut; /** * @Execution void examples.attribdef.cflow.Target.step2() */ Pointcut methodsToLog; /** * @Around methodsToLog IN cflowPointcut */ public Object logMethod(final JoinPoint joinPoint) throws Throwable { Object result = joinPoint.proceed(); System.out.println(" --> invoking advice triggered by step2"); return result; } }
Here is the XML definition file for the aspect examples above.
<!DOCTYPE aspectwerkz PUBLIC "-//AspectWerkz//DTD//EN" "http://aspectwerkz.codehaus.org/dtd/aspectwerkz.dtd"> <aspectwerkz> <system id="samples-attribdef"> <package name="examples.attribdef"> <use-aspect class="caching.CachingAspect"> <param name="timeout" value="10"/> </use-aspect> <use-aspect class="logging.LoggingAspect"/> <use-aspect class="introduction.IntroductionAspect"/> <use-aspect class="cflow.CFlowAspect"/> <use-aspect class="exception.ExceptionHandlingAspect"/> </package> </system> </aspectwerkz>