Aspect-Oriented Programming & AspectJ
by William Grosso

Listing One
/* Pulls out calls to any public method that throws a RemoteException */
    pointcut example1(): call(public * * (..) throws RemoteException);

/* Pulls out calls to a constructor of any subclass of UnicastRemoteObject. 
The '+' indicates any subclass.  */
    pointcut example2(): call(UnicastRemoteObject+.new(..));

/* Pulls out executions of public methods of classes in any package below 
com.wgrosso (including classes in com.wgrosso). The '..' is what indicates 
any subpackage. */
    pointcut example3(): execution(public * com.wgrosso..*.*(..));

/* Pulls out executions of public methods of classes in any package below 
com.wgrosso (including classes in com.wgrosso). The methods have to 
be "setter" methods and return void */
    pointcut example4(): execution(public void com.wgrosso..*.set*(..));

    
Listing Two
/* The call pointcut isn't applicable, because stringWrapper is declared to 
be of type Object (which does not match the signature). Because StringWrapper 
is in the package com.wgrosso, the execution pointcut does apply.  */
    pointcut callExample(): call(* com.wgrosso..*.*(..));
    pointcut executionExample(): execution(* com.wgrosso..*.*(..));

/* The code */
    public static void main(String[] args) {
        if ((null==args) || (0==args.length)) {
            System.out.println("No arguments");
        }
        else {
            System.out.println("Arguments:\n");
            for (int i=0; i < args.length; i++) {
                Object stringWrapper = new StringWrapper(args[i]);
                System.out.println("\t" + stringWrapper.toString() + "\n");
            }
        }
    }


Listing Three
/* The call pointcut isn't applicable, because stringWrapper is declared to 
be of type Object (which does not match the signature). Because StringWrapper 
is in the package com.wgrosso, the execution pointcut does apply.  */
    pointcut callExample(): call(* com.wgrosso..*.*(..));
    pointcut executionExample(): execution(* com.wgrosso..*.*(..));

/* The code */
    public static void main(String[] args) {
        if ((null==args) || (0==args.length)) {
            System.out.println("No arguments");
        }
        else {
            System.out.println("Arguments:\n");
            for (int i=0; i < args.length; i++) {
                Object stringWrapper = new StringWrapper(args[i]);
                System.out.println("\t" + stringWrapper.toString() + "\n");
            }
        }
    }


Listing Four
/* enteringFromExternalSource picks out join points which are involve public 
methods and are not in the cflowbelow of a public method invocation. You 
need to use && and ! to define this pointcut. */
    pointcut comWGrossoPulicMethods():
        call(public * com.wgrosso..*.*(..));
    pointcut enteringFromExternalSource():
        comWGrossoPulicMethods() &&
        !cflowbelow(comWGrossoPulicMethods());


Listing Five
/*  The entire aspect. */
package com.wgrosso.ddjarticle1;
import org.aspectj.lang.*;
public aspect Aspect_PrintThree {
    pointcut CallStringWrapper(): call(* com.wgrosso..*.*(..));
    pointcut ExecuteStringWrapper(): execution(* com.wgrosso..*.*(..));
    before(): CallStringWrapper() {
        System.out.println("1");
    }
    before(): ExecuteStringWrapper() {
        System.out.println("2");
    }
    after(): ExecuteStringWrapper() {
        System.out.println("4");
    }
    after(): CallStringWrapper() {
        System.out.println("5");
    }
}
/* The entire class */
package com.wgrosso.ddjarticle1;
public class PrintThree {
    public static void main(String[] args) {
        System.out.println("3");    
    }
}

Listing Six
/* We still need to define a pointcut */
    pointcut callExample(): call(public void com.wgrosso..*.*(..));

/* Around advice must call proceed in order for the  original method 
invocation to occur. Note that around advice needs a return type that 
matches the pointcut. */
    void around(): callExample() {
        /* Any code before the proceed executes before the method body. */
        proceed(); // proceed executes the method body
        /*  Any code after the proceed executes after the method body.*/
   }

Listing Seven
package aspects.wgrosso.ddjarticle1;
import org.aspectj.lang.*;
import java.lang.ref.*;
import java.rmi.*;
import java.rmi.server.*;
import java.util.*;

