rich internet applications with grails, part 2: grails and...

25
Rich Internet Applications with Grails, Part 2: Grails and the Google Web Toolkit Skill Level: Intermediate Michael Galpin Software architect eBay 10 Mar 2009 In this second part of a two-part series, add to the Grails-powered Web services you created in Part 1. You will create a new search page, but this time using the Google Web Toolkit (GWT) to create the application. You will also use some richer UI widgets from the Ext GWT library. About this series This series explores application architectures that use a Service Oriented Architecture (SOA) on the back end implemented with the Grails framework. Explore how much Grails simplifies creating Web applications in general and Web services in particular. This kind of back end can be easily hooked up to any pure client-side application. In Part 1, you used Adobe Flex to create an application that leveraged the Flash Player. In this article you will use the Google Web Toolkit (GWT) to create the front end in pure JavaScript. Prerequisites In this article you will build a Web application using Grails and GWT. The Grails framework is built on the Groovy programming language, a dynamic language for the Java™ platform. Familiarity with Groovy is great, but not completely necessary. Knowledge of Java programming can be a good substitute, or even other dynamic languages like Ruby or Python. Grails 1.0.3 was used with developing this article (see Resources). Grails can work with numerous databases or application servers, but none is needed for this article—Grails comes with both. The front end is built Grails and the Google Web Toolkit © Copyright IBM Corporation 2008. All rights reserved. Page 1 of 25

Upload: trancong

Post on 01-Dec-2018

227 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Rich Internet Applications with Grails, Part 2: Grails and ...download.boulder.ibm.com/ibmdl/pub/software/dw/web/wa-riagrails2/... · Rich Internet Applications with Grails, Part

Rich Internet Applications with Grails, Part 2: Grailsand the Google Web ToolkitSkill Level: Intermediate

Michael GalpinSoftware architecteBay

10 Mar 2009

In this second part of a two-part series, add to the Grails-powered Web services youcreated in Part 1. You will create a new search page, but this time using the GoogleWeb Toolkit (GWT) to create the application. You will also use some richer UIwidgets from the Ext GWT library.

About this series

This series explores application architectures that use a Service OrientedArchitecture (SOA) on the back end implemented with the Grails framework. Explorehow much Grails simplifies creating Web applications in general and Web servicesin particular. This kind of back end can be easily hooked up to any pure client-sideapplication. In Part 1, you used Adobe Flex to create an application that leveragedthe Flash Player. In this article you will use the Google Web Toolkit (GWT) to createthe front end in pure JavaScript.

Prerequisites

In this article you will build a Web application using Grails and GWT. The Grailsframework is built on the Groovy programming language, a dynamic language forthe Java™ platform. Familiarity with Groovy is great, but not completely necessary.Knowledge of Java programming can be a good substitute, or even other dynamiclanguages like Ruby or Python. Grails 1.0.3 was used with developing this article(see Resources). Grails can work with numerous databases or application servers,but none is needed for this article—Grails comes with both. The front end is built

Grails and the Google Web Toolkit© Copyright IBM Corporation 2008. All rights reserved. Page 1 of 25

Page 2: Rich Internet Applications with Grails, Part 2: Grails and ...download.boulder.ibm.com/ibmdl/pub/software/dw/web/wa-riagrails2/... · Rich Internet Applications with Grails, Part

using the Google Web Toolkit, and to use GWT you definitely must be familiar withJava. Google Web Toolkit 1.5.3 was used for this article (see Resources).

New services

In Part 1, you created an application that used a Service Oriented Architecture(SOA) built using Grails. It is possible to build a new application on top of this backend. That is one of the major advantages of using an SOA back end with a pureclient-side front end. Your server-side code is completely decoupled from the userinterface. However, to further demonstrate how easy it is to create Web serviceswith Grails, let's modify the existing back end and add a search API to it.

Search API service

The existing application had a search business service. We only used its list API toprovide a list of all stories in the application. Take a look at what else the service cando, as shown in Listing 1.

Listing 1. The Search Business service

classSearchService {

booleantransactional =false

def list() {Story.list()

}

deflistCategory(catName){Story.findAllWhere(category:catName)

}

defsearchTag(tag){Story.findAllByTagsIlike("%"+tag+"%")

}}

The listCategory method finds all of the stories in a given category. ThesearchTag method finds all of the stories with a given tag. It does not require anexact match and is case insensitive. As mentioned, we have only used the list APIso far. So let's create a new Web service that uses these other two methods. All youneed to do is add a new method to the ApiController, as shown in Listing 2.

Listing 2. New ApiController

import

developerWorks® ibm.com/developerWorks

Grails and the Google Web ToolkitPage 2 of 25 © Copyright IBM Corporation 2008. All rights reserved.

Page 3: Rich Internet Applications with Grails, Part 2: Grails and ...download.boulder.ibm.com/ibmdl/pub/software/dw/web/wa-riagrails2/... · Rich Internet Applications with Grails, Part

