ARJ: Extending AspectJ with Aspect Refinement and Mixin-Based Aspect Inheritance


Latest Version 0.2 (Feb 1, 2007)

Tutorial

How to Install

Get the abc-ar and the abc-runtime JAR files from the download section and place them in a directory included in the class path.

To compile abc from source it is necessary to first download and compile soot and polyglot. Afterwards the source from the download section can be compiled using ant. The proceeding is the same as for the abc compiler described on the abc download page.

Simple Example

In this section we build a simple example to show the basic principle of aspect refinement.

We start with a simple Fifo class that provides a get and a put method. The class is put in a subdirectory called "Fifo", but do not use java packages:

import java.util.*;
class Fifo {
  protected Vector buf = new Vector();
  public void put(Item i) {
    System.out.println("Fifo.put(" + i + ")");
    buf.add(i);
  }
  public Item get(int index) {
    Item res = (Item)buf.get(index);
    System.out.println(res + " = Fifo.get(" + index + ")");
    return res;
  }
}

To test this Fifo class we need a small Main class placed in the Main subdirectory:

class Main {
  public static void main(String[] args){
    Fifo fifo = new Fifo();
    fifo.put(new Item(4444));
    fifo.get(0);
  }
}

Then we add a simple aspect to sync the Fifo class with an around advice that matches to the get and put methods. This aspect called FifoSync is placed in the FifoSync-subdirectory:

aspect FifoSync {
  pointcut syncPC() : execution(* Fifo.get(..)) || execution(* Fifo.put(..));
  Object around() : syncPC() {
    lock();
    Object res = proceed();
    unlock();
    return res;
  }
  void lock() {
    System.out.println(featureName() + ".lock()");
  }
  void unlock() {
    System.out.println(featureName() + ".unlock()");
  }
  String featureName(){ return "FifoSync"; }
}

Now we want to extend this aspect, by overriding the lock and unlock methods to add a counter. Using classic AspectJ we would need to declare the FifoSync aspect abstract and create a new one. Instead we declare a refinement that has the same name as the original aspect. The refinement is placed in the sub-directory WaitNotifySync:

refines aspect FifoSync {
  int _count = 0;
  void lock() {
    _count++;
    super.lock();
  }
  void unlock() {
    _count--;
    super.unlock();
  }
  String featureName() { return "WaitNotifySync+" + super.featureName(); }
}

To compile this example we need to specify which features the compiler should use and in which order. Therefore we create a file fifo.equation that specifies the subdirectories in the correct order for the compiler:

Fifo
FifoSync
WaitNotifySync
Main

In this simple example the order of the entries does not matter. In more complex examples with multiple refinements the equation file determines the ordern in which the refinements are applied.

Finally the compiler can be called with java abc.main.Main -ext abc.ar fifo.equation. The compiler weaves in the advice and its refinement so that the output on running the example should look like this:

WaitNotifySync+FifoSync.lock()
Fifo.put(4444)
WaitNotifySync+FifoSync.unlock()
WaitNotifySync+FifoSync.lock()
4444 = Fifo.get(0)
WaitNotifySync+FifoSync.unlock()

Advanced Example

In this advanced example we want to show how to use pointcut refinements and named advice. We therefore extend the previous example with a Stack class that extends the Fifo class in the Stack subdirectory:

class Stack extends Fifo {
  void push(Item i) {
    System.out.println("Stack.push(" + i + ")");
    super.put(i);
  }
  Item pop() {
    Item res = super.get(buf.size() - 1);
    System.out.println(res + " = Stack.pop()");
    return res;
  }
}

We now refine the FifoSync advice to that it also applies to the Stack class and defined in the StackSync subdirectory. We therefore extend the pointcut syncPC. To access the parents pointcut the super keyword is introduced for pointcuts:

refines aspect FifoSync {
  pointcut syncPC() : super.syncPC() ||
      execution(* Stack.pop(..)) || execution(* Stack.push(..));
  String featureName() { return "StackSync+" + super.featureName(); }
}

To show the power of named advice we introduce another aspect Logging. It uses named advice to allow their extention:

