Saturday, August 16, 2008

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 ?

No comments: