Saturday, June 28, 2008

Aspect Programming with Oracle Coherence

Due to the nature of Coherence APIs, it is deceptively easy to make any current application Grid ready. Coherence v3.3 requires that all the domain objects implement java.io.Serializable. Coherence provides ExternalizableLite, a highly optimized Serializable interface along with ExternalizableHelper to serialize/deserialize attributes. It is required that all Cached Domain objects are updated to implement this interface. Even though this process can be made pretty trivial by using AOP (Aspect Oriented Programming). Following is an Aspect along with a Helper class that can be applied/woven to all of your domain objects to make them Coherence ready. The ELAspect makes the following assumptions:


  • Domain Objects follow standard Java Bean specification.

  • All the Domain Objects extend a single Type. Change the ELAspect code to replace "Test" with an appropriate root object or follow AspectJ's Inter-type declarations.


This Aspect can be compiled with the domain objects (Or woven) with AJC AspectJ compiler.

package com.ezduck.aop;

import org.aspectj.lang.reflect.Pointcut;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.io.DataInputStream;

import java.lang.Exception;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;

import com.tangosol.io.ExternalizableLite;
import com.tangosol.util.ExternalizableHelper;

public aspect ELAspect {

declare parents: Test implements ExternalizableLite;
Field [] Test.fields = this.getClass().getDeclaredFields();
Class Test.elHClass = ELHelper.class;


private Object Test.invokeGetter (Field field, DataInput dI) {
Class clazz = field.getType ();
String mName;
if (clazz.getPackage().getName().startsWith("java")) {
mName = "read" + clazz.getSimpleName ();
} else {
mName = "readObject";
}
Object value = null;
try {
Method eMethod = elHClass.getMethod (mName, DataInput.class);
value = eMethod.invoke (null, dI);
} catch (NoSuchMethodException nExp) {
try {
Method eMethod - elHClass.getMethod ("writeObject", new Class[] {DataOutput.class, Object.class});
ehMethod.invoke (this, new Object [] {dO, value});
} catch (Exception exp) {
// -- Skip it
}
} catch (IllegalAccessException iExp) {
} catch (InvocationTargetException tExp) {
}
return value;
}

/**
* Add an implementation for readExternal, for example:
* in = ExternalizableHelper.readInt(dataInput);
*/
public void Test.readExternal (DataInput dI) {
System.out.println("Inside readExternal");
String attrName;
Class clazz;

for (int i = 0; i < fields.length; i++) {
if(!fields[i].isSynthetic ()) {
attrName = fields[i].getName();
clazz = fields[i].getType ();
Method eMethod;
String setter = "set" + Character.toUpperCase(
attrName.charAt(0)) +
attrName.substring(1);
Method method;
try {
Object value = invokeGetter (fields[i], dI);
System.out.println("Value is: " + value.toString ());
method = getClass().getMethod(setter, clazz);
method.invoke(this, value);
} catch (NoSuchMethodException nExp) {
} catch (IllegalAccessException iExp) {
} catch (InvocationTargetException tExp) {
}
}
}
}

private void Test.invokeSetter (Field field, DataOutput dO, Object value) {
try {
Class clazz = field.getType();
String cName;
String mName;
if (clazz.getPackage().getName().startsWith("java")) {
mName = "write" + clazz.getSimpleName ();
} else {
mName = "writeObject";
clazz = Object.class;
}
Method ehMethod = elHClass.getMethod (mName,
new Class [] {DataOutput.class, clazz});
ehMethod.invoke (this, new Object[] {dO, value});
} catch (NoSuchMethodException _nExp) {
_nExp.printStackTrace ();
} catch (InvocationTargetException _tExp) {
_tExp.printStackTrace ();
} catch (IllegalAccessException _iExp) {
_iExp.printStackTrace ();
}
}

/**
* Add an implementation for readExternal, for example:
* ExternalizableHelper.readInt(dataOnput, in);
*/
public void Test.writeExternal (DataOutput dO) {
System.out.println("In writeExternal");
Class clazz;
String attrName;
for (int i = 0; i < fields.length; i++) {
if (!fields[i].isSynthetic ()) {
attrName = fields[i].getName();
attrName = Character.toUpperCase(attrName.charAt(0)) +
attrName.substring(1);
clazz = fields[i].getType ();
String getter = "get" + attrName;
Method method = null;
Object value = null;
try {
method = getClass().getMethod(getter, new Class[]{});
value = method.invoke(this);
System.out.println("Value: " + value.toString ());
invokeSetter (fields[i], dO, value);
} catch (NoSuchMethodException nExp) {
nExp.printStackTrace ();
} catch (IllegalAccessException iExp) {
iExp.printStackTrace ();
} catch (InvocationTargetException tExp) {
tExp.printStackTrace ();
}
}
}
}
}

And the Helper class is:

package com.ezduck.aop;

import com.tangosol.util.ExternalizableHelper;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;

public class ELHelper extends ExternalizableHelper {
public static int readInteger (DataInput dI) throws IOException {
return readInt(dI);
}
public static String readString (DataInput dI) throws IOException {
return readSafeUTF(dI);
}

public static void writeInteger (DataOutput dO, int n) throws IOException {
writeInt (dO, n);
}

public static void writeInteger (DataOutput dO, Integer iN) throws IOException {
writeInt (dO, iN.intValue());
}

public static void writeint (DataOutput dO, int i) throws IOException {
writeInt (dO, i);
}

public static void writeString (DataOutput dO, String s) throws IOException {
writeSafeUTF(dO, s);
}
}

Even though I tested the code with quite a few data types but feel free to update it if any Exceptions are thrown and leave a comment on this blog as well to let us all know.

No comments: