Advices

The Advice class implements the advice concept, i.e. defines code that is executed when a join point is reached.

Implementation

There are currently four types of Advices supported:

  • AroundAdvice - is invoked "around" the join point. Can be used to intercept method invocations.


  • PreAdvice - is invoked before the join point. Can be used for advising fields or caller side pointcuts.


  • PostAdvice - is invoked after the join point. Can be used for advising fields or caller side pointcuts.


  • ThrowsAdvice - advises join points where an exception is thrown out of a method.

AroundAdvice

An AroundAdvice is implemented by extending the AroundAdvice class and implementing the abstract method Object execute(final JoinPoint jp) .

Please note: An AroundAdvice can not be used with caller side or field pointcuts.

Here is a simple example of an AroundAdvice . (For more examples see the Examples section .)

It is in the method execute that the action takes place. The JoinPoint object that is passed to the method contains metadata of the current join point. To invoke the next advice in the chain (or the target method if there are no more advices) simply call joinPoint.proceed() . This method will return the result from the next advice (or the target method).

public class MyAroundAdvice extends AroundAdvice {
    public MyAroundAdvice() {
        super();
    }
    public Object execute(final JoinPoint joinPoint) throws Throwable {
        // do some stuff
        Object result = joinPoint.proceed();
        // do some more stuff
        return result;
    }
}


PreAdvice

A PreAdvice is implemented by extending either the abstract PreAdvice class and implementing the abstract method void execute(final JoinPoint jp) . The PreAdvice class is being executed before the join point (that it has been applied to) has been is reached.

Here is a simple example of a PreAdvice advice. It is in the method execute that you can implement your logic. The JoinPoint object that is passed to the method contains metadata for the current join point. There is no need to call joinPoint.proceed() for either PreAdvices or PostAdvices .

public class MyPreAdvice extends PreAdvice {
    public MyPreAdvice() {
        super();
    }
    public void execute(final JoinPoint joinPoint) throws Throwable {
        // do some stuff
    }
}


PostAdvice

A PostAdvice is implemented by extending either the abstract PostAdvice class and implementing the abstract method void execute(final JoinPoint jp) . The PreAdvice class is being executed before the join point (that it has been applied to) has been is reached.

Here is a simple example of a PostAdvice advice. It is in the method execute that you can implement your logic. The JoinPoint object that is passed to the method contains metadata for the current join point. There is no need to call joinPoint.proceed() for either PreAdvices or PostAdvices .

public class MyPostAdvice extends PostAdvice {
    public MyPostAdvice() {
        super();
    }
    public void execute(final JoinPoint joinPoint) throws Throwable {
        // do some stuff
    }
}


ThrowsAdvice

A ThrowsAdvice is implemented by extending the the ThrowsAdvice class and implementing the abstract method void execute(final JoinPoint jp) . The ThrowsAdvice class is being executed after the join point (that it has been applied to) has been reached. I.e. when a specific exception has been thrown out of a specific method.

Here is a simple example of a ThrowsAdvice advice. It is in the method execute that you can implement your logic. The JoinPoint object that is passed to the method contains metadata of the current join point.

public class MyThrowsAdvice extends ThrowsAdvice {
    public MyThrowsAdvice() {
        super();
    }
    public void execute(final JoinPoint joinPoint) throws Throwable {
        Throwable cause = ((ThrowsJoinPoint)joinPoint).getException());
        // do some stuff
    }
}

Definition

Attributes

When defining the advices there are three attributes that needs to be specified:

  • name - for each advice you first have define the name of the advice. This name has to be unique and will work as a handle to the advice to be used when referencing the advice in the system.


  • advice - secondly you have to define the class name of the advice that the name attribute should be mapped to.


  • deployment-model - last we have an optional attribute specifying the deployment model to use. If no deployment model is defined the default perJVM (singleton) will be used. (For more information about the deployment model types available see the Deployment models section ).


Here you also have the possibility to pass parameters to the advices. See the Passing parameters to advices section for a detailed description.

XML definition

<advice-def name="advices/caching"
            class="advices.CachingAdvice"
            deployment-model="perInstance">
    <param name="timeout" value="10"/>
</advice>

Introductions

The Introduction class implements the concept of Mixins/Open Classes. I.e. an Introduction makes it possible to extend a class with a new interface and/or a new implementation (methods and fields).

Implementation

Both the interface and the implementation extensions are just regular Java interfaces and classes. There is no need to have them implement a specific interface or extend a certain class. All you have to do is define them. The only rules are that the introduced implementation has to implement the introduced interface and have a default no-argument constructor.

When defining an interface introduction you only have to specify the interface, but when introducing a new implementation to a class, you must specifiy both the implementation class a matching interface. This is needed since if you don't specify an interface that the client can cast the target obje ct to, the introduced implementation will not be accessible.

Note: if you add more than one Introduction to a target class then you have to make shure that the names of the methods does not collide (or you will get strange results).

Definition

Attributes

When defining the introductions there are four attributes that needs to be specified:

  • name - each introduction needs to have a unique name that will work as a handle to the advice to be used when referencing the introduction in the system.


  • interface - this attribute specifies the full name of the interface class to use.


  • implementation - this attribute specifies the full name of the implementation class to use. (Is skipped when we are defining an interface introduction).


  • deployment-model - is an optional attribute specifying the deployment model to use. If no deployment model is defined the default perJVM (singleton) will be used. (For more information about the deployment model types available see the Deployment models section ).

XML definition

<introduction-def name="java/io/Serializable"
                  interface="java.io.Serializable"/>

