Friday, July 24, 2009

TurboStringMap for Gwt

In my previous post I did mention that Gwt has the basic Java collections emulated in Javascript. In the browser such rich interfaces may not be needed. There is a lightweight Map implementation where the keys are constrained to String types only called FastStringMap. It is directly backed by a Js array. Want to go even lighter then here is the derived TurboStringMap which even a thinner API over a Js array to act like a Map.

The rest of the this post is Gwt Java code-


package com.onyem.finance.client;

import com.google.gwt.core.client.JavaScriptObject;

class TurboStringMap {

/*
* Accesses need to be prefixed with ':' to prevent conflict with built-in
* JavaScript properties.
*/
@SuppressWarnings("unused")
private JavaScriptObject map;

public TurboStringMap() {
init();
}

public void clear() {
init();
}

private native void init() /*-{
this.@com.onyem.finance.client.TurboStringMap::map = {};
}-*/;

// Prepend ':' to avoid conflicts with built-in Object properties.
public native T get(String key) /*-{
return this.@com.onyem.finance.client.TurboStringMap::map[':' + key];
}-*/;

// Prepend ':' to avoid conflicts with built-in Object properties.
public native T put(String key, T value) /*-{
key = ':' + key;
var map = this.@com.onyem.finance.client.TurboStringMap::map;
var previous = map[key];
map[key] = value;
return previous;
}-*/;

// Prepend ':' to avoid conflicts with built-in Object properties.
public native T remove(String key) /*-{
key = ':' + key;
var map = this.@com.onyem.finance.client.TurboStringMap::map;
var previous = map[key];
delete map[key];
return previous;
}-*/;

// only count keys with ':' prefix
public native int size() /*-{
var value = this.@com.onyem.finance.client.TurboStringMap::map;
var count = 0;
for(var key in value) {
if (key.charAt(0) == ':') ++count;
}
return count;
}-*/;

public boolean isEmpty() {
return size() == 0;
}

public native String[] keys() /*-{
var value = this.@com.onyem.finance.client.TurboStringMap::map;
var keys = [];
for(var key in value) {
keys.push(key.substring(1));
}
return keys;
}-*/;
}

Wednesday, July 08, 2009

GWT

I've been working with Gwt since a while and in this post will dump some of my learnings

What is Gwt
Gwt is a toolkit primarily to enable writing webapps in Java which will then be cross compiled into plain Javascript and Html. The core is based on this java to javascript compiler. Additionally they have libraries for purposes like web gui creation, dom manipulation, json and xml parsing, RPC calls with java server support and also unit testing. The Gwt guys are seem pretty obsessed with performance so a lot of the design choices are based on this.

To code in Gwt you use your standard Java tools. This is a great advantage as you get great tool/ide support and java's static checking for code. Java generics are also supported. To create UIs a SWT-like library has been created which can be used. The library contains both Widget classes for common controls as well as layout classes for positioning. There are some quirks which you have to be aware of but thats true for almost any new platform. The layout library is one of the first reasons which got me to Gwt as I was (and still am) simply too scared to use CSS for managing a layout. Using the UI libraries for building interfaces is a bit painful in Java just as it is in Swing and Swt. But more importantly it does not translate to the best Html/Css layout code. For example to place child elements horizontally next to each other you can use the HorizontalPanel and add elements to this. Now when this code is cross compiled the HorizontalPanel is converted to a Html table with a single tr and all the child elements will be placed in td elements. Which depending on your style may not look that good. In the next version of Gwt a new UI Binder feature is going to be added. This will allow declaring the UI in an XML format and then writing the actual event handlers in Java. I guess a lot of UI frameworks are moving to this style which really does make sense in this domain. Also the code generated may be closer to the layout code you would have written by hand (if you knew CSS). You can also create your own Widgets and Panels if you want to. I also almost forgot to mention that you have access to a subset of the Java library. The API can be read here. Basic java.lang and other important packages like some collections are supported.

Now that you have written some Java code you compile it by using the GwtCompiler which can be invoked by an ant task. You get a whole bunch of files into your dist folder. Now these are plain html, js and css files. You dont need any Java support in your webserver to run these. Gwt will generate separate optimized files for each browser supported. A client using IE7 will get a file separate from a FF client and each file will manage the quirks of that browser. So a client downloads almost only what is needed. I lied a bit in this process though. When the browser first hits the entry point html file special js code will decide what browser is running the code. After that the client code for that browser is then loaded in another Http request. Search for more on deferred binding to learn more. Importantly most of the code generated can be cached with long expiration headers.

The Gwt compiler essentially compiles Java (source code) to Js. But from where does it get the java.lang and other code of the standard library? The Gwt team has re-written supported Java libraries in a more Js friendly fashion. The String class is based on a normal Js string but the extended Java API for the string class is supported. Similarly the ArrayList class is not something that Bloch wrote but a simpler Js friendly version. Just like the layout code generated some of this is overkill for Js. You dont really need the whole Collections API most of the time. You dont need the whole class hierarchy. Like I just needed a lame Map implementation with put and get and nothing else. And since some part of the Gwt library may use the collections in some way you end up using them anyways. See my bug for an extended rant

Atleast one compiler optimization has to mentioned at this point - dead code elimination. For example if you dont use the substing method in the String class.. that method will not be compiled to Js. Additionally Js code is minified and obfuscated which greatly helps in reduction of download size.

Where should you use GWT
Gwt is great for Ajax apps like Gmail, Google calendar etc. As a Java developer I dont think I could do better/faster had I been coding Js/Html for Onyem. There are deficiencies right now but things are improving and are already optimized enough.
I would not still recommend Gwt in sites that have a lot content like news sites or sites where you just want a small widget in one corner. Use jquery or yui for that.
Also there can be no substitute for knowing CSS and also how to build websites. With a desktop mindset you will end up just bulding really slow apps.

More Features
These may come in some other post-
Hosted mode to OOPHM
Async pattern
Jsni
RPC
Deferred binding
More Compiler optimizations