Friday, June 24, 2011

Dynamic Proxy for gui component listener using InvocationHandler.

Listeners for gui is always easy to create and difficult to maintain.
As they will create additional classes for that and in case we need to
give a patch or something it can be a real pain.

Lets say that a Frame (MyFrame.java) has 10 components and each of them has a listener than there will be 10 additional classes ( MyFrame$1.class,... , MyFrame$10.class, etc).
Now if a fix is given for one of the component and we really do not know which one to give as a hot fix, we will be ending up in giving all the 11 classes.
Another thing which might also force to give all the classes if we change the serialversionId.

So how to overcome this, i have tested it and found it works well.
But is it the right thing to do not sure but good to know.

We can use the InvocationHandler to handle this situation which can call the required method of the frame where we can have the logic/code to be run using Dynamic Proxies to call whenever event is raised.


import java.lang.reflect.*;

/**
 * @author deepak.singhvi
 *
 */
public class InvocationHandlerProxy implements 
      InvocationHandler {

private Object obj;

public static Object newInstance(Object obj) {
  return Proxy.newProxyInstance(obj.getClass()
  .getClassLoader(), obj.getClass().getInterfaces(),
  new InvocationHandlerProxy(obj));
}

public InvocationHandlerProxy(Object obj) {
 this.obj = obj;
}

public Object invoke(Object proxy, Method m, Object[] args)
 throws Throwable {
 Object result;
  try {
    result = m.invoke(obj, args);
  } catch (InvocationTargetException e) {
    throw e.getTargetException();
  } catch (Exception e) {
    throw new RuntimeException("unexpected invocation exception: "
 + e.getMessage());
  } 
  return result;
}
}


For every gui component, for e.g. button instead of overriding actionListener for some action event we can call.

ActionListener foo = (ActionListener) InvocationHandlerProxy.newInstance(new FooWithoutArgActionListener(this,"methodWithoutArgument",new Class[0]));

Listener class would implement ActionListener as usual but the method to be called when a
specific event is raised will be defined in the same class where listener is created, without creating lister anonymously.

public class FooWithoutArgActionListener 
implements ActionListener {
  Method method;
  Object parent;
  public FooWithoutArgActionListener(Object classObject, 
    String methodName, Class[] parameterTypes ){
    method = getTargetMethod(classObject, methodName, parameterTypes);
    this.parent = classObject;
}

@Override
public void actionPerformed(ActionEvent e) {
 ....
  method.invoke(parent, new Object[0]);
 ...
}

private Method getTargetMethod(Object target,
  String methodName, Class[] parameter) 
{
// find the target method which should get 
// executed when actionPerformed is called.
}


Click here to get the Complete example

No comments:

Post a Comment

Heroku Custom Trust Store for SSL Handshake

  Working with Heroku for deploying apps (java, nodejs, etc..) is made very easy but while integrating one of the service ho...