Using JSP as a templating language for GWT

I wanted to share a solution to a problem a client of mine had–needing the same (or very similar) content in two places–in a lightbox, managed by GWT, and in an HTML page.  The content itself had GWT widgets inside it (that would need to be functional in both places).

The solution was to expose the HTML content as a JSONP file for GWT consumption (and just have the HTML displayed for the HTML page).  To do this,

  • we build the HTML page (in this case, using JSTL and JSP, but any other HTML view technology would work).
  • then we build code that retrieves the page (I used HttpClient)
  • and encodes the entire HTML content as an attribute of a json object (I used json-simple)
  • and exposes it to the world via a URL

Now that we have the content as JSON encoded HTML, we need to consume it:

  • first, create a JSONP consumer, as outlined here
  • then, when you get the content, pull it into an HTMLPanel, not just a HTML widget
  • create new instances of your GWT widgets and attach them to your known span ids using the HTMLPanel.add() method.
  • if your content depends on external css files, you’ll need to add and remove them via JSNI when the lightbox is shown (if you can’t integrate the CSS into the existing site)
  • if your lightbox and html content differ slightly, you can hide or show spans via your server side presentation layer to configure your in lightbox widgets

Benefits

  • One location for display–one place to make changes
  • No layout in GWT–everything happens in HTML
  • Cross domain–since the content is exposed via JSONP, it can be consumed by javascript on any domain.

Detriments

  • Security–you’re exposing yourself to some possible security issues, though since you control both the endpoints, they shouldn’t be too bad.  Read this excellent document carefully to understand the implications.
  • Complexity–lots of moving pieces
  • Caching–JSONP calls are cached by the browser, and a control refresh doesn’t seem to refresh them.  I end up clearing my cache a lot when debugging.
  • Two calls to the server for every lightbox shown.
  • Not sure if it would work in developer mode–possibly with an external server.  Haven’t tried this.

I haven’t played around with any of the GWT templating solutions, but I don’t believe they would work in this case, because of the need for a plain, crawlable HTML page.



GWT Mini Pattern: Bare Bones Entry Point Class

Don’t ever let your entry point class do anything. Why? Because the constructor of the entry point class will be called twice. Once when the object is being instantiated so that onModuleLoad can be called, and then once if your code does anything useful in the constructor. You can also have a constructor that does nothing active (XHR, modifying the DOM) in which case it won’t matter that it is called twice (except it will slow down the user’s computer a little bit.)
Here’s an example of how not to do it (sorry for the [lack of] code formatting):

 

