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?

Jul 19, 2010

Supporting multiple Android versions in Your application

Often when developing apps for the Android platform you come across the problem of supporting multiple Android versions. There are two flavors of this problem. The first is when the API you need does not exist in the older version and thus you can only use it in the new version. An example is the AccountManager which is available since API level 5 (Android 2.0). The second flavor is when the API changed between versions. In this case You can (if you are lucky) find a common ground between the versions and use it with both versions. An example of this problem is the Contacts API which changed drastically between versions 1.6 and 2.0. There are several solutions to this problems. A few of them are mentioned in this Google I/O video (at about minute 36).

The first flavor
As I mentioned earlier this is the flavor where the API did not exist in the older version. I will elaborate on an example with the AccountManager. The base of the solution is to isolate the behavior that causes the problem (i.e. the AccountManager stuff) in a separate component. The first step is to design an interface through which the component will communicate with the rest of the world. In this case I will use the following interface:

public interface IGoogleAuth {
  List<String> getGoogleAccounts();
  ...
}   

Next I will implement it:

class GoogleAuth implements IGoogleAuth {
  private static final String ACCOUNT_TYPE = "com.google";

  @Override
  public List<String> getGoogleAccounts(){
    AccountManager accountManager =                         AccountManager.get(App.getContext());
    Account[] accounts = accountManager.getAccountsByType(ACCOUNT_TYPE);
    ArrayList
<String> accList = new ArrayList();
    if (accounts != null && accounts.length > 0) {
      for(Account a: accounts) {
       
accList.add(a.name);
      }
    }
    return
accList;
  }
  ...
}

The code is pretty straightforward. First an AccountManager instance is requested from the application and then the instance is queried for Google Accounts (they have the type "com.google"). If the account manager returns any accounts, their name (email) is added to the list that is returned to the caller. Note that the GoogleAuth class is package private since it should not be used outside the enclosing package. One important point to note is that the interface must not use any classes that are defined in the new API because then the application would throw an exception probably causing a Force Close dialog when run on a device with an older Android version. In other words, the interface must only use classes that all involved versions can process. For example, the interface must not use the Account class in the following way:

public interface IGoogleAuth {
  List<Account> getGoogleAccounts();
  ...
}   

since it would crash on an older Android version. Now that the implementation is finished we can implement the factory class:

public enum GoogleAuthFactory {
  ;
  private static IGoogleAuth auth = null;
  private static boolean isSet = false; 

  public static boolean hasGoogleAuth() {
    int sdkVersion = Integer.parseInt(Build.VERSION.SDK);
    return sdkVersion >= Build.VERSION_CODES.ECLAIR;
  }  

  public static IGoogleAuth get() {
    if (!isSet) {
      if (hasGoogleAuth()) {
          auth = new GoogleAuth();
      }
      isSet = true;
    }
    return auth;
  }
}

All that remains is to use the code. It can be used in the following way:

  if(GoogleAuthFactory.hasGoogleAuth()) {
    //This device has a version that implements the api
    IGoogleAuth auth = GoogleAuthFactory.get(); 
    List<Account> accountList = auth.getGoogleAccounts();
    // Display the account list
  } else {
    //This device has an older version. Do something else. 
  }

The code above will work on both versions without problems. Now let's get on to the second flavor.

The second flavor
Now let's examine the second type of problem that includes an API that both versions support but has changed drastically between versions. This problem is actually very similar to the first one but it has its own set of tips and tricks. To elaborate this problem I will use the Contacts API that has changed a lot between versions 1.6 and 2.0. Let's say that we want to start the default activity for adding a new contact to our contacts. To start the activity we need an intent. Such an intent exists, of course, but it looks like this in version 1.6:

Intent i = new Intent(Contacts.Intents.Insert.ACTION, Contacts.People.CONTENT_URI);

and it looks like this in version 2.0:

Intent i = new Intent(Intent.ACTION_INSERT, ContactsContract.Contacts.CONTENT_URI);

It should be noted that in this example starting the activity with the version 1.6 intent on the version 2.0 device would probably work but I am using it here just to demonstrate a technique and to keep the code snippet size at bay. But with this technique You could also implement a method that returns a list of contacts that have an email address which is a lot less trivial task to implement on both versions (that's another story). The base of the solution is the same as with the first kind of problem. We need to isolate the different API's in separate components. First we will design the interface to the world. It looks like this:

public interface IContact {
  Intent getAddContactIntent();
}

Next we implement the interfaces in package private classes. Once for the version 1.6 API:

class ContactVersion4 implements IContact { 
  @Override
  public Intent getAddContactIntent() {
    return new Intent(Contacts.Intents.Insert.ACTION, Contacts.People.CONTENT_URI);
  }
}

And the second time for the version 2.0 API:

class ContactVersion5 implements IContact { 
  @Override
  public Intent getAddContactIntent() {
    return new Intent(Intent.ACTION_INSERT, ContactsContract.Contacts.CONTENT_URI);
  }
}

Everything gets connected in the factory class:

public enum ContactFactory {
  ;
  private static IContact contact = null;

  public static IContact get() {
    if (contact == null) {
      int sdkVersion = Integer.parseInt(Build.VERSION.SDK);
      if (sdkVersion <= Build.VERSION_CODES.DONUT) {
        contact = new ContactProcesorStari();
      } else {
        contact = new ContactProcesorNovi();
      }
    }
    return contact;
  }
}

The get method determines the Android version on the first invocation and creates the appropriate IContact implementation according to the version. The reference is  then cached for future invocations. The only thing that remains to do is to use the factory. This is how it is done:

  IContact contact = ContactFactory.get();
  startActivityForResult(contact.getAddContactIntent(), 1);

This code is safe to use on both Android version 1.6 and version 2.0. A variant of the factory implementation involves using reflection but I do not like to use reflection unless I absolutely have to. I hope this will help someone. Forgive my beginner's mistakes since this is the first blog I have written.

References
Nick's blog
Working with Android contacts