grails.converters.*

classApiController {

// injectedservices

defsearchService

defstoryService

def search ={

defresults= null

deftagResults = null

if(params.tag){tagResults =searchService.searchTag(params.tag)

}def

catResults = nullif

(params.category){catResults =searchService.listCategory(params.category)

}if

(params.tag &&params.category){

deftagMap = [:]tagResults.each{story ->tagMap[story.id]= story

}results =catResults.findAll{ tagMap[it.id]!= null}

} else {if

(params.category){results =catResults

}else {results =tagResults

}}

renderresults as JSON

}}

Listing 2 only shows the new search method. There are two request parameters thatit expects: tag and category. It can handle either or both. These parameters, likeall request parameters in a Grails application, are exposed through the paramsobject. If the tag parameter is present, then the searchTag method is invoked onthe search service. If the category parameter is present, then the listCategorymethod is invoked on the search service. If both parameters are present (if

ibm.com/developerWorks developerWorks®

Grails and the Google Web Toolkit© Copyright IBM Corporation 2008. All rights reserved. Page 3 of 25

Page 4: Rich Internet Applications with Grails, Part 2: Grails and ...download.boulder.ibm.com/ibmdl/pub/software/dw/web/wa-riagrails2/... · Rich Internet Applications with Grails, Part

params.tag and params.category), then things get interesting.

We only want to show the stories that are common to both lists of stories returnedfrom the calls to the search service. So first you create an empty map using the [:]notation. This is a HashMap from Java. You then iterate over the list from the storieswith the given tag, putting each into the map using the ID of the story as the key.Use the standard Groovy syntax for a closure. Then you find all of the stories fromthe category search whose ID is present in the map you just created. Use theconvenient findAll method that Groovy adds to lists, and once again use aclosure. This time use Groovy's shorthand notation (the 'it' object) for the closure.Finally, whatever the results are, use the JSON converter from Grails to turn the listinto a JSON object.

In the previous article (see Resources), you saw how easy Grails makes it to renderdata as XML, but as you can see, Grails makes it just as easy to render as JSON.You can now test the new Web service. Following the Grails conventions, you knowthe URL to it will be http://<root>/digg/api/search. Here is some sample output fordoing a search where category is equal to "technology," as shown in Listing 3.

Listing 3. Sample search output

[{"id":1,"class":"Story","category":"technology","description":"Howto geta ternaryoperator inScala","link":"http://blog.tmorris.net/does-scala-have-javas-ternary-operator/","tags":"programmingscala","title":"DoesScala haveJava's ternaryoperator?","votesAgainst":0,"votesFor":0},{"id":3,"class":"Story","category":"technology","description":"Newanimationsavailable in theFlex 4 'Gumbo'release.","link":"http://graphics-geek.blogspot.com/2008/10/flex-specificanimations-posted.html","tags":"flashflex","title":"FlexSpecificAnimationsPosted","votesAgainst":0,"votesFor":0}]

This is standard JSON and is exactly what you would expect. You get an array ofobjects, where each JSON object represents a story. One interesting thing youshould notice is that the Grails serializer adds a class attribute that is the Groovyclass of your object. You will not need this in your application here because the list ishomogeneous, but you could imagine scenarios where this metadata would be veryuseful. Now that you've modified the Web services, you can start building a newapplication that consumes this service using the GWT.

developerWorks® ibm.com/developerWorks

Grails and the Google Web ToolkitPage 4 of 25 © Copyright IBM Corporation 2008. All rights reserved.

Page 5: Rich Internet Applications with Grails, Part 2: Grails and ...download.boulder.ibm.com/ibmdl/pub/software/dw/web/wa-riagrails2/... · Rich Internet Applications with Grails, Part

Search application with GWT

We are ready to create a new application for searching stories from the Digg cloneapplication. Like the Flex-based application, this will be a completely client-sideapplication that will call your Grails-powered services. This time, however, you willuse the GWT. This allows you to program all of your application in Java, but GWTwill compile it into extremely efficient JavaScript that will run on the client. Let's startby looking at the entry point to the GWT-powered application.

Search entry point

The entry point into a GWT application is a Java class whose compiled JavaScript isthe script for a given page. It is responsible for creating the user interface andhandling interactions. In this case you need to create a form the user can fill out tospecify a search query, as well the result of those queries. Take a look at this codein Listing 4.

Listing 4. The DiggApp class