aspect Logging {
  pointcut newFifo() : execution(Fifo.new(..));
  after afterNewFifo(Fifo fifo) : newFifo() && this(fifo) {
    System.out.println("after new Fifo: " + fifo);
  }
  // Matching all executions of to toString in Item
  pointcut ItemToString(Item i) : execution(* Item.toString()) && this(i);
  after afterItemToString(Item i) returning(String s) : ItemToString(i) {
    System.out.println("------ Returning string value " + s + " for Item");
  }
  String around aroundItemToString(Item i) : ItemToString(i) {
    System.out.println("before proceed Item.toString()");
    String s = proceed(i);
    System.out.println("after proceed Item.toString() -- result: " + s);
    return s;
  }
}

This aspect can now easily be refined by the ExtendedLogging feature:

refines aspect Logging {
  void afterNewFifo(Fifo fifo) {
    super.afterNewFifo(fifo);
    System.out.println("refined afterNewFifo: " + fifo);
  }
  void afterItemToString(Item i, String s) {
    super.afterItemToString(i,s);
    System.out.println("------ refined Returning string value " + s + " for Item");
  }
  String aroundItemToString(Item i) {
    System.out.println("refined before proceed Item.toString()");
    String s = super.aroundItemToString(i);
    System.out.println("refined after proceed Item.toString() -- result: " + s);
    return s;
  }
}

To test this advanced example we add a new Stack test to the Main class and extend the equation file with the new subdirectories. After compiling the example the Main class should return this output

after new Fifo: Fifo@9cab16
refined afterNewFifo: Fifo@9cab16
after new Fifo: Stack@3e25a5
refined afterNewFifo: Stack@3e25a5
StackSync+WaitNotifySync+FifoSync.lock()
refined before proceed Item.toString()
before proceed Item.toString()
------ Returning string value 4444 for Item
------ refined Returning string value 4444 for Item
after proceed Item.toString() -- result: 4444
refined after proceed Item.toString() -- result: 4444
Fifo.put(4444)
StackSync+WaitNotifySync+FifoSync.unlock()
StackSync+WaitNotifySync+FifoSync.lock()
refined before proceed Item.toString()
before proceed Item.toString()
------ Returning string value 4444 for Item
------ refined Returning string value 4444 for Item
after proceed Item.toString() -- result: 4444
refined after proceed Item.toString() -- result: 4444
4444 = Fifo.get(0)
StackSync+WaitNotifySync+FifoSync.unlock()
StackSync+WaitNotifySync+FifoSync.lock()
refined before proceed Item.toString()
before proceed Item.toString()
------ Returning string value 1111 for Item
------ refined Returning string value 1111 for Item
after proceed Item.toString() -- result: 1111
refined after proceed Item.toString() -- result: 1111
Stack.push(1111)
StackSync+WaitNotifySync+FifoSync.lock()
refined before proceed Item.toString()
before proceed Item.toString()
------ Returning string value 1111 for Item
------ refined Returning string value 1111 for Item
after proceed Item.toString() -- result: 1111
refined after proceed Item.toString() -- result: 1111
Fifo.put(1111)
StackSync+WaitNotifySync+FifoSync.unlock()
StackSync+WaitNotifySync+FifoSync.unlock()
StackSync+WaitNotifySync+FifoSync.lock()
StackSync+WaitNotifySync+FifoSync.lock()
refined before proceed Item.toString()
before proceed Item.toString()
------ Returning string value 1111 for Item
------ refined Returning string value 1111 for Item
after proceed Item.toString() -- result: 1111
refined after proceed Item.toString() -- result: 1111
1111 = Fifo.get(0)
StackSync+WaitNotifySync+FifoSync.unlock()
refined before proceed Item.toString()
before proceed Item.toString()
------ Returning string value 1111 for Item
------ refined Returning string value 1111 for Item
after proceed Item.toString() -- result: 1111
refined after proceed Item.toString() -- result: 1111
1111 = Stack.pop()
StackSync+WaitNotifySync+FifoSync.unlock()