AspectWerkz - Plain Java AOP

##### General Information

- Overview
- Features
- License
- Downloads

##### Documentation

- New features in 2.x
- Introduction
- Tutorials
- Implementation issues
- General definition issues
- Annotation definition
- XML definition
- Annnotation driven development
- Deployment
- Weaving
- Dynamic AOP
- AOP container extensions
- Examples
- IDE integration
- JavaDoc
- FAQ

##### Misc.

- Releases & Release notes
- Build & install
- CVS access
- Mailing lists
- Tasks
- Papers, articles & talks

##### Project Documentation

- About AspectWerkz - Plain Java AOP
- Project Info
- Project Reports
- Development Process

## Table of Contents

1. Introduction
2. Call and Execution pointcuts + Around advice
3. Set and Get pointcuts + Aspect inheritance
4. Implementation introductions
5. Control flow (cflow) pointcuts
6. Handler pointcuts (catch clauses)
7. Annotation driven AOP (matching on Annotations)
8. Java 5 Annotations
9. XML definition file for the examples

## Introduction

Here are some simple examples to get you going. All examples together with ready to execute tests are to be found in the source distribution under `src/samples/examples`. They are all defined using the same definition file `aop.xml`

## Call and Execution pointcuts + Around advice

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: `ant samples:caching`

     /**

      * @Aspect perInstance

      */

     public class CachingAspect {

        /**

         * The cross-cutting info.

         */

        private final CrossCuttingInfo m_info;

        /**

         * We are interested in cross-cutting info, therefore we have added a constructor that takes a cross-cutting info

         * instance as its only parameter.

         *

         * @param info the cross-cutting info

         */

        public CachingAspect(final CrossCuttingInfo info) {

            m_info = info;

        }

        /**

         * @Before call(int examples.caching.Pi.getPiDecimal(int)) &&

         *         withincode(int examples.caching.main(String[]))

         */

         public void invocationCounter(final JoinPoint joinPoint) throws Throwable {

             MethodSignature signature = (MethodSignature)joinPoint.getSignature();

             CacheStatistics.addMethodInvocation(

                     signature.getName(),

                     signature.getParameterTypes()

             );

         }

         /**

          * @Around execution(int examples.caching.Pi.getPiDecimal(int))

          */

         public Object cache(final JoinPoint joinPoint) throws Throwable {

            MethodRtti rtti = (MethodRtti)joinPoint.getRtti();

            final Long hash = new Long(calculateHash(rtti));

            final Object cachedResult = m_cache.get(hash);

            if (cachedResult != null) {

                System.out.println("using cache");

                CacheStatistics.addCacheInvocation(rtti.getName(), rtti.getParameterTypes());

                System.out.println("parameter: timeout = " + m_info.getParameter("timeout"));

                return cachedResult;

            }

            final Object result = joinPoint.proceed();

            m_cache.put(hash, result);

            return result;

         }

        // ============ Utility methods ============

        ...

        protected Map m_cache = new HashMap();

    }