public classDiggAppimplementsEntryPoint {

privatestatic finalString[][]CATEGORIES = {

{"Technology","technology" }, {"World &Business","business" },

{"Science","science" }, {"Gaming", "games"},

{"Lifestyle","lifestyle" }, {"Entertainment","entertainment"},

{"Sports","sports" }, {"Offbeat","miscellaneous" }};

private finalHorizontalPanelsearchPanel =createSearchForm();

private final

ibm.com/developerWorks developerWorks®

Grails and the Google Web Toolkit© Copyright IBM Corporation 2008. All rights reserved. Page 5 of 25

Page 6: Rich Internet Applications with Grails, Part 2: Grails and ...download.boulder.ibm.com/ibmdl/pub/software/dw/web/wa-riagrails2/... · Rich Internet Applications with Grails, Part

VerticalPanelresultsPanel =newVerticalPanel();

public voidonModuleLoad() {RootPanel.get().add(searchPanel);RootPanel.get().add(resultsPanel);

}private

HorizontalPanelcreateSearchForm(){HorizontalPanelpanel = newHorizontalPanel();panel.setTitle("Searchfor Stories");

LabeltagLabel = newLabel("Tag:");

finalTextBox tagBox =new TextBox();panel.add(tagLabel);panel.add(tagBox);

LabelcatLabel = newLabel("Category:");

finalListBox catBox =new ListBox();catBox.addItem("");

for(String[]category :CATEGORIES){catBox.addItem(category[0],category[1]);

}panel.add(catLabel);panel.add(catBox);

ButtonsearchBtn = newButton("Search");searchBtn.addClickListener(newClickListener(){public voidonClick(Widgetsender) {search(tagBox.getText(),catBox.getValue(catBox.getSelectedIndex()));

}});

panel.add(searchBtn);return

panel;}

}

The onModuleLoad method is invoked when the page is loaded. In this case itcreates a search form with a text box for entering tags, a drop-down list ofcategories, and a search button for requesting a search. It also creates an emptypanel for showing search results. The search method is invoked when the searchbutton is clicked. The code for that is shown in Listing 5.

developerWorks® ibm.com/developerWorks

Grails and the Google Web ToolkitPage 6 of 25 © Copyright IBM Corporation 2008. All rights reserved.

Page 7: Rich Internet Applications with Grails, Part 2: Grails and ...download.boulder.ibm.com/ibmdl/pub/software/dw/web/wa-riagrails2/... · Rich Internet Applications with Grails, Part

Listing 5. The DiggApp search method

private finalvoidsearch(Stringtag, Stringcategory){resultsPanel.clear();Story.search(tag,category, newRequestCallback(){

publicvoidonError(Requestrequest,Throwableexception) {

Labellabel = newLabel("Sorrythere was anerror");resultsPanel.add(label);

}public

voidonResponseReceived(Requestrequest, Responseresponse) {List<Story>stories =Story.fromJson(response.getText());SearchTable grid= newSearchTable(stories);resultsPanel.add(grid);

}});

}

This uses a search method on the Story class. The Story class acts as the modelin the system, very similar to the Story class created in the Flex application fromthe first part of this series. It has a static search method and acts as a data model. Itis shown in Listing 6.

Listing 6. The Story class

public classStory {

privatestatic finalString BASE_URL ="/digg/api/search?";

private intid;

privateString link;

privateString title;

private

ibm.com/developerWorks developerWorks®

Grails and the Google Web Toolkit© Copyright IBM Corporation 2008. All rights reserved. Page 7 of 25

Page 8: Rich Internet Applications with Grails, Part 2: Grails and ...download.boulder.ibm.com/ibmdl/pub/software/dw/web/wa-riagrails2/... · Rich Internet Applications with Grails, Part

Stringdescription;

privateString tags;

privateString category;

private intvotesFor;

private intvotesAgainst;

publicStory(JSONObjectobj){

id =(int)obj.get("id").isNumber().doubleValue();

link =obj.get("link").isString().stringValue();

title =obj.get("title").isString().stringValue();description =obj.get("description").isString().stringValue();

tags =obj.get("tags").isString().stringValue();

category=obj.get("category").isString().stringValue();

votesFor= (int)obj.get("votesFor").isNumber().doubleValue();votesAgainst =(int)obj.get("votesAgainst").isNumber().doubleValue();

}

public staticvoid search(finalString tag, finalString category,finalRequestCallbackcallback){

Stringurl =buildRequest(tag,category);RequestBuilderbuilder =

newRequestBuilder(RequestBuilder.GET,url);

try {builder.sendRequest(null,newRequestCallback(){public voidonError(Requestrequest,Throwableexception) {callback.onError(request,exception);

}public voidonResponseReceived(Requestrequest, Responseresponse) {callback.onResponseReceived(request,

developerWorks® ibm.com/developerWorks

Grails and the Google Web ToolkitPage 8 of 25 © Copyright IBM Corporation 2008. All rights reserved.

Page 9: Rich Internet Applications with Grails, Part 2: Grails and ...download.boulder.ibm.com/ibmdl/pub/software/dw/web/wa-riagrails2/... · Rich Internet Applications with Grails, Part

response);}

});} catch

(RequestExceptione) {callback.onError(null,e);

}}

}