<introduction-def name="mixins/Mixin"
                  interface="mixins.Mixin"
                  implementation="mixins.MixinImpl"
                  deployment-model="perThread"/>

(These examples only shows how to define the Introduction , for examples how to add them see the Aspects section .)

Pointcuts

The Pointcut class implements the pointcut concept. Pointcuts selects join points and values at those points, i.e. selects well-defined points in the program flow.

Implementation

There are currently four different types of pointcuts supported:

  • MethodPointcut - picks out join points defining method execution. Valid advice for this pointcut is AroundAdvice .


  • FieldPointcut - picks out join points defining field access or modification. Valid advices for this pointcut are PreAdvice and PostAdvice .


  • ThrowsPointcut - picks out join points definining where an exception is thrown out of a method. Valid advice for this pointcut is ThrowsAdvice .


  • CallerSidePointcut - picks out join points defining method invocation on the caller side. Valid advices for this pointcut are PreAdvice and PostAdvice .


  • CFlowPointcut - picks out join points defining a control flow (cflow). This pointcut can only be used on conjunction with other pointcuts.

Definition

Attributes

When defining the pointcuts there are three attributes that needs to be specified:

  • name - specifies the name of the pointcut. Needs to be a unique name throughout the aspect definintion.

    Caution: names must only consist of these characters: [A-Z ] , [a-z ] , [0-9 ] and the characters $ and _ (not for example - or / ).


  • type - specifies the type of the pointcut. Valid types are (all lowercase is also valid):
    • method
    • setField
    • getField
    • throws
    • callerSide
    • cflow


  • pattern - specifies the pattern for the pointcut. This is the pattern that picks out the join points that should be included in the pointcut.

    For the ThrowsPointcut the pattern is defined like this: methodPattern#fullyQualifiedNameOfException .

    For the CallerSidePointcut the pattern is defined like this: callerSideClassPattern->calleeSideMethodPattern .

    See the Join point selection pattern language section for a detailed description on how these patterns work and are used. `


XML definition

<aspect ...>
    <pointcut-def name="pc1" type="method" pattern="* foo.Bar.method(..)"/>
    <pointcut-def name="pc2" type="setField" pattern="* foo.Bar.m_field"/>
    <pointcut-def name="pc3" type="throws" pattern="* foo.Bar.method(..)#java.lang.Exception"/>
    <pointcut-def name="pc4" type="callerSide" pattern="foo.Caller->String foo.Callee.method()"/>
    <pointcut-def name="pc5" type="cflow" pattern="* Transaction.begin(..)"/>
    ...
</aspect>

Aspects

The Aspect class implements the aspect concept. Aspects are AspectWerkz's unit of modularity for crosscutting concerns. They are defined in terms of pointcuts, advices and introductions.

Definition

Abstract aspects - aspect inheritance

You have the possibility of defining abstract aspects that you can reuse by letting aspects inherit the the abstract aspect using the extends attribute. Aspect inheritance works pretty much like regular class in heritance. An abstract aspect is defined using the abstract-aspect element.

Attributes

When defining the aspects there is first one attribute that needs to be specified:

  • name - specifies a unique name for the aspect.


  • extends - specifies the abstract aspect that the aspect extends (optional).


Adding the pointcuts definitions

In the aspect definition you put the pointcut definitions (see the Pointcuts section ).

Adding the introductions

Then you specify the introductions that you want to define in this aspect . This is done using the introduction element. You can also use the element introduce if you find it more intuitive.

This element has an attribute class where you define the pattern for the classes that you want to be applied by this/these introductions. Within this element you define the references to the introductions. Using the introduction-ref element: < introduction-ref name="nameOfIntroduction"/ >

Adding the advices

You also define which advices should be applied to which pointcuts. This is done using the advice element. You can also use the element advise if you find it more intuitive.

The advice element has an attribute called expression ( pointcut works fine as well) in which you can define an expression based on the names of the pointcuts you have defined for this aspect.

This expression can be any (almost) kind of algebraic expression. The only difference is that you have to use OR instead of || and AND instead of & & (lowercase works fine as well). AND is needed because it is cumbersome to write & & in XML (needs to be escaped) and OR is used to make it coherent;

Here you also define if the pointcut/expression should be a part of a control flow using the cflow attribute. The cflow is defined using its pointcut name.

XML definition

<abstract-aspect name="MyAbstractAspect">
    <advice cflow="facadeCalls" pointcut="setters AND !getters">
        <advices-ref name="log_and_cache"/>
    </advice>

    <advice pointcut="persistentFields">
        <advice-ref name="persistent"/>
    </advice>
</aspect>

<aspect name="MyAspect" extends="MyAbstractAspect">
    <introduction class="domain.*">
        <introduction-ref name="serializable"/>
        <introduction-ref name="mixin"/>
    </introduction>

    <pointcut-def name="facadeCalls" type="cflow" pattern="* *..facade.*.*(..)"/>
    <pointcut-def name="setters" type="method" pattern="String domain.*.set*(..)"/>
    <pointcut-def name="getters" type="method" pattern="String domain.*.get*(..)"/>
    <pointcut-def name="persistentFields" type="setField" pattern="* domain.*.*">
</aspect>

Join points

The JoinPoint class implements the join point concept, i.e. a well-defined point in the program flow. A JoinPoint is picked out by a Pointcut .

Implementation

There are four different types of join points:

  • MethodJoinPoint


  • FieldJoinPoint


  • ThrowsJoinPoint


  • CallerSideJoinPoint

You only have to deal with the different types of join points when you in your Advice need to cast the JoinPoint object to a specific type to be able to retrieve meta-data from this specific join point. See the JavaDoc for more information on what information is available.