The standard abc release contains several extensions that have been developed by the abc team. This page contains a description of the eaj, tracematch, and open modules extensions.

The source code for these extensions is included with the full abc source code (available from the download page).

eaj

The eaj extension provides some extensions to the AspectJ language. As well as being useful in their own right, they are also there to demonstrate how to extend abc. To compile with these extensions turned on, use the command:

abc -ext abc.eaj.ExtensionInfo [options and source files] (version 0.9.0 or 0.9.1)

abc -ext abc.eaj [options and source files] (later versions)

The source code for eaj is in the sub-directory src/abc/eaj of the standard abc release.

Cast pointcut

The cast pointcut picks out any implicit or explicit casts to a type matching the specified TypePattern. It has the following syntax:

cast ( TypePattern )

For example, suppose you wanted to perform a dynamic check on all casts from int to short to check that there is no information lost (by casting integers that won't fit in a short). The following aspect achieves this:


aspect CastingBoundsCheck
{
    before(int i):
           cast(short) && args(i)
        && if (i < Short.MIN_VALUE || i > Short.MAX_VALUE)
    {
        System.err.println(
            "Warning: loss of information casting " +
            i + " to a short.");
    }
}

Private pointcut variables

When writing pointcuts, and especially named pointcuts, you may want to bind a pointcut variable but not have to parametise the pointcut with it. For example, consider the following pointcut to match calling a certain method with a null argument:


pointcut nullCall(Object o) :    call(* SomeClass.someMethod(..))
                              && args(o) && if(o == null);

Having to to parameterize this pointcut with a variable is pointless: there is nothing useful you can do with the reference in some advice because you know it must be null. With the private pointcut variables extension you can write the pointcut as:


pointcut nullCall() : private(Object o) (   call(* SomeClass.someMethod(..))
                                         && args(o) && if(o == null));

Global pointcut declarations

A global pointcut declaration allows you to conjoin a pointcut with the pointcuts for each advice declaration within aspects matching a ClassnamePattern.

This means is you can protect the implementation of a class from being exposed using aspects:


class HiddenImplementation
{
    global : * : !within(HiddenImplementation);

    .
    .
    .
}

They can also be used to prevent you from having to repetitively include the same text in each advice declaration. For example, when an aspect shouldn't apply to itself you can specify that with one line at the top of the aspect:


aspect DoesNotApplyToSelf
{
    global : DoesNotApplyToSelf : !within(DoesNotApplyToSelf);

    // The following advice would create a non-terminating
    // loop without the global declaration above.
    before() : call(* *(..))
    {
        System.out.println("Entering a method");
    }

    .
    .
    .
}

The syntax for a global pointcut declaration is:

global : ClassnamePattern : Pointcut ;

Tracematches

Normal aspects only intercept one event at a time; tracematches instead allow you to write advice that is triggered by a pattern that ranges over the whole history of the computation.

Here is a tracematch for checking that the vector underlying an enumeration is not changed while the enumeration is in progress. It first declared three symbols: these are the events of interest, and all events that do not match these symbols are ignored. Next follows a regular expression, which singles out the traces of symbols that should trigger advice: here that is the creation of an enumeration, zero or more steps, an update and then one more (erroneous) step. In this case the advice just throws a ConcurrentModificationException.


    tracematch(Vector ds, Enumeration e) {
      sym create_enum after returning(e) :
           call(Enumeration+.new(..)) && args(ds);
      sym call_next before : 
           call(Object Enumeration.nextElement()) && target(e);
      sym update_source after : vector_update()
																             
     create_enum call_next* update_source+ call_next
     {
       throw new ConcurrentModificationException();
     }
    }

Details of the design of this new extension can be found in our OOPSLA 2005 paper.

The tracematch extension has been part of the standard abc release since version 1.1.0. To run the tracematch extension, use the command:

abc -ext abc.tm [options and source files] (from version 1.1.0)

The source code for tracematches is in the sub-directory src/abc/tm of the standard abc release.

The benchmarks used for tracematches are provided here: ( tar.gz , zip )

Open modules

An often heard criticism of aspects is that they break the principle of information hiding. A small change in the underlying base code may cause an aspect to apply wrongly, and thus cause the whole system to fail. Jonathan Aldrich has proposed the concept of Open Modules to specify for groups of classes and aspects what joinpoints are part of the interface (and thus must be maintained by the module's author).

In the technical report Adding Open Modules to AspectJ we show how Aldrich's design may be integrated into the full AspectJ language. Convincing examples of open modules need a substantial system, so we refer you to that report for details.

The open module extension has been included in the standard abc release since version 1.1.0. To run the open modules extension, use the command

abc -ext abc.om [options and source files] (from version 1.1.0)

The source code for the open modules extension is in the sub-directory src/abc/om of the standard abc release.

The main example from the AOSD 2006 paper and the technical report is a simulator for ants tournaments, and the full source code is available here: (tar.gz, zip).