Note that this is only a partial listing of the class; some helper methods and thegetters and setters have been omitted. The search method takes the tag andcategory and also a RequestCallback. It then uses the GWT RequestBuilderclass to create and send an HTTP request to the Web service. RequestCallbackis an interface in GWT needed for sending asynchronous HTTP requests. TheStory.search method simply delegates the RequestCallback passed in to it.So in this case it will execute the RequestCallback created in Listing 5. Note thatin both Listing 5 and Listing 6, we created an anonymous inner class thatimplemented the RequestCallback interface. This is a common technique in GWT(and in Java UI programming in general) because it gives you access to the fieldsand methods of the enclosing class. Going back to Listing 5 again, you can see thatyou get the response text and parse it into a list of Story objects using theStory.fromJson method. This is shown in Listing 7.

Listing 7. The Story.fromJson method

public staticList<Story>fromJson(StringjsonText){

JSONValue val=JSONParser.parse(jsonText);

JSONArrayarray =val.isArray();

List<Story>stories = newArrayList<Story>(array.size());

for (inti=0;i<array.size();i++){

Storystory = newStory(array.get(i).isObject());stories.add(story);

}return

stories;}

This method uses GWT's JSONParser class. It creates an array of JSON objectsand passes each object into the constructor of the Story class (shown in Listing 6).Going back to Listing 5 again, you see that once you have the list of story objects,you use it to create a SearchTable object. This is a custom widget and is shown in

ibm.com/developerWorks developerWorks®

Grails and the Google Web Toolkit© Copyright IBM Corporation 2008. All rights reserved. Page 9 of 25

Page 10: Rich Internet Applications with Grails, Part 2: Grails and ...download.boulder.ibm.com/ibmdl/pub/software/dw/web/wa-riagrails2/... · Rich Internet Applications with Grails, Part

Listing 8.

Listing 8. The SearchTable widget

public classSearchTableextends FlexTable{

privateList<Story>stories;

publicSearchTable(List<Story>stories) {

super();this.stories =stories;this.buildTable();

}private void

buildTable(){this.setBorderWidth(2);this.setText(0,0, "story");this.setText(0,1, "category");this.setText(0,2,"description");

if(stories.size()== 0){showMessage("Sorrythere were noresults");

} else {for

(inti=0;i<stories.size();i++){Story story =stories.get(i);setWidget(i+1, 0,story.getTitleLink());setText(i+1, 1,story.getCategory());setText(i+1, 2,story.getDescription());

}}

}private void

showMessage(Stringmsg){setText(1,0,msg);getFlexCellFormatter().setColSpan(1,0, 3);

}}

This class extends the core GWT class, FlexTable. It simply iterates over the listof stories and populates a simple table. If there are no stories, then it shows a simplemessage saying as much. You now have created all of the code for the application,

developerWorks® ibm.com/developerWorks

Grails and the Google Web ToolkitPage 10 of 25 © Copyright IBM Corporation 2008. All rights reserved.

Page 11: Rich Internet Applications with Grails, Part 2: Grails and ...download.boulder.ibm.com/ibmdl/pub/software/dw/web/wa-riagrails2/... · Rich Internet Applications with Grails, Part

but there is one more thing you need to do. The Story class used GWT's HTTPlibrary and JSON library for sending requests to the Web service and for parsing theresponse from the service. You need to make these available to the compiler byadding it to the module definition for the application. This is shown in Listing 9.

Listing 9. The module definition

<module>

<!--Inherit the coreWeb Toolkitstuff.-->

<inheritsname='com.google.gwt.user.User'/>

<!--Inherit thedefault GWT stylesheet. You canchange -->

<!-- thetheme of your GWTapplication byuncommenting-->

<!-- anyone of thefollowing lines.-->

<inheritsname='com.google.gwt.user.theme.standard.Standard'/>

<!--<inheritsname='com.google.gwt.user.theme.chrome.Chrome'/>-->

<!--<inheritsname='com.google.gwt.user.theme.dark.Dark'/>-->

<!-- Othermodule inherits-->

<inheritsname="com.google.gwt.http.HTTP"/>

<inheritsname="com.google.gwt.json.JSON"/>

<!--Specify the appentry pointclass.--><entry-pointclass='org.developerworks.digg.client.DiggApp'/>

<!--Specify theapplicationspecific stylesheet.

ibm.com/developerWorks developerWorks®

Grails and the Google Web Toolkit© Copyright IBM Corporation 2008. All rights reserved. Page 11 of 25

Page 12: Rich Internet Applications with Grails, Part 2: Grails and ...download.boulder.ibm.com/ibmdl/pub/software/dw/web/wa-riagrails2/... · Rich Internet Applications with Grails, Part

--><stylesheet

src='DiggApp.css'/></module>