/* Aspect_ObjectTracking. An example of how to use aspects to implement 
additional debugging in your system. This uses a simple RMI server to 
vend the counts. */
public aspect Aspect_ObjectTracking {

/* Constructor signatures don't have a return type. */
    pointcut allConstructors(): execution(com.wgrosso..*.new(..));

/* Called after constructor is finished, but before we return out of the
constructor. We use the canonical variable thisJoinPoint to figure out 
what object we're in.  */
    after(): allConstructors() {
        Object newlyCreatedObject = thisJoinPoint.getThis();
        objectWasCreated(newlyCreatedObject);
    }

/* We need to instance variables and state in this aspect, to implement our 
memory tracker. Aspect definitions are a lot like class definitions (but 
there is only 1 instance of the aspect at runtime). Thus, aspects can have 
state (and constructors which initialize their state).   */
    private HashMap _classNamesToWeakHashMapOfInstances = new HashMap();
    private Object DUMMY_ENTRY = new Object();
    private static long TWO_MINUTES = 2 * 60 * 1000;
    private static long MEM_PRINTING_DELAY = TWO_MINUTES;

    public Aspect_ObjectTracking() {
        (new Thread(new BackgroundInstanceCountPrinter())).start(); 
   }
    private synchronized void objectWasCreated(Object object) {
        String className = object.getClass().getName();
        /* We use weak hashmaps to avoid memory leaks (weak hashmaps are 
           automatically cleaned up when objects are garbage collected). */
        WeakHashMap instances = 
            (WeakHashMap) _classNamesToWeakHashMapOfInstances.get(className);
        if (null==instances) {
            instances = new WeakHashMap();  
            _classNamesToWeakHashMapOfInstances.put(className, instances);  
            instances.put(object, DUMMY_ENTRY); 
        }
        else {
            /* We need to worry about possibility that one constructor calls 
              another one within same class. That's what this check is for. */
            if (!instances.containsKey(object)) {
                instances.put(object, DUMMY_ENTRY); 
            }
        }
    }
    private synchronized int getNumberOfInstances(String className) {
        WeakHashMap instances = (WeakHashMap) _classNamesToWeakHashMapOfInstances.get(className);
        if (null==instances) {
            return 0;
        }
        return instances.size();
    }
    private synchronized void printOutInstanceCountInformation() {
        Iterator i = _classNamesToWeakHashMapOfInstances.keySet().iterator();
        while(i.hasNext()) {
            String nextClassName = (String) i.next();
            int numberOfInstances = getNumberOfInstances(nextClassName);
            if (numberOfInstances > 0) {
                System.out.println(nextClassName + ": " + numberOfInstances);
            }
        }
    }
    private class CountServer extends UnicastRemoteObject 
                                                   implements ClassCounter {
        public CountServer() throws RemoteException {
            super(STANDARD_PORT);
        }
        public int getNumberOfInstances(String className) throws 
                                                    RemoteException{
            return getNumberOfInstances(className);
        }
    }
    private class BackgroundInstanceCountPrinter implements Runnable {
        public void run() {
           while(true) {
                try {
                    Thread.sleep(MEM_PRINTING_DELAY);
                }
                catch (Exception ignored) {}
                printOutInstanceCountInformation(); 
            }
        }
    }
}

Listing Eight
package com.wgrosso.rmi;

import java.rmi.*;
import java.rmi.server.*;
import org.aspectj.lang.*;

/* Logs all calls that come into a method that throws a remote exception. Uses
target pointcut type to make sure target is instance of UnicastRemoteObject */
public aspect Aspect_LogRemoteMethodCalls {
    pointcut potentiallyRemoteMethodCall():
        target(UnicastRemoteObject) &&
        call(public * * (..) throws RemoteException);
    pointcut comWGrossoCode():
        execution(public * com.wgrosso..*.*(..));
    pointcut reallyRemoteMethodCall():
        potentiallyRemoteMethodCall () &&
        !cflowbelow(comWGrossoCode());
    before(): reallyRemoteMethodCall() {
        logRemoteCall(thisJoinPoint);
    }
    private void logRemoteCall(JoinPoint joinPoint) {
        try {
            System.out.println("Remote call to " + joinPoint.getTarget());
            System.out.println("\tCaller is " + RemoteServer.getClientHost());
            System.out.println("\tAguments are: " + joinPoint.getArgs());
        }
        catch (Throwable t) {
        /* Just in case. */
            t.printStackTrace();
        }
    }
}






1


