Saturday, August 16, 2008

Starting with AOP/AspectJ


We have been modularizing our applications to achieve what is called as separation of "concerns." We created a security module, logging module, persistence module and many more modules. What were we trying to achieve? Answer is “Separation of Concerns”, but were we able to do so? Answer is NO. Though we created these different modules, we still have to use them together in our code. We still have to invoke the API’s provided by these modules in our client code. Example:

Public void someOperation(, , …){
.. Ensure authorization (user)
.. Ensure Thread Safety
.. Ensure cache is updated
.. Log start of operation
...- > perform the core operation
.. Log end of operation
.. unlock the object
}


This is what we call as code tangling. Secondly, call to the module “Ensure authorization (user)” will be scattered all over the place where we need authorization. So, what is the solution? Dynamic proxy, EJB 3 interceptors or AOP? I guess I don’t have the right answer [we’ll discuss it later], but anyways let us see what AOP has to offer.

AOP is just the methodology and AspecJ is one of its implementations, e.g. Java is one of the implementations of OOP. Also, AspectJ is aspect-oriented extension to Java [every valid java program is a valid AspectJ program.] Weaver is the component which applies the weaving rules to the core business logic to form the final system. This process is called as weaving. So, bottom line is, we create the business core concerns using Java classes, crosscutting concerns using Aspect and finally Weaver [AspectJ compiler in our case] weaves the crosscutting functionality to the core modules and gives the executable which can run on any JVM. UFFF, that was not so easy. It’s not all, we still have to learn the dialect used in this area.



Join Point: It is an identifiable point in the execution of a program, e.g. method call.

Pointcut: is a program construct that selects join points and also collects the context at those points. E.g. a methods call with the methods context, like target object and its arguments. Pointcuts are weaving rules and Join points are the situation satisfying those rules. Example will make it more clear, I know.

Advice: a code to be executed at a join point that has been selected by a Pointcut. It can be executed before, after or around the join point.

Introduction: [we will leave it for a while.] we have to come to the point ASAP, no?

Aspect: is a central unit of AspectJ, as class is the central unit of Java. It contains code that expresses weaving rules, advice, introductions. I think, example is the best way to explain here.

Let’s create the business classes first and then we will apply our crosscutting concerns over it. You will notice that we will not have to change any code in those business classes.


package com.farwaha;

interface Animal {
public void makeSound(String name, String sound);
public void makeSound(String sound);
}
//Animal Type
class Dog implements Animal {
public void makeSound(String name, String sound) {
System.out.println("Name:" + name + ", Sound: " + sound);
}

public void makeSound(String sound) {
System.out.println("Sound: " + sound);
}
}
//main
public class AOPTest {
public static void main(String[] args) {
Animal animal = new Dog();
animal.makeSound("Moti", "GRRRRRR");
animal.makeSound("THIS IS ANIMAL SOUND");
}
}

-----------------------------------OUTPUT----------------------------------------
Name:Moti, Sound: GRRRRRR
Sound: THIS IS ANIMAL SOUND
----------------------------------------------------------------------------------

Now, let’s create a Logging and Greeting aspect. Logging aspect will log execution of each method call to Animal and Greeting aspect will greet the Animal who has name.


package com.farwaha;

aspect LoggerAspect {
pointcut logMessage()
: call (* Animal.makeSound(..));

void around() : logMessage(){
System.out.println("[Log]: ... start");
proceed(); // if I comment out, the method will not even execute
System.out.println("[\\Log]: ... end");
}
}

public aspect GreetingAspect {
pointcut greetAnimal(String name)
: call (* Animal.makeSound(String , String ))
&& args (name, String);

void around(String name) : greetAnimal(name){
proceed("MR. " + name);
}
}


Compile all the files together with AspectJ compiler (ajc) and run it. Below is the output:

-----------------------------OUTPUT----------------------------------
[Log]: ... start
Name:MR. Moti, Sound: GRRRRRR
[\Log]: ... end
[Log]: ... start
Sound: THIS IS ANIMAL SOUND
[\Log]: ... end
----------------------------------------------------------------------


Let me talk about LoggerAspect. This aspects defines pointcut which results in returning join points. Let me explain, by using the below code,

