Jul 21, 2010

Using Hessian in your Android application

Adding Hessian to your application is not very hard but there are a few things you have to take care of. One of them is the size of the Hessian library.

Size matters
Although the Hessian library is pretty small (the version I used 4.0.6 has only 376 kilobytes) it can be made smaller. Since it is not likely that you will need the server side code on the mobile device it can safely be removed. Also the library contains some other stuff that you can safely do without. A nice attempt to remove the superfluous stuff from the Hessian library can be found in the hessdroid project on Google Code. I personally did not use it since I wanted to have the same Hessian version on the client and on the server and I was not sure which Hessian version hessdroid is based so I made my own "hessdroid" library. The changes were too extensive to list here but if anyone is interested please drop a line in the comments and I will post an archive containing my version of the library. To use and understand the following code snippets you have three options. You can use the original library without the modifications (and thus end up with an apk file a bit bigger than necessary), you can try to use the snippets with the hessdroid library or you can drop me a line in the comments and you can try with my version when I prepare and upload it.

The setup
To retrieve the proxies we need to invoke the remote methods, we will implement a factory class.

public enum ProxyFactory {;
    private static ClassLoader classLoader;
    private static HessianProxyFactory factory = 
      new HessianProxyFactory();
    private static String defaultServerUrl;

    public static void init(ClassLoader cl, String dsu) {
      classLoader = cl;
      defaultServerUrl = dsu;
    }
    
    public static <T> T getProxy(
        final Class
<T> proxyClass,
        final String relativePath) {
      URL url;
      try {
        url = new URL("http://" + defaultServerUrl + "/" +              relativePath);
      } catch (MalformedURLException e) {
        throw new RuntimeException(e);
      }
      HessianProxy proxy = new MyHessianProxy(factory, url);
      T o = (T) Proxy.newProxyInstance(
          classLoader,
          new Class[]{proxyClass, HessianRemoteObject.class},
          proxy);
     return o;
  }

  private static class MyHessianProxy extends HessianProxy {
    public MyHessianProxy(HessianProxyFactory factory, URL url) {
        super(url, factory);
    }
  }
 
}

I will explain how the init method should be used a bit later. The method is used to set Hessian's class loader since the default class loader Hessian uses does not work properly on Android. The init method is also used to set the default server's url. Since most servlets that the proxies will invoke are on the same server it makes sense to store the server part of the url in a dedicated variable. You can easily overload the getProxy method with an additional parameter if you need to change the server part of the url. The getProxy method is the workhorse of this factory class. It is the method you can use anywhere in your code to retrieve a proxy to invoke methods on the server (GAE in our case). It first creates the complete url from its components. Then it creates the HessianProxy which handle all the calls that will come through the interface defined by proxyClass. I extend the HessianProxy class with MyHessianProxy since HessianProxy's original constructors are all protected. This extending will come in handy later when we implement cookie handling in Hessian (and some other stuff but I'll write about that in a future post). The last step is to create a new proxy instance and return it to the caller.

Usage 
It is very easy to use this factory class in your code. You just need to do this:

  Service service = ProxyFactory.getProxy(
    Service.class, "relative/path");
  service.doSomething();


While it is certainly possible to use this snippet from anywhere in your code, it is best to use it in background threads since the remote calls may take a long time to complete.

The initialization
All that is left to explain is the proxy factory initialization. It is best done when the Android application starts up. To do this you must implement a class that extends from android.app.Application and override its onCreate method. For example:

public class MyApp extends Application {
  @Override
  public void onCreate() {
    super.onCreate();
    String server = getString(R.string.server);
    ProxyFactory.init(getClassLoader(), server);
  }
}

The last thing to do is to add an android:name=".MyApp" attribute to the application tag in your AndroidManifest.xml file. 

Conclusion
As you can see it is not exactly trivial to use Hessian in your Android app. The trickiest part is reducing the size of the library. So I thought that it would be nice if we could use such a framework out of the box on Android. This is why I reported an issue on the Android issue tracker. If you like the idea please star it. That's all folks for this post.

4 comments:

  1. Thanks! Could you post your version of truncated hessian library?
    I'm using hessdroid n client and hessian 3.1.5 on server and sometimes have some deserialize errors or hessian exceptions ("expected integer at the end of file, etc..") :(

    ReplyDelete
  2. Sure man. Here it is:
    http://code.google.com/p/monkeyboy-blog/
    It is the only thing in the repository. I was planning to include the examples from this blog in that repo but I never seem to find the time to do it.

    ReplyDelete
  3. This is one of the amazing post.This is one of the user friendly post.This is one of the well organized post.
    Android app developers

    ReplyDelete
  4. Thank you very much, your version worked on Android 5.1, while hessdroid and the flamingo implementations did not.

    ReplyDelete