## Set and Get pointcuts + Aspect inheritance

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: `ant samples:logging` It is possible to run this sample using offline weaving thru `ant samples:offline: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.

    public abstract class AbstractLoggingAspect {

        private int m_level = 0;

        /**

         * @Around methodsToLog1 || methodsToLog2 || methodsToLog3

         */

        public Object logMethod(final JoinPoint joinPoint) throws Throwable {

            MemberSignature signature = (MemberSignature)joinPoint.getSignature();

            indent();

            System.out.println("--> " + joinPoint.getTargetClass().getName() + "::" + signature.getName());

            m_level++;

            final Object result = joinPoint.proceed();

            m_level--;

            indent();

            System.out.println("<-- " + joinPoint.getTargetClass().getName() + "::" + signature.getName());

            return result;

        }

        /**

         * @Before logSet || logGet

         */

        public void logEntry(final JoinPoint joinPoint) throws Throwable {

            MemberSignature signature = (MemberSignature)joinPoint.getSignature();

            System.out.println("ENTER: " + joinPoint.getTargetClass().getName() + "::" + signature.getName());

        }

        /**

         * @After logSet || logGet

         */

        public void logExit(final JoinPoint joinPoint) throws Throwable {

            MemberSignature signature = (MemberSignature)joinPoint.getSignature();

            System.out.println("EXIT: " + joinPoint.getTargetClass().getName() + "::" + signature.getName());

        }

        private void indent() {

            for (int i = 0; i < m_level; i++) {

                System.out.print("  ");

            }

        }

    }

    /**

     * The concrete Aspect just defines the pointcut following the naming convention

     * the abstract Aspect has defined.

     */

    public class LoggingAspect extends AbstractLoggingAspect {

        // ============ Pointcuts ============

        /**

         * @Expression execution(* examples.logging.Target.toLog1(..))

         */

        Pointcut methodsToLog1;

        /**

         * @Expression execution(* examples.logging.Target.toLog2(..))

         */

        Pointcut methodsToLog2;

        /**

         * @Expression execution(* examples.logging.Target.toLog3(..))

         */

        Pointcut methodsToLog3;

        /**

         * @Expression get(int examples.logging.Target.m_*)

         */

        Pointcut logGet;

        /**

         * @Expression set(int examples.logging.Target.m_*)

         */

        Pointcut logSet;

    }

## Implementation introductions

This example shows both how implementation introductions (Mixins) are implemented.

To run the example type: `ant 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.

    public abstract class AbstractIntroductionAspect {

        /**

         * The Introduce doclet is not necessary here. This aspect provides a half completed mixin impl (abstract one)

         */

        public static abstract class MyImpl implements Mixin {

            public String sayHello1() {

                return "Hello World!";

            }

        }

    }

    public class IntroductionAspect extends AbstractIntroductionAspect {

        /**

         * @Mixin(pointcut="within(examples.introduction.Target)",

         *        deploymentModel="perInstance")

         */

        public static class MyConcreteImpl extends MyImpl {

            /**

             * The cross-cutting info.

             */

            private final CrossCuttingInfo m_info;

            /**

             * We are interested in cross-cutting info, therefore we have added a constructor that takes a cross-cutting infor

             * instance as its only parameter.

             *

             * @param info the cross-cutting info

             */

            public MyConcreteImpl(final CrossCuttingInfo info) {

                m_info = info;

            }

            public String sayHello2() {

                System.out.println("mixin target class: " + m_info.getMixinTargetClass(this));

                System.out.println("mixin target instance: " + m_info.getMixinTargetInstance(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: `ant 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.

    public class CFlowAspect {

        /**
         * @Around cflow(call(void examples.cflow.Target.step1())) && execution(void examples.cflow.Target.step2())
         */
        public Object logMethod(final JoinPoint joinPoint) throws Throwable {
            Object result = joinPoint.proceed();
            System.out.println("  - invoking advice triggered by step2");
            return result;
        }
    }

## Handler pointcuts

This example shows how catch clauses be intercepted with `@Handler` pointcut.

To run the example type: `ant samples:exception`

    public class ExceptionHandler {

        /**
         * @Before handler(java.lang.Exception+) &&
         *         withincode(public static void examples.exception.Target.main(String[]))
         */
        public void handleException(final JoinPoint joinPoint) throws Throwable {
            // handle the exception
            CatchClauseRtti rtti = (CatchClauseRtti)joinPoint.getRtti();
            Exception e = (Exception)rtti.getParameterValue();
            ...
        }
    }

## Annotation driven AOP

This examples shows Annotation driven AOP - that is matching on Annotations. The current samples relies on the provided Java 1.4 strongly typed annotations framework but the same concepts can easily be applied for Java 5 Annotations (as supported in AspectWerkz 2.0).

To run the example type: `and samples:annotation` or `ant samples:offline:annotation` to see it running using post compilation (offline weaving instead of load time weaving).

What do we want to achieve ?
We want to apply advices on method not based on their name or signature but based on the annotations. Given the following sample class, we would like to apply an advice for all methods annotated with `@examples.annotation.AnnotationA` and another advice for all methods annotated with bot `@examples.annotation.AnnotationA` and `@examples.annotation.AnnotationB`:

    public class Target {

        /**

         * @examples.annotation.AnnotationA

         * @examples.annotation.AnnotationB

         */

        public void targetAB() {

            System.out.println("Target.target AB ");

        }

        /**

         * @examples.annotation.AnnotationA

         */

        public void targetA() {

            System.out.println("Target.target A");

        }

        public void target() {

            System.out.println("Target.target");

        }

    }

Annotation handling for Java 1.4
Since we are using Java 1.4 in this sample, the annotations appears in JavaDoc. Nevertheless, AspectWerkz provides a way to treat those annotation as in Java 5 and have runtime access to them thru a strongly typed API (read here). In this sample, the annotations do not have any particular values. We will then use untyped annotations. We first need to run the `AnnotationC` compiler so that those Annotations gets self-embedded in the compiled class `.class` file. Before doing so, we need to write our property file to say to the system what are the annotations used (and distinguished those from `@author` for example, that we don't want at runtime (similar to the retention policy in Java 5).

    #

    # annotation.properties file

    #

    # examples.annotation are untyped, we don't need a proxy

    examples.annotation.AnnotationA

    examples.annotation.AnnotationB

Invoke AnnotationC with Ant or programmatically at your convenience. Notice the `-custom ...annotation.properties` argument to point to the annotation properties file.

    <target name="samples:annotationc">

        <java fork="true" classname="org.codehaus.aspectwerkz.annotation.AnnotationC">

            <classpath>

                <path refid="project.class.path"/>

                <pathelement path="${samples.classes}"/>

            </classpath>

            <arg line="-verbose -src ${basedir}/src/samples -classes ${basedir}/target/samples-classes -custom ${basedir}/src/samples/annotation.properties"/>

        </java>

    </target>

Aspect that match on those annotations Now we need to write our pointcuts and advice that match on those annotations. The syntax is straightforward:

    public static class AnnotationMatchAspect {

        /**

         * @Before execution(@examples.annotation.AnnotationA * examples.annotation.Target.*(..))

         * @param jp

         */

        public void beforeA(JoinPoint jp) {

            System.out.println("Target$AnnotationMatchAspect.beforeA");

        }

        /**

         * @Before execution(@examples.annotation.AnnotationB * examples.annotation.Target.*(..))

         * @param jp

         */

        public void beforeB(JoinPoint jp) {

            System.out.println("Target$AnnotationMatchAspect.beforeB");

        }

    }

Running the sample
Since we are using an annotation defined aspect, we need to run `AnnotationC` on the aspect class itself to take care of the `@Before` and alike AspectWerkz provided annotations.
It is possible to run AnnotationC once on both the aspect(s) and the target application classes. Then we need to write our little `aop.xml` file to tell the framework which aspect to use. We could redefine or define new pointcuts in this XML as well (see here)
For your convenience, everything is wrapped thru an ant target.
Run `ant samples:annotation`

What about offline mode ?
If we wanted to use offline mode, the process would be the same: AnnotationC on both the aspect(s) [if needed] and the target application classes, then invoke the `AspectWerkzC` post compiler, and then run your class as usual, passing the aop.xml file.
Run `ant samples:offline:annotation`

## Java 5 Annotations

A sample with Java 5 Annotations defined aspects can be run from `ant samples:jdk5:callback`. For it to work you will need to define `ASPECTWERKZ_HOME` as for others samples, and have the JDK 5 environment set up as your default java.

The source code for this sample is in `src/jdk15/samples/examples/callback` and illustrates how to define an Aspect using Java 5 annotations.

## XML definition file for the examples

Here is the XML deployment descriptor file for the aspect examples above.

    <!DOCTYPE aspectwerkz PUBLIC

        "-//AspectWerkz//DTD//EN"

        "http://aspectwerkz.codehaus.org/dtd/aspectwerkz2.dtd">

    <aspectwerkz>

        <system id="samples">

            <package name="examples">

                <aspect class="caching.CachingAspect">

                    <param name="timeout" value="10"/>

                </aspect>

                <aspect class="logging.LoggingAspect"/>

                <aspect class="introduction.IntroductionAspect"/>

                <aspect class="cflow.CFlowAspect"/>

                <aspect class="exception.ExceptionHandlingAspect"/>

                <aspect class="annotation.Target$AnnotationMatchAspect"/>

            </package>

        </system>

    </aspectwerkz>