Jul 22, 2010

Adding cookies to your Hessian requests

Many authentication schemes use cookies in Http requests to accomplish their task. For example, if you want to implement Google Account authentication in your Android app that uses GAE as the backend you need a way to embed cookies in your request. The Hessian reference implementation does not provide a way to handle cookies out of the box. The hessdroid implementation has some support for cookies but I haven't used it.

Adding basic cookie support is fairly straightforward. All we need to do is extend the HessianProxy class like we did in the previous post with MyHessianProxy.

class CookieProxy extends HessianProxy {
  protected final ICookieProvider cookieProvider;

  CookieProxy(
      HessianProxyFactory factory,
      URL url,
      ICookieProvider cp) {
    super(url, factory);
    cookieProvider = cp; 
  }

  @Override
  protected void addRequestHeaders(HessianConnection conn) {
    super.addRequestHeaders(conn);
    if (cookieProvider != null && 
        cookieProvider.getCookie() != null) {
      conn.addHeader("Cookie", cookieProvider.getCookie());
    }
    conn.addHeader("Content-Type", "x-application/hessian");
  }
}

The constructor receives a ICookieProvider interface aside from the factory and url parameters which are simply forwarded to the parent constructor. The ICookieProvider interface is very simple:

interface ICookieProvider {
    String getCookie();
}

Its getCookie method is used to retrieve the cookie content from the provider that implements it. The main point of interest here is the HessianProxy-s addRequestHeader method which was overridden in order to add our custom Cookie header. The content type header is also set in this method. That's all there is to it. By using this proxy we can send any kind of cookie in the Http requests that are sent to the server when a method is invoked on the proxy.
The last step is to add a new factory method to the defined in the previous post that will use this proxy.

public enum ProxyFactory {;
    ...
    public static T getCookieProxy(
        Class proxyClass,
        String relativePath,
        ICookieProvider cp) {
      URL url;
      try {
        url = new URL("http://" + defaultServerUrl + "/" +               relativePath);
      } catch (MalformedURLException e) {
        throw new RuntimeException(e);
      }
      HessianProxy proxy = new CookieProxy(factory, url, cp);
      T o = (T) Proxy.newProxyInstance(
          classLoader,
          new Class[]{proxyClass, HessianRemoteObject.class},
          proxy);
     return o;
  }
}


Now we can use this method to generate a proxy that sends cookies to the server from anywhere in our code.

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.

Jul 20, 2010

Connecting Android applications to a GAE backend

The last Android application I was working on needed a server side. We decided to use the Google App Engine infrastructure (GAE for short) for that purpose. A problem arose of how to connect the two and make them talk to each other. This is not a trivial task to accomplish. The solution I needed had to satisfy the following requirements:
  • The client side must work on Android. Since Android is a mobile platform the solution on the client side must be lightweight and efficient.
  • The server side must work on GAE. The GAE platform cannot run any Java library (we use the Java flavor of GAE) you throw at it because of the security features the good people at Google implemented.
  • Allow easy object transfer between client and server. I use a lot of Java objects both on the client and on the server side (surprise, surprise). When the need arises to process an object on the server I need to be able to send it to the server and continue the processing there in as few steps as possible. The same goes when I need to get some objects from the GAE database to the client. The objects can contain primitive Java data types, collections and other (simpler) objects.  
  • The solution should require as little boilerplate code as possible (no manual message parsing, etc.)
  • Some kind of support for handling cookies. Google Account authentication and other authentication schemes use cookies in their implementations.
I considered these solutions:
  • GWT RPC - cannot use GWT on a pure java client, although gwtrpccommlayer looks promising but it just got published and i did not have time to test it.
  • gwt-syncproxy - GWT on pure Java clients. Not mature enough at the time I tested it (arround May 2010).
  • Web Services - these are too heavy and complex for the Android platform. Also several implementations do not work on GAE (JAX-WS and JAX-RPC).
  • GET/POST requests with JSON/XML embedded - did not try it but I had the feeling that it involves too much boilerplate code and reinventing the wheel.
  • Restlet - this is a nice library. I used it in a previous project (which did not involve Android) and it works well. But I must confess that I am not a big fan of the Rest concept. Also, as you can probably tell from my first pick, I was looking for a RPC like solution which uses even less boilerplate code than the Rest solution.
  • Hessian - this was the best match for what I had in mind.
The Hessian library is very small (only 376 kilobytes and has no other dependencies). It works on Android (although not perfectly) and on GAE (also not perfectly). I will describe what you need to do to make it work on both in the next couple of posts so stay tuned. It allows you to transfer almost any kind of objects (within reason) between Android and GAE. As for the ease of use here is an example. First we define the contract (a fancy way to say interface):

public interface Service { 
  public String echo(String message); 
}
Next we implement it on the server side:

public class ServiceImpl extends HessianServlet
    implements Service { 
  public String echo(String message){
    return "Server echoes:" + message;
  }
}

Here is how we use this on the client:

HessianProxyFactory factory = new HessianProxyFactory(); 
Service service = (Service) factory. 
    create(Service.class, "http://myserver/echo"); 
String serverEcho = service.echo("Hello world!");
// use server echo...
This is the main reason why I prefer this solution to the Rest and/or GET/POST requests with JSON/XML. You can just define an interface in Java, implement it on the server and use it on the client. You can name the methods of your interface in any meaningful way (or not) you like. IDE refactoring just works. Also, instead of String-s in the example you can use arbitrary objects as parameters or return value of your interface methods. Moreover, when the method is invoked on the server the input parameters are ready to be used. There is no need to use JSON parsers or other methods to create the input parameters from HTTP requests. This is also true on the client side as the Hessian framework takes care of the serialization/deserialization of all your objects. This is one of the cleanest and simplest way I have seen to implement the communication between client and server. However, cookie support is not built into the Hessian framework but the framework is extensible so it is fairly easy to add cookie support to Hessian. I will write about this in a future post.
I would also like to hear from you. What are you using in your Android applications to communicate with a GAE backend?