Introduction

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

Caching

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();
}

Logging

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;
}

Introductions and Mixins

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!";
        }
    }
}
}
As you can see neither the interface nor the implementation class needs to implement a certain interface or extend a certain class.

Now you will be able to invoke your Introduction like this:

public class Target {
    ...
    System.out.println("The mixin says: " + ((Mixin)this).sayHello2());
    ...
}

Control flow (cflow) pointcuts

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;
    }
}
}

Exception throwing pointcuts

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;
    }
}
                

XML definition file for the examples

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>