a stream of thoughts, features, goals, and implementation ideas for navigating personal spaces in a connected metaverse.

Friday, June 17, 2011

Using Google Web Toolkit (GWT) for UI and RPC for the Anarchia Author interface

This is a bit of a ramble, but contains links to get started using GWT, and some notes on how to use Eclipse and IntelliJ IDEA for GWT development.

For http://anarchia.us I plan to deploy using http://dynamide.com as the templating engine for browsing all the content. But the Author interface (that is, the interface that authors must use to upload content, manage identity, choose frame layouts, make story trails, and assign copyrights), is a real app. It has business rules, editing of one-to-many relations, and many of the things that make application development and deployment difficult via a web interface. I had planned to deploy this app as a pure java client using http://tagland.org , but the tagland client still needs a heap of work. I could use dynamide for this app, but there is a lot of back and forth to the server, and dynamide, being form-based, would make this a bit too web-1.0.

Enter Google Web Toolkit (GWT). I decided on using GWT for the Author interface because it promises cross-browser functionality, and AJAX communication to the server. Downsides: it is complicated; it has a slow load time; it has a number of moving parts that are inaccessible. I decided that the slow load time was acceptable for the Author interface since it is basically an admin application--designed to be used by a limited number of authors who are motivated to use the system, compared with the browsing interface which will be used by anyone on the web. After some initial testing, I also found that complications seemed to be in the build and deploy process, and not in the browser environment, so could be managed like any other software complexity. I also found during prototyping that all of the abstractions I really wanted were supported. GWT supports serializing real java objects across the wire with its own RPC mechanism, and supports construction of the UI by composition of components. Another plus of GWT, for a Java programmer, is that all the code and logic are in Java. So you get compile-time checking of everything, strong typing, exceptions, etc. This goes a long way towards managing simplicity. On balance, it seemed that GWT managing of complexity was the way to go rather than managing that complexity directly with something like jQuery.

On to the things I learned while prototyping GWT.

First, you can see the actual code I used here: http://tagland.sourceforge.net . There are some dependencies, so you'll probably need to check out the whole project. Look in module anarchiaAuthor. This project compiles in IntelliJ IDEA 10.5.

GWT is supported in Eclipse and IntelliJ IDEA. Eclipse supports a UI designer tool which is very cool. They both generate sample applications for you, which is the only way to get started. The flavor of AsyncCallback that the use is a bit different. Eclipse generates inline anonymous classes; IDEA generates named, inner classes. I'm a fan of IDEA, so once I established that they both worked, I moved on to developing all my code in IDEA. IDEA has slightly better inspections and jumps between Java, XML, and HTML files in the project a bit better. Eclipse generates the deployment files correctly, which is to say, all the files with MD5 sums in their names, which are browser-specific files for deploying to all supported browsers. In IDEA 10.5 (they say they'll fix this in 10.5.1) you need to add two jars to your classpath to get this to work. In Project Structure > Libraries > gwt-user > Classes, you need to click "Attach Classes", then point to your local GWT installation dir, where you must find validation-api-1.0.0.GA.jar and validation-api-1.0.0.GA-source.jar. Accepting these files should add the jar files to the classes node (not to the sources node).

To get started in IDEA with GWT, I followed this screen-cast *very* closely, using the pause button frequently. http://www.jetbrains.com/idea/training/demos/GWT_Basics/GWT_Basics.html . Basically, you install the GWT plugin, then create a new Java module, and then specify that it uses Google Web Toolkit, making sure to check the checkboxes that ask if you want it to create a source directory and if you want it to create a sample application.

I found this article to be thorough and well written:http://www.vogella.de/articles/GWT/article.html
It also got me past one of the big humps, which was how to let GWT know about dependent modules so I could use GWT as a layer, rather than an all-in-one solution. This is important if you want to keep from copying code or source jars around, and if you want to keep from getting everything wrapped up in GWT land so that you can't pursue other implementation strategies. Specifically, I found this section very helpful: http://www.vogella.de/articles/GWT/article.html#modules

There are two things going on when you import modules. First, you have to get your IDE to know about the modules. Second, you have to get GWT to find the source code, so that it can translate it into javascript, which is the magic that makes GWT work.

The above article shows how to do this in Eclipse. In IDEA, you should also follow the article on how to do GWT module imports, then you must create an IDEA module in your main project, call it a Java module, and add dependencies on lib directories. In tagland, tagland is the main project, anarchiaAuthor is the GWT module (a Java module with a Google Web Toolkit feature selected on the second or third page of the New Module wizard), and anarchia-obj is a Java module that contains just the serializable, GWT-friendly POJOs. (POJOs are GWT-friendly if they don't import things that can't be serialized and sent to the client. The list is here: http://code.google.com/intl/pl-PL/webtoolkit/doc/2.2/RefJreEmulation.html . You'll find that things like java.net.URL are not included.) anarchiaAuthor, being a GWT module, has a WEB-INF/lib directory, and that must be added in the project as a lib directory, and that lib must be added as a dependency in the module settings. anarchia-obj, being a POJO module, must be added as a dependency in the module settings for anarchiaAuthor.

"No source code is available for type java.net.MalformedURLException; did you forget to inherit a required module?"

You'll get these kinds of errors if you don't have the source code for the classes you want to serialize included properly in the IDE and in the imports statement for GWT. For IDEA, you sometimes need to restart IDEA after fiddling with the GWT imports statements.

You will get all kinds of strange errors if you try to send anything across the wire that cannot be serialized and emulated by GWT. In IDEA, be sure to look on the Modules tab of the Run window for the log.

You will also get errors if you include jars in your lib directory that have older sax parsers. The solution is to clean out your lib directory, and add things slowly until the error appears. These can look like this:

[WARN] Unable to process 'file:/Users/laramie/Library/Caches/IntelliJIdea10/gwt/tagland.90e8b9ba/anarchiaAuthor.4b3edb74/run/www/WEB-INF/web.xml' for servlet validation javax.xml.parsers.ParserConfigurationException: AElfred parser is namespace-aware at com.icl.saxon.aelfred.SAXParserFactoryImpl.newSAXParser(SAXParserFactoryImpl.java:37) at com.google.gwt.dev.ServletValidator.create(ServletValidator.java:191) at com.google.gwt.dev.ServletValidator.create(ServletValidator.java:172) at com.google.gwt.dev.DevMode.doStartup(DevMode.java:426)"

This give you a clue that can help when figuring this stuff out. Note the location of the WEB-INF directory. This is the deployed location, so go in there, and look in WEB-INF/lib, and see what has been deployed. In my case it was extra sax parsers that were incompatible with the one GWT wanted to use.

1 comment:

Thanks for the article. I'm getting started with GWT, and I'm an IntelliJ user. Question: Did you hear any sound in the demo ( http://www.jetbrains.com/idea/training/demos/GWT_Basics/GWT_Basics.html )? Not me!