This is mostly just the file that is generated by the GWT applicationCreator script, butyou have added two lines to it. Those are the two lines after the 'Other moduleinherits' comment in Listing 9. All you have done is add the two GWT libraries: HTTPand JSON. Now the application is ready to be compiled into JavaScript and bedeployed.

GWT deployment

It is common to see GWT code as part of a Java Web application, so it getscombined into a WAR file. In this case you are only using the client-side parts ofGWT—in other words, just HTML, CSS, and JavaScript. This lets you use GWTindependent of server technologies. All you need to do is compile the Java toJavaScript, take the results, and combine it with any Web application.

When you created the GWT application (using GWT's applicationCreator script), acompiler script was created for you. It is an executable, so it can be invoked simply,as shown in Listing 10.

Listing 10. Compiling GWT application

$./DiggApp-compileCompiling moduleorg.developerworks.digg.DiggApp2008-11-0819:56:14.962java[1300:c1b]

[JavaCocoaComponentcompatibilitymode]: Enabled2008-11-0819:56:14.963java[1300:c1b][JavaCocoaComponentcompatibilitymode]:

Settingtimeout for SWTto 0.100000CompilationsucceededLinkingcompilation into./www/org.developerworks.digg.DiggApp

Now you just copy this folder (the one called org.developerworks.digg.DiggApp) to

developerWorks® ibm.com/developerWorks

Grails and the Google Web ToolkitPage 12 of 25 © Copyright IBM Corporation 2008. All rights reserved.

Page 13: Rich Internet Applications with Grails, Part 2: Grails and ...download.boulder.ibm.com/ibmdl/pub/software/dw/web/wa-riagrails2/... · Rich Internet Applications with Grails, Part

the Web application. Now recall that GWT runs as JavaScript, and so any calls aGWT application makes to remote servers is limited by the same-origin policy. Thesimplest thing to do is deploy the GWT application as part of the Grails application.To do this, simply copy it to the web-app folder in the Grails application, as shown inFigure 1.

Figure 1. GWT application deployed to Grails

ibm.com/developerWorks developerWorks®

Grails and the Google Web Toolkit© Copyright IBM Corporation 2008. All rights reserved. Page 13 of 25

Page 14: Rich Internet Applications with Grails, Part 2: Grails and ...download.boulder.ibm.com/ibmdl/pub/software/dw/web/wa-riagrails2/... · Rich Internet Applications with Grails, Part

Now you can run the new search application by opening it in a browser. Using theGrails conventions, the URL will behttp://<root>/digg/org.developerworks.digg.DiggApp/DiggApp.html. It should looksomething like Figure 2.

Figure 2. The search application

developerWorks® ibm.com/developerWorks

Grails and the Google Web ToolkitPage 14 of 25 © Copyright IBM Corporation 2008. All rights reserved.

Page 15: Rich Internet Applications with Grails, Part 2: Grails and ...download.boulder.ibm.com/ibmdl/pub/software/dw/web/wa-riagrails2/... · Rich Internet Applications with Grails, Part

Figure 2 shows the application with only the search form being displayed. Entereither a tag or a category (or both) to perform a search. The result is shown in Figure3.

Figure 3. The search application with search results

So there is the application! This is a pretty typical GWT application using its corecomponents. Those components provide a thin wrapper on top of standard HTML.This makes them fast and lightweight, but a little ... underwhelming, at least whencompared to a lot of JavaScript-based widget kits (or what you get with Flex). Luckilyyou have some options, namely Ext GWT.

Using Ext GWT widgets

The Ext JS library is a very popular JavaScript library for creating applications. It has

ibm.com/developerWorks developerWorks®

Grails and the Google Web Toolkit© Copyright IBM Corporation 2008. All rights reserved. Page 15 of 25

Page 16: Rich Internet Applications with Grails, Part 2: Grails and ...download.boulder.ibm.com/ibmdl/pub/software/dw/web/wa-riagrails2/... · Rich Internet Applications with Grails, Part

numerous rich widgets, as well as utility methods for common JavaScript tasks. Ithas also been translated into Java for use with the Google Web Toolkit under thename of Ext GWT. First you need to configure the application to use Ext GWT.

Setting up Ext GWT

Setup with Ext GWT is pretty simple. First, you need the Ext GWT JAR (gxt,jar, partof the Ext GWT download) to be on your classpath. For the application, you createda lib directory and copied gxt.jar to it. You now need to add it to the compiler'sclasspath, so modify the DiggApp-compile script by adding './lib/gxt.jar' to theclasspath there, as shown in Listing 11.

Listing 11. Modified DiggApp-compile script

#!/bin/shAPPDIR=`dirname$0`;java-XstartOnFirstThread-Xmx256M -cp"$APPDIR/src:$APPDIR/bin:/Users/michael/lib/gwt-mac-1.5.3/gwt-user.jar:/Users/michael/lib/gwt-mac-1.5.3/gwt-dev-mac.jar:./lib/gxt.jar"com.google.gwt.dev.GWTCompiler-out"$APPDIR/www""$@"org.developerworks.digg.DiggApp;

Next, you need to make slight modifications to the base HTML page that GWTgenerates. This can be found in the /public directory. The modified version is shownin Listing 12.

Listing 12. Modified DiggApp.html

<!DOCTYPE htmlPUBLIC"-//W3C//DTD HTML3.2 Final//EN">

<html><head>

<metahttp-equiv="content-type"content="text/html;charset=UTF-8">

<!---->

<!-- Anytitle is fine-->

<!----><title>DiggApp</title>

<!--

developerWorks® ibm.com/developerWorks

Grails and the Google Web ToolkitPage 16 of 25 © Copyright IBM Corporation 2008. All rights reserved.

Page 17: Rich Internet Applications with Grails, Part 2: Grails and ...download.boulder.ibm.com/ibmdl/pub/software/dw/web/wa-riagrails2/... · Rich Internet Applications with Grails, Part

--><!-- This

script loads yourcompiled module.-->

<!-- If youadd any GWT metatags, they must-->

<!-- be addedbefore this line.-->

<!---->

<scripttype="text/javascript"language="javascript"src="org.developerworks.digg.DiggApp.nocache.js"></script>

<linkrel="stylesheet"type="text/css"href="css/ext-all.css"/></head>

<!----><!-- The body

can havearbitrary html,or --><!-- you can

leave the bodyempty if you want--><!-- to create

a completelydynamic UI.--><!--

--><body>

<!--OPTIONAL: includethis if you wanthistory support-->

<iframesrc="javascript:''"id="__gwt_historyFrame"tabIndex='-1'style="position:absolute;width:0;height:0;border:0"></iframe>

</body></html>

Two modifications have been made. First, you changed the DOCTYPE to HTML 3.2,as this is what Ext expects. Next, you added the CSS stylesheet that Ext needs:"css/ext-all.css". Note, you do not need to actually copy this CSS file anywhere; itwill be created by the compiler when it sees that the application uses the Ext GWTmodule. That brings us to the last modification: You need to add the Ext GWTmodule to the module definition. This is shown in Listing 13.

ibm.com/developerWorks developerWorks®

Grails and the Google Web Toolkit© Copyright IBM Corporation 2008. All rights reserved. Page 17 of 25

Page 18: Rich Internet Applications with Grails, Part 2: Grails and ...download.boulder.ibm.com/ibmdl/pub/software/dw/web/wa-riagrails2/... · Rich Internet Applications with Grails, Part

Listing 13. Module definition with GXT support

<module>

<!--Inherit the coreWeb Toolkitstuff.-->

<inheritsname='com.google.gwt.user.User'/>

<!--Inherit thedefault GWT stylesheet. You canchange -->

<!-- thetheme of your GWTapplication byuncommenting-->

<!-- anyone of thefollowing lines.-->

<inheritsname='com.google.gwt.user.theme.standard.Standard'/>

<!--<inheritsname='com.google.gwt.user.theme.chrome.Chrome'/>-->

<!--<inheritsname='com.google.gwt.user.theme.dark.Dark'/>-->

<!-- Othermodule inherits-->

<inheritsname="com.google.gwt.http.HTTP"/>

<inheritsname="com.google.gwt.json.JSON"/>

<inheritsname='com.extjs.gxt.ui.GXT'/>

<!--Specify the appentry pointclass.--><entry-pointclass='org.developerworks.digg.client.DiggApp'/>

<!--Specify theapplicationspecific stylesheet.-->

<stylesheetsrc='DiggApp.css'/>

developerWorks® ibm.com/developerWorks

Grails and the Google Web ToolkitPage 18 of 25 © Copyright IBM Corporation 2008. All rights reserved.

Page 19: Rich Internet Applications with Grails, Part 2: Grails and ...download.boulder.ibm.com/ibmdl/pub/software/dw/web/wa-riagrails2/... · Rich Internet Applications with Grails, Part

</module>

If you compare Listing 13 to Listing 9, there is only one difference. The module nowinherits from the com.extjs.gxt.ui.GXT module. This means that Ext GWT isconfigured, and you can use Ext's widgets.

Richer search results

Ext includes a Grid widget that is much richer than the GWT table. It allows for manyof the same things that the DataGrid in Flex allows for, like sortable and resizablecolumns. You will use this as a basis for a new search results display widget, asshown in Listing 14.

Listing 14. The StoryGrid widget

public classStoryGrid extendsLayoutContainer {

publicStoryGrid(List<Story>stories){this.setLayout(newFlowLayout(10));this.setSize(750,300);ListStore<BaseModelData>store =this.buildDataModel(stories);Grid<BaseModelData>grid =

newGrid<BaseModelData>(store,createColumnModel());grid.setBorders(true);add(grid);

}

privateColumnModelcreateColumnModel(){List<ColumnConfig>configs = newArrayList<ColumnConfig>();ColumnConfigcolumn = newColumnConfig();column.setId("titleLink");column.setHeader("Story");column.setWidth(200);configs.add(column);

column =newColumnConfig();column.setId("category");column.setHeader("Category");column.setWidth(100);configs.add(column);

column =new

ibm.com/developerWorks developerWorks®

Grails and the Google Web Toolkit© Copyright IBM Corporation 2008. All rights reserved. Page 19 of 25

Page 20: Rich Internet Applications with Grails, Part 2: Grails and ...download.boulder.ibm.com/ibmdl/pub/software/dw/web/wa-riagrails2/... · Rich Internet Applications with Grails, Part

ColumnConfig();column.setId("description");column.setHeader("Description");column.setWidth(400);configs.add(column);

returnnewColumnModel(configs);

}

privateListStore<BaseModelData>buildDataModel(List<Story>stories){ListStore<BaseModelData>data = newListStore<BaseModelData>();

for(Story story :stories){BaseModelDatamodel = newBaseModelData(story.properties());data.add(model);

}return

data;}

}

A Grid in Ext needs two basic things: column definitions and a data store. ThecreateColumnModel method creates the column definitions for the Grid. It is a listof ColumnConfig objects. The key thing about ColumnConfig is its ID property.This tells the Grid the name of the property of the data model to use. The data modelis created by the buildDataModel method. You use the GXT classBaseModelData. This class just wraps around a Java Map. In this case you usedthe properties() method from the Story class. Take a look at that in Listing 15.

Listing 15. Story.properties method

public classStory {

publicMap<String,Object>properties(){Map<String,Object>props = newHashMap<String,Object>();props.put("id",id);props.put("link",link);props.put("title",title);props.put("description",description);props.put("tags",tags);props.put("category",category);props.put("votesFor",votesFor);props.put("votesAgainst",votesAgainst);props.put("titleLink",getTitleLink().getHTML());

returnprops;

developerWorks® ibm.com/developerWorks

Grails and the Google Web ToolkitPage 20 of 25 © Copyright IBM Corporation 2008. All rights reserved.

Page 21: Rich Internet Applications with Grails, Part 2: Grails and ...download.boulder.ibm.com/ibmdl/pub/software/dw/web/wa-riagrails2/... · Rich Internet Applications with Grails, Part

}}

Now if you go back to the ColumnConfig objects created in thecreateColumnModel method in Listing 14, you see that when you setColumnConfig's ID to "titleLink", then that string was used as a key into the Mapcreated in Listing 15. Now you can simply swap out the SearchTable for theStoryGrid back in Listing 5, recompile, and deploy. The application now looks alittle different, as shown in Figure 4.

Figure 4. Improved search application

From here you could further enhance the UI. For instance, you could add morecolumns to the Grid. You could customize what columns can be used for sorting,which ones can be resized, and which ones provide access to the customizationmenu. You could even replace the search form widgets with more widgets from Ext.The sky's the limit.

Summary

In the first article in this series, you created an SOA back end using Grails and a UIusing Flex. This time you took that back end and added a new Web service to it.Once again Grails and Groovy made this very easy to do. You created a new searchapplication using GWT and saw how GWT can work with any Web service using itsHTTP and JSON libraries. Finally, you looked at Ext GWT as a way to add richer UIwidgets to GWT. Now you can create feature-rich applications in pure Java that iscompiled into JavaScript that runs completely on the client.

ibm.com/developerWorks developerWorks®

Grails and the Google Web Toolkit© Copyright IBM Corporation 2008. All rights reserved. Page 21 of 25

Page 22: Rich Internet Applications with Grails, Part 2: Grails and ...download.boulder.ibm.com/ibmdl/pub/software/dw/web/wa-riagrails2/... · Rich Internet Applications with Grails, Part

Downloads

Description Name Size Download method

Example Grails Application digg.zip 1101KB HTTP

Example GWT app source digg-GWT.zip 2990KB HTTP

Information about download methods

developerWorks® ibm.com/developerWorks

Grails and the Google Web ToolkitPage 22 of 25 © Copyright IBM Corporation 2008. All rights reserved.

Page 23: Rich Internet Applications with Grails, Part 2: Grails and ...download.boulder.ibm.com/ibmdl/pub/software/dw/web/wa-riagrails2/... · Rich Internet Applications with Grails, Part

Resources

Learn

• Part 1 of this series explores how to build a Web application using Grails andFlex.

• The application created in this article can be deployed to any application server.See an example of this in the developerWorks article "Apache Geronimo onGrails" (Michael Galpin, developerWorks, July 2008).

• "Mastering Grails: Build your first Grails application" (Scott Davis,developerWorks, January 2008) gives an introduction to creating Grailsapplications.

• "Mastering Grails: GORM: Funny name, serious technology" (Scott Davis,developerWorks, February 2008) shows you the power of GORM in action.

• "RESTful Web services and their Ajax-based clients" (Shailesh K. Mishra,developerWorks, July 2007) explores combining RESTful Web services, like theones developer here, with Ajax applications.

• "Introducing Project Zero: RESTful applications in an SOA" (Roland Barcia andSteve Ims, developerWorks, January 2008) shows how REST-based services fitin perfectly in an SOA system.

• "Exploring the Google Web Toolkit" (Philip McArthy, developerWorks, June2006) gives an introduction to the Google Web Toolkit.

• "Build an Ajax-enabled application using the Google Web Toolkit and ApacheGeronimo" (Michael Galpin, developerWorks, May 2007) explores using theGoogle Web Toolkit as part of a Java Web application.

• "Build an Ajax application using Google Web Toolkit, Apache Derby, andEclipse" (Noel Rappin, developerWorks, December 2006) explains how GWT isdesigned to work with Eclipse. Learn how to use Eclipse with it.

• "Integrate XForms with the Google Web Toolkit" (Michael Galpin,developerWorks, September 2007) explains that GWT can integrate with anyJavaScript using its JSNI interface. See some of the possibilities this opens upin this developerWorks article.

• Read the Ext GWT reference documentation and samples on the GXT site.

• "Build Ajax applications with Ext JS" (John Fronckowiak, developerWorks, July2008) shows that Ext GWT is of course based on Ext JS. Learn all about ExtJS.

• "Mastering Grails: Changing the view with Groovy Server Pages" (Scott Davis,developerWorks, March 2008): Don't like the UI of this app? Learn all the ways

ibm.com/developerWorks developerWorks®

Grails and the Google Web Toolkit© Copyright IBM Corporation 2008. All rights reserved. Page 23 of 25

Page 24: Rich Internet Applications with Grails, Part 2: Grails and ...download.boulder.ibm.com/ibmdl/pub/software/dw/web/wa-riagrails2/... · Rich Internet Applications with Grails, Part

to change it.

• "Practically Groovy: Reduce code noise with Groovy" (Scott Hickey,developerWorks, September 2006): Are you a fan of the succinctness thatGroovy provides? Learn all about its concise syntax.

• Groovy is another promising language that compiles to Java bytecode. Readabout creating XML with it in the developerWorks article, "Practically Groovy:Mark it up with Groovy Builders" (Andrew Glover, developerWorks, April 2005).

• Grails.org: The best place for Grails information is the project's site.

• The Grails manual: Every Grails developer's best friend.

• Take a look at a series of rough benchmarks to see how Grails has significantadvantages over Rails by advantages being on top of Java, Hibernate, andSpring.

• Deploying an application on Geronimo is easy, but there is a lot that goes on.Learn all about it in the developerWorks article, "Understand Geronimo'sdeployment architecture" (Hemapani Srinath Perera, developerWorks, August2005).

• "Remotely deploy Web applications on Apache Geronimo" (Michael Galpin,developerWorks, May 2006) shows how to deploy your Grails applications toremote instances of Geronimo.

• Learn about other alternative languages running on the JVM in thedeveloperWorks article, "Invoke dynamic languages dynamically, Part 1:Introducing the Java scripting API" (Tom McQueeney, developerWorks,September 2007).

• "Build an Ajax-enabled application using the Google Web Toolkit and ApacheGeronimo" (Michael Galpin, developerWorks, May 2007) shows how Geronimocan be used with the Google Web Toolkit.

• To listen to interesting interviews and discussions for software developers,check out developerWorks podcasts.

• Stay current with developerWorks technical events and webcasts.

Get products and technologies

• Grails: This article uses Grails Version 1.0.3.

• Get the Google Web Toolkit: This article uses Version 1.5.3.

• Java SDK: This article uses Java SE 1.6_05.

• Download IBM product evaluation versions, and get your hands on applicationdevelopment tools and middleware products from DB2, Lotus, Rational, Tivoli,and WebSphere.

developerWorks® ibm.com/developerWorks

Grails and the Google Web ToolkitPage 24 of 25 © Copyright IBM Corporation 2008. All rights reserved.

Page 25: Rich Internet Applications with Grails, Part 2: Grails and ...download.boulder.ibm.com/ibmdl/pub/software/dw/web/wa-riagrails2/... · Rich Internet Applications with Grails, Part

Discuss

• Participate in developerWorks blogs and get involved in the developerWorkscommunity.

About the author

Michael GalpinMichael Galpin has been developing Web applications since the late 90's. He holds adegree in mathematics from the California Institute of Technology and is an architectat eBay in San Jose, CA.

Trademarks

Java and all Java-based trademarks and logos are trademarks of Sun Microsystems,Inc. in the United States, other countries, or both.

ibm.com/developerWorks developerWorks®

Grails and the Google Web Toolkit© Copyright IBM Corporation 2008. All rights reserved. Page 25 of 25