pointcut logMessage()
: call (* Animal.makeSound(..));

we defined a join point at every method of Animal type which is like makeSound. We do not care what type of arguments it has [(..) expresses that] and we don’t care what is its return value [* before Animal expresses that.] Now, for every join point this pointcut returns, we want to log a message around it. Below code is self explanatory.

void around() : logMessage(){
System.out.println("[Log]: ... start");
proceed(); // if I comment out, the method will not even execute
System.out.println("[\\Log]: ... end");
}


BTW, we are done with this small exercise to start with AOP, I should rather say AspectJ. Did you notice the GreetingAspect and the way it has defined its pointcut? I think, learning how to define pointcuts in your Aspect will be the hard part.



Dynamic Proxy

Recently, I came to know about AOP (Aspect Oriented Programming) and realized that its really cool. I read few articles about it and how people take advantage of AOP provided by Spring framework. BTW, AspectJ is number 1 :) But thats not the point, the point is WHY AOP ? when we know that AOP modifies the .class and insert its own code [clever hunn :).] So, how will you debug if there is some exception? Anyways, then I realized I can do the same stuff with Dynamic Proxy ? why not ? : oh yea, reflexion is expensive.

This post is about Dynamic Proxy so, here are my 2 cents.

package com.farwaha;

interface Animal{
public void makeSound(String comments);
public void initialize(String name);
}
class Dog implements Animal{
String name;
public void initialize(String name){
this.name = name;
}
// No logging around this, but we will decorate it using dynamic proxy
public void makeSound(String comments) {
System.out.println(name + " Barks with sound " + comments);
}
public void doDogThing(){
System.out.println(" Doing Dog things");
}
}
class AnimalFactory{
private Class animalClass;
private boolean log = false;
public AnimalFactory(String className, boolean log){
try{
animalClass = Class.forName(className);
this.log = log;
}catch(ClassNotFoundException cne){
System.out.println("ClassNot found exceptoin");
}
}
//here is the trick,
public Animal newInstance(String name){
try{
Animal animal = (Animal)animalClass.newInstance();
animal.initialize(name);
if (log){
//return proxy if log is enabled
return (Animal)Logger.newInstance(animal);
}
return animal;
}catch(Exception e){e.printStackTrace();}
return null;
}
}
//main
public class ProxyTest {
public static void main(String[] args){
AnimalFactory factory = new AnimalFactory("com.farwaha.Dog", true);
Animal animal = factory.newInstance("Jennifer");
if (animal != null) animal.makeSound("...Grrrrree..");

if (animal instanceof Dog){
System.out.println(" its kind of Dog");
}
if (animal instanceof Animal){
System.out.println("its kind of animal");
}
}
}

-------------------------------------OUTPUT-------------------------------------------------------
[LOG]: makeSound .... invoking
Jennifer Barks with sound ...Grrrrree..
[LOG]: .. Done invoking, args: ...Grrrrree..
its kind of animal
--------------------------------------------------------------------------------------------------

Here is how I will read the code:

  1. Main - > get the AnimalFactory (kind of Animal, log enabled);
  2. Main - > get the animal from factory (name);
  3. Main - > animal make sound ( sound );
  4. SEE THE OUT PUT: What about the log messages ? Logger.newInstance() is the answer


package com.farwaha;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class Logger implements InvocationHandler{
//return the proxy of given object, and save the reference
public static Object newInstance(Object target){
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new Logger(target));
}
private Logger(Object target){
this.target = target;
}
private Object target;
//decorate the invoked method, transparently.
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
try{
System.out.println("[LOG]: " +method.getName() + " .... invoking");
result = method.invoke(target, args); // method invocation
System.out.print("[LOG]:"+ " .. Done invoking, args: ");
for(Object obj : args){
System.out.print(obj.toString() + " ");
}
System.out.println();
}catch(InvocationTargetException iet){
System.out.println("Some crap exception");
}
return result;
}
}


I hope this is the simplest example of dynamic proxy, but it clearly shows its power. So, if I can separate my logging "concern" with dynamic proxy, I can also separate my "authorization", "persistence" and "transactional" concerns, Isn't it ?