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.

Tuesday, June 24, 2008

I back Obama..

I am backing Obama. I don't want to, but I want to be part of the fairytale as well!!

Saturday, June 21, 2008

The myth of Serializable free distributed computing

For some, Domain modeling is not a science its an art. Hardcore domain modelers will tell you rules and list of good practices that will make you believe that you haven't learned anything yet. I loosely touched this subject in one of my blogs as well. A good domain object is one that does not know anything about the infrastructure it will be run inside. A domain object is not just a placeholder of getters and setters but can also have other behaviors as long as it only operates on the attributes it owns. Following is a good example of a domain object:


public class TwoInt {
private int a;
private int b;
public int getA () {..}
public void setA (int a) {..}
public int getB () {..}
public void setB (int b) {..}

// --
public int add (int a, int b) {
return a+b;
}
}

Distributed computing somewhat challenges the established notions of domain modeling. The JVM contract says if an Object is to be moved from one JVM to another it has to be Serializable. Period. This contract can not be breached. Designing a distributed application with a Single System Image has this challenge to overcome. For the example Object TwoInt to be used in a distributed environment it has to implement java.io.Serializable that the domain perfectionists will see red on. What if the application is only deployed on one single JVM? Then why Serializable? Being Serializable is a concern of an infrastructure not a requirement of the domain model.
Whats wrong with the following?

public class TwoInt implements Serializable {....}

public class App {
public static void main (String [] args) {
TwoInt key = new TwoInt ();
TwoInt value = new TwoInt ();
java.util.Map m = <??????>;
m.put (key, value);
}
}

Map is an Interface. If its implementation is to be replaced by a HashMap by far the most popular implementation of java.util.Map, then TwoInt objects are not required to implement Serializable. If this application is to be run in a Distributed Environment and Map's implementation is a NamedCache (Another implementation of a Map interface but now in a distributed environment) then TwoInt has to implement Serializable. So any change in the Map's implementation has a direct consequence on its domain model.
Aspect Oriented Programming can be a bridge between what is required in distributed computing and domain perfectionists. Good part is, a domain modeler sees a Java source and Distributed computing sees the byte codes. Hence Serializable is a cross cutting concern and with AOP if implemented at compile time both camps will be happy. Following is a sample how to do it using AspectJ, an AOP implementation:

public aspect TwoIntAspect {
declare parents: TwoInt implements Serializable;
}

Then compile the domain object with its Aspect using ajc (AspectJ Java compiler) as:
$ ajc TwoInt.java TwoIntAspect.java
The TwoInt.class will be changed to have Serializable interface implemented.

Friday, June 20, 2008

Why solar cars won't fly

Reason is simple - I just don't trust batteries. Here is what I have at home as I write:
1. The cable wire of the AC Adapter of my laptop was somehow cut (looked like because of heat) and with no adapter the laptop is sitting idle drained. Just ordered an adapter from Amazon.
2. The new battery for one of my smoke deductor seems dead.
3. The battery of the Roomba discovery has been dead for months now and I just can't find a local replacement place.
4. I just replaced rechargeable batteries for my hand set and now seems the other one's died as well.
Either batteries don't like me or this is the least researched area of manufacturing. Go green is good, but with these experience how could anyone convince me to buy a solar paneled car?

Thursday, June 19, 2008

Custom is good


How many times have you downloaded a product to find that it comes prepackaged with products freely downloadable? You would quite often see Apache web-servers or a Java runtime bundled with a product. These are typically either open sourced products or are under a license and customized. Custom is good. And I have an evidence on the upper left. It gives products flexibility to make it work as per your requirements. Off the shelf or cookie cutters are good as well but may not be suitable for all the needs. This is quite true with Application servers that are built on top of products like Apache or Orion. A bunch of custom web server plugins and custom protocols and now I can make money on top of these freebies. JRE is another but not usually highly customized. JREs are pre-bundled to avoid having to download one or due to certification issues or a need of a specific version. I went custom too. Very recently while working for a Client I came across a .NET security issue that required DLLs to be colocated with the invoking application. It was a Java application that invokes some C# APIs. Packaging is important. Now, it was needed that the dll coexists where java.exe was. A good scenario to go custom. Many installers like Install4J provide a flexibility to bundle a JRE with the product. I am not promoting install4j as this not being an open and free product but you got my point. If I can have my own instance of JRE then I can also copy the dynamic libraries in it that the application uses. And your custom JRE is ready to be ridden.