public class Display implements EntryPoint {  public void onModuleLoad() {  final RootPanel rootPanel = RootPanel.get(COMPONENT_HOME_ID);  if (rootPanel != null) {  Display fd = new Display();  } }  public Display() { Window.alert("new date: "+new Date()); // more stuff }  // more stuff }

If you were to compile and execute the code above, you'd see two different alerts. Instead you want:

public class DisplayEntry implements EntryPoint {  public void onModuleLoad() {  final RootPanel rootPanel = RootPanel.get(COMPONENT_HOME_ID);  if (rootPanel != null) {  Display fd = new Display();  } }  }  class Display { // or it could be in a separate java file public Display() { Window.alert("new date: "+new Date()); // more stuff }  // more stuff }

You can also get around it by having a no-op no arg constructor (which all EntryPoint classes are required to have) and one that takes arguments that you'll use in your class to do something.

Tested on Windows, GWT 1.4.62.


GWT Mini Pattern: Make Your Links Friendly To All Users

Sometimes GWT widgets are used to provide functionality, like a form submission, that is easily replicable in traditional HTML. Other times, it’s not so easy to create a user interface that degrades well. Luckily, the self contained nature of widgets means that crucial functionality is typically still available to users with javascript disabled. However, you can take steps to make your site more friendly to users with javascript disabled (for whatever reason).

For the first case, where there is a viable HTML analog, the solution is to have your widget home span look something like this:

<span id="requestinfocuspan"><span class="clickable-link" id="requestinfocuspanplaceholder"><a xhref="/ContactUs.do?ContactUsType=More-info-about-a-listing" mce_href="/ContactUs.do?ContactUsType=More-info-about-a-listing" >Request More Info</a></span></span>

Now, if the user has javascript disabled, and they click on the href, they are sent to the appropriate HTML form. However, if the user has javascript enabled, the widget looks for a span to enable and if it sees the “requestinfocuspan” span, calls code like this:

public static Label buildClickableLink(String span, ClickListener listener) {
Element placeHolderLink = DOM.getElementById(span+"placeholder");
String contentsOfPlaceHolder = "Content unavailable";
Element placeHolderSpan = DOM.getElementById(span);
if (placeHolderSpan != null && placeHolderLink != null) {
contentsOfPlaceHolder = DOM.getInnerText(placeHolderLink);
DOM.removeChild(placeHolderSpan, placeHolderLink);
}
Label clickme = new Label(contentsOfPlaceHolder);
clickme.setStyleName(Constants.CLICKABLE_LINK_STYLE_NAME);
clickme.addStyleName(Constants.INLINE_STYLE_NAME);

clickme.addClickListener(listener);
return clickme;
}

This code takes the contents of “requestinfocuspan”, grabs the text of the span inside it, and replaces the whole of the contents with a label. That label has the same text and a click listener attached, so there’s no bouncing of text. If a designer wants to change the text of this link, they can do so by modifying the JSP without touching (or redeploying) GWT components.The second case mentioned above, where there is no easy way to build an HTML interface for GWT functionality, can be handled by placing a link to a page explaining to the user that javascript is required, and possibly how to turn it on. An easy way to show that link for non javascript users is to use the noscript tag

<script type="text/javascript">document.write("<a xhref='/psaf&city=Boulder'>Advanced Search Form</a>");</script>
<noscript><a xhref='/HomePage.do?state=javascriptNeeded'>Advanced Search Form</a></noscript>

This is a viable option here because there is no need to run the ‘buildClickableLink’ method. We don’t really need a click listener, because we have a plain href to a page that the GWT component will run on.

The other option is to use the existing link method discussed above and use the buildClickableLink method:

<span id="searchspan"><span class="clickable-link" id="searchspanplaceholder"><a
xhref="/HomePage.do?state=javascriptNeeded" mce_href="/HomePage.do?state=javascriptNeeded" >Advanced Search</a></span></span>

While accessibility to non javascript users is not built into GWT (although it might be on the way), you can take steps to make your widgets more friendly to these users. This is especially true if you’re merely ‘ajaxifying’ existing functionality. In addition, users with javascript enabled get a better user experience if you use some of the above methods because the text on the page doesn’t ‘jump around’ when GWT code is executed after the page is loaded.

PS Sorry for the ‘xhref’s in my links above–I’m not quite sure how to turn off the escaping that WordPress or TinyMCE does.  Please replace ‘xhref’ with ‘href’ wherever you see it.


GWT Mini Pattern: Cache ‘static’ data

Using the Java marshalling API makes remote calls from GWT to a Java server quick and easy. However, each of those calls introduces performance and complexity issues. Performance, because browsers tend to limit the number of remote network calls per server. From the HTTP 1.1 RFC: “A single-user client SHOULD NOT maintain more than 2 connections with any server or proxy.” This means that if you have more than two components making network calls, the calls will queue up (and that ignores image downloads and other network connections). The complexity arises from the non linear nature of asynchronous network calls. This can lead to a program structure that is not easily understood without careful reading (‘first, we find the user, then, after that we branch, and if we have a valid user, we find their saved bookmarks from the server…’).

If you have an amount of static content that doesn’t often change from user to user, use a RequestBuilder to retrieve the data from the server. Whatever software generates the data should set headers such that the page is cached for a fair while (either via the Cache Control header or the Expires header). The first time the request is made, the browser ends up making a network request–all the way to the server. After that, the browser will return the resource from its cache, using fewer network resources and returning the data more quickly. Using this approach also makes data available across components and pages. I almost always use JSON to represent such rarely changing data, because GWT can parse that easily, though you could use some other data format as well.

Using the browser as your caching system is not free: you pay for the creating of the network call (XMLHttpRequest, etc) and the reparse of the JSON. But you aren’t going over the network, and it’s relatively transparent to all the clients. The alternative, however, of creating your own caching system, is often more daunting–especially if you want to share data across page requests. I’m not aware of any caching systems (such as ehcache) that are GWT compatible at the moment (and they’d have their own costs in terms of javascript download size). Google Gears does provide something compatible, but is not transparent to the user (Gears requires installation).

Technorati Tags: , ,


GWT Mini Pattern: Configuration Reader

I’ve written about configuration options to GWT widgets before. Basically, the idea is that you have some configuration that lets the widget change behavior without redeploying or compiling code. In fact, nontechnical users (like designers) can change configuration, if it’s documented. These are the ways I know to specify configuration:

Meta tags

In the page:

<meta content="bar" name="foo" id="foo" />

Updated 4/1/2008, to have id in the meta tag attbute.

In your code:

String var = DOM.getElementProperty(DOM.getElementById("foo"), "content");

You can also request only Boolean and Int:

String var = DOM.getElementPropertyInt(DOM.getElementById("foo"), "content");

This is simple, all browsers ignore these tags, and you can place them anywhere in a page and get them read. However, attributes can only contain strings.

Hidden spans

In the page:

<span id="foo" style="display: none">bar</span>

In your code:

String var = DOM.getInnerHTML(DOM.getElementById("foo"));

This is a good choice if you want configuration to be more structured than what a tag attribute can provide--you can parse the 'var' string further.

Javascript using jsni

<script type="text/javascript">
var ID = 'bar';
</script>

And in your code:

private native String getIDAsString()/*-{
if ($wnd.ID == undefined) {
return "";
} else {
return $wnd.ID;
}
}-*/;

private Integer getID() {
Integer id = new Integer(-1);
try {
id = Integer.valueOf(getIDAsString());
} catch (NumberFormatException ignore) {}
return id;
}

Integer foo = getID();

This method is great when you have variables that are used by other javascript components that you'd like to leverage for your GWT component, or if you have a really complex configuration that is multiple levels in structure.

Javascript using dictionary

(As outlined here and here.)
In the page:

<script type="text/javascript">
var dictionary = {
foo: "bar"
};
</script>

In your code:

Dictionary theme = Dictionary.getDictionary("dictionary");
String bar = theme.get("foo");

This is good for simple hash datastructures. I haven't tried it, but from the documentation, it doesn't look like it supports anything past String key value pairs, and your module must inherit from com.google.gwt.i18n.I18N.

Regardless of your configuration method, I've found myself using a ConfigReader to isolate this logic. It looks something like this:

public class ConfigReader{

private final boolean opt1;
private final String opt2;

public ConfigReader(){
// init opt1 and opt2 using one of the four methods above.
}

public boolean isOpt1() {
return opt1;
}

public String getOpt2() {
return opt2;
}
}

GWT Mini Pattern: Use a span to enable

Since I last checked, you aren’t able to have more than one GWT module on a page.  However, each widget is independent, so it makes a lot of sense to package them up as separate modules.  Then, you have one module that inherits from all of the other ones, and therefore all the widget code gets executed.  Except, sometimes it makes sense for a widget to be on one page and not another.  The easies way I have found to do this is to use a span tag with a unique id to mark a page for a component.  Sometimes the span tag is where the component places itself–other times it just serves as a
marker for a component which manipulates the DOM in other ways.

The code often looks like this:

RootPanel rp = RootPanel.get(SPAN_ID);
if (rp != null) {

MyComponent obj = new MyComponent();
rp.add(obj);
}

Now, if we’re on a page that this component does not make sense on, it never gets intialized, no network calls are made, etc.

One issue is that if you want to have the component in more than one place on the page, you need to handle that with special cases.  You can simply use the same id twice, because it is bad form to have more than one element with the same id on a single page–ids are supposed to be globally unique on a page.  If you could use a special tag, that’d be nice, but GWT does not support getElementsByTagName.


GWT Mini Patterns Introduction

GWT can be used to create applications and widgets. I’ve done both, but the feeling I get from reading the newsgroups is that a lot of people are using using GWT to build network applications rather than smaller chunks of functionality. So, I’m going to write a number of posts about GWT component patterns.

First off, what’s a GWT component? In my mind, it is a small bit of functionality that is better run on the client than on the server. It can have server interaction. It does not occupy the entire screen, and has to integrate into an existing HTML based application. Components are relatively self contained and can be dropped in multiple places across a website, or across different websites.

The patterns in this category are not that complicated. They just seemed to be popping up in my code more than once and I thought it’d be nice to document them. Check back here for more as I write them.

Technorati Tags: ,



© Moore Consulting, 2003-2017 +