Wednesday, June 18, 2008

Let BJP support Congress if govt falls

Every sane person knows how important is the US nuclear deal for India to address its long term energy needs. Left parties who unfortunately are part of UPA are just propagating weird agenda and do not see the benefit this country will have. Compromises here and there are part and parcel of all the deals. As long as the deal does not threaten the sovereignty of India, the Indo-US nuclear deal should go ahead. Without a stable energy resource India's economy and development is going no where, and for that it would need Nuclear reactors not a dependency on fossil fuels coming from unstable regions. As long as it reserves a right to continue doing research and development with transparency I don't see any reason for anyone to oppose it. I dare left to pull out the support if Government decides to go ahead and challenge BJP to come forward and support the govt on this issue.

Monday, June 16, 2008

Never thought of going to MSDN these many times

I am working on a project that uses quite a few C# APIs. For the audience of this blog I would have never imagined mentioning C#. But, its a good language and has its advantages for those who are using it. I came across a scenario when the option was either to rewrite the APIs in Java or reuse it. To mitigate the risk I decided to reuse it and invoke the C# API in Java through JNI. As it turns out C# API needs to be wrapped around two layers of C++ - First a Managed C++ and then another C++ wrapper to generate the dynamic library (DLL) that can be loaded and used by JNI. Came across another rather bizarre problem, that due to a reference to C# API (Some .NET Security requirement) the DLL has to be in the same directory as its invoker. My invoker is java.exe and for this thing to work this DLL has to be copied over to $JAVA_HOME/bin directory. Even though not a show stopper but this defeats the entire purpose of good deployment practices. One of my colleagues at the Clients who brings in a lot of .NET experience to the team pointed me to GAC (Global Assembly Cache) that can be used to address these issues. A few more MSDN pages to the point that I don't even care of using it. And as GAC requires administrative accounts I am even more disinclined of using it. Not because I do not have an administrative account but my dislike of products that only work when you have one. In the meantime while the colleague researches other options of by-passing the java.exe and dll co-location I am happy to take a shot to sell the idea of it.

Friday, June 06, 2008

Sirf - A good movie to watch

There is always a time in a year when I start to believe that Bollywood has stopped making good movies and then I end up watching one that defeats my opinion. "Sirf" being one this year. First 15 mins felt as one loose boring new comer launch sort of, but as more and more characters were introduced it kept me bounded to my chair. Even though not very well controlled but the strength of the script pulled it off. This movie is about four couples at different social levels, different dreams and with different priorities but related to the same set of events. Manisha Koirala looked as beautiful as she was 16 years ago when I first fell in love with her. Other characters played good as well. I did connect to one of the characters that drove me through the end of the movie. It was a sad end, a little exaggerated reality but yes with some truth that might leave you a little shaken. A good watch.

Monday, June 02, 2008

Security framework for C++ *Extend clients

Before Oracle Coherence v3.4 goes live (More on Brian Oliver's blog for a review of C++ APIs), a shortcut to integrate C++ clients is through JNI. JNI solution works like any other Java application as the requests are made to the grid through a JVM spawned from a C++ thread using JNI invocation API. Even though not required but typically C++ clients use Coherence *Extend technology. If your network is not reliable and prone to failures then Extend is a perfect solution to access a data grid. Coherence Extend is also an important approach to build a transparent fail-over to a DR cluster should the primary cluster goes down in case of a catastrophic failure. Besides unreliability of the network, if the environment is not safe and prone to malicious use of the grid then it is important to integrate a Security framework as well. Oracle Coherence has a built in support for security for Grid members and Extend clients. Extend security works different from a grid member security and requires some programming effort using Coherence APIs. Coherence supports Java security model and expects to have a valid Subject before a PrivilegedAction is run on it. JAAS will be a good framework to read. Once a valid Subject has been created, it can be used to run multiple privileged actions unless logged out.
The Coherence data grid uses Java's security framework to retrieve and validate the Subject when its resource is accessed. The way it does is a bit novel as well. The grid uses an obfuscated redirection to a custom NamedCache that validates if the user is allowed to use its resource. This internal redirection is hidden from the *Extend clients. It is important to make sure that which ever way is the obfuscation done is done strongly. Even though this is not a fool proof solution and can be broken but then no security solution is. More creative you are better the obfuscation will be - at the cache and code level.