27
Build a dynamic organization tree using GWT and RESTful Web services Skill Level: Intermediate Bruce Sun ([email protected]) Java Architect National Center for Atmospheric Research 19 Jan 2010 Learn why the Google Web Toolkit (GWT) is ideal for Java™ developers to build rich and responsive desktop-like interfaces, especially large-scale Web applications. In this article, I use GWT Tree widgets to display an organizational structure of a company. I implement an RPC proxy to integrate with RESTful Web services, which provides organizational data and employee data. I also discuss a lazy loading strategy to ensure a faster start up, to reduce the data download time, and to minimize memory usage. Introduction The trend of Web application development over the last few years has been to create rich Internet applications, most of which are implemented using Asynchronous JavaScript + XML (Ajax). But, it hasn't been easy because of the nature of JavaScript coding. It is especially difficult to build large-scale Web applications. Here's where GWT comes into play: It lets you build rich and responsive Web interfaces using Java programming instead of Ajax. GWT also provides all the benefits of Java development, such as excellent IDE support with advanced debugging capabilities. GWT can dramatically improve your productivity and enrich your users' experience. In this article, I explain how to create a GWT application in Eclipse and how to use the GWT Tree and TreeItem widgets to create a sample organizational structure at the University Corporation of Atmosphere Research (UCAR). I explain how to implement lazy loading, how to integrate with RESTful Web services, and how to implement GWT callbacks and custom exceptions. JSON has been used as data format for RESTful Web services. Build a dynamic organization tree using GWT and RESTful Web services © Copyright IBM Corporation 2010. All rights reserved. Page 1 of 27

Build a dynamic organization tree using GWT and RESTful ...public.dhe.ibm.com/software/dw/ajax/wa-aj-gmt/wa-aj-gmt-pdf.pdf · Learn why the Google Web Toolkit (GWT) is ideal for Java™

  • Upload
    others

  • View
    6

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Build a dynamic organization tree using GWT and RESTful ...public.dhe.ibm.com/software/dw/ajax/wa-aj-gmt/wa-aj-gmt-pdf.pdf · Learn why the Google Web Toolkit (GWT) is ideal for Java™

Build a dynamic organization tree using GWT andRESTful Web servicesSkill Level: Intermediate

Bruce Sun ([email protected])Java ArchitectNational Center for Atmospheric Research

19 Jan 2010

Learn why the Google Web Toolkit (GWT) is ideal for Java™ developers to build richand responsive desktop-like interfaces, especially large-scale Web applications. Inthis article, I use GWT Tree widgets to display an organizational structure of acompany. I implement an RPC proxy to integrate with RESTful Web services, whichprovides organizational data and employee data. I also discuss a lazy loadingstrategy to ensure a faster start up, to reduce the data download time, and tominimize memory usage.

Introduction

The trend of Web application development over the last few years has been tocreate rich Internet applications, most of which are implemented usingAsynchronous JavaScript + XML (Ajax). But, it hasn't been easy because of thenature of JavaScript coding. It is especially difficult to build large-scale Webapplications. Here's where GWT comes into play: It lets you build rich andresponsive Web interfaces using Java programming instead of Ajax. GWT alsoprovides all the benefits of Java development, such as excellent IDE support withadvanced debugging capabilities. GWT can dramatically improve your productivityand enrich your users' experience. In this article, I explain how to create a GWTapplication in Eclipse and how to use the GWT Tree and TreeItem widgets tocreate a sample organizational structure at the University Corporation ofAtmosphere Research (UCAR). I explain how to implement lazy loading, how tointegrate with RESTful Web services, and how to implement GWT callbacks andcustom exceptions. JSON has been used as data format for RESTful Web services.

Build a dynamic organization tree using GWT and RESTful Web services© Copyright IBM Corporation 2010. All rights reserved. Page 1 of 27

Page 2: Build a dynamic organization tree using GWT and RESTful ...public.dhe.ibm.com/software/dw/ajax/wa-aj-gmt/wa-aj-gmt-pdf.pdf · Learn why the Google Web Toolkit (GWT) is ideal for Java™

Software requirements

To begin, you'll need to download the following software packages and install themaccording to the installation guides on their respective Web sites. (See Resourcesfor links.)

1. Eclipse IDE for Java EE Developers Galileo (Eclipse 3.5)

2. GWT 2.0

3. GWT plug-in for Eclipse

4. MySQL 5.1 or DB2® Express-C

5. Tomcat 6.x

RESTful Web services

RESTful Web services provide organizational data for the GWT client. In this article,I don't discuss the steps to demonstrate how to implement RESTful Web services;all you need to do is set up the database and deploy the WAR file to your Tomcatserver. You also might need to change a few database attributes such as databasehost, login, and password in the configuration file. The RESTful Web services areimplemented using the multi-tier architecture I discussed in the two articles "Amulti-tier architecture for building RESTful Web services" and "Build RESTful Webservices and dynamic Web applications with the multi-tier architecture."

Set up the database

I used MySQL Community Server 5.1 as the database for this article. However, youcould also use DB2 Express-C or others. To use MySQL, you'll find a download linkin Resources. Download and install it on your chosen host if you haven't done so.Then create a database called gwtresttutorial and a user named gwtresttutorial withthe password gwtresttutorial. Connect to the gwtresttutorial database and log in asgwtresttutorial. Download the sql script from Download and run the script to createtables and insert the data into the tables.

To connect the RESTful Web service server to a DB2 Express-C or to anotherDB2-variant database, the configuration is very similar to the one described forMySQL in Listing 1, with the following changes:

• Use the com.ibm.db2.jcc.DB2Driver as the driverClassName.

developerWorks® ibm.com/developerWorks

Build a dynamic organization tree using GWT and RESTful Web servicesPage 2 of 27 © Copyright IBM Corporation 2010. All rights reserved.

Page 3: Build a dynamic organization tree using GWT and RESTful ...public.dhe.ibm.com/software/dw/ajax/wa-aj-gmt/wa-aj-gmt-pdf.pdf · Learn why the Google Web Toolkit (GWT) is ideal for Java™

• Use jdbc:db2://<host>:<port>/<database_name> as the URL where thehost is the name of the host where DB2 Express-C is installed, port isthe port number to access the database, and database_name is thename of the database instance.

• Copy the db2jcc.jar and db2jcc_license_cu.jar files from the DB2Express-C installation directory to the WEB-INF/lib directory.

• You might need to modify the setup.sql script from the download to useDB2 syntax.

Deploy the WAR file to the Tomcat server

Download the WAR file from the Download section and save it to your Tomcatfolder: <TOMCAT_HOME>/webapps, where TOMCAT_HOME is where your Tomcatserver is installed. If you don't have Tomcat installed, you can download it fromResources.

After you deploy the WAR file to the <TOMCAT_HOME>/webapps directory, theTomcat server will unzip the WAR file into the gwtRESTTutorial folder if it is running.Check<TOMCAT_HOME>/webapps/gwtRESTTutorial/WEB-INF/classes/applicationContext.xml(Listing 1) to make sure the values to configure the dataSource bean match theones you are using for your MySQL database. Note that you might need to restartthe Tomcat server if any changes are made.

Listing 1. Configure the dataSource bean in applicationContext.xml

1. <bean id="dataSource"class="org.springframework.jdbc.datasource.DriverManagerDataSource">2. <property name="driverClassName" value="com.mysql.jdbc.Driver"/>3. <property name="url" value="jdbc:mysql://localhost:3306/gwtresttutorial"/>4. <property name="username" value="gwtresttutorial"/>5. <property name="password" value="gwtresttutorial"/>6. </bean>

Access RESTful Web services

Two RESTful Web services have been implemented for this article. The first one isto provide information about an employee. The URI to access this Web service is:http://localhost:8080/gwtRESTTutorial/rrh/employees/<EMP_ID>, where EMP_ID isthe ID for an employee. A JSON string that contains the detailed employee data isreturned. Listing 2 gives an example of the returned JSON string.

Listing 2. Sample JSON data returned from employee RESTful Web service

1. {2. "id":20,3. "firstName":"Robert",

ibm.com/developerWorks developerWorks®

Build a dynamic organization tree using GWT and RESTful Web services© Copyright IBM Corporation 2010. All rights reserved. Page 3 of 27

Page 4: Build a dynamic organization tree using GWT and RESTful ...public.dhe.ibm.com/software/dw/ajax/wa-aj-gmt/wa-aj-gmt-pdf.pdf · Learn why the Google Web Toolkit (GWT) is ideal for Java™

4. "nickName":"Bob",5. "lastName":"Sunny",6. "title":"SE",7. "phone":"303-123-1234",8. "email":[email protected]. }

The second Web service is to provide the information about an organizational unit.Its URI is http://localhost:8080/gwtRESTTutorial/rrh/organizations/<ORG_ID>, whereORG_ID is the ID for an organizational unit. Like the employee data, a JSON stringthat contains the detailed organizational data is returned (Listing 3). The detaileddata contains the ID, acronym, name, lead name, lead title, and total number ofemployees within the organization as well as its sub-organizations of all levels. Italso contains an array of data for employees working in the organizational unit and aseparate array of data for the immediate sub-organization units. The employee dataand sub-organization data contain only the ID and the display name.

Listing 3. Sample JSON data returned from organization RESTful Web service

1. {2. "id":1,3. "acronym":"NCAR",4. "name":"National Center for Atmospheric Research",5. "leadName":"Dan Bush -Director",6. "leadTitle":"Director",7. "totalEmployees":15,8. "employees":9. [{10. "id":2,11. "displayName":"Dan Bush - Director"12. },13. {14. "id":3,15. "displayName":"Lori Stanley - Deputy Director"16. }],17. "subOrgs":18. [{19. "id":3,20. "displayName":"CISL"21. },22. {23. "id":5,24. "displayName":"EOL"25. },26. {27. "id":6,28. " displayName ":"RAL"29. },30. {31. "id":4,32. "displayName":"ESSL"33. }]34. }

Create the GWT application in Eclipse

Eclipse with GWT support is the environment used for developing the GWT

developerWorks® ibm.com/developerWorks

Build a dynamic organization tree using GWT and RESTful Web servicesPage 4 of 27 © Copyright IBM Corporation 2010. All rights reserved.

Page 5: Build a dynamic organization tree using GWT and RESTful ...public.dhe.ibm.com/software/dw/ajax/wa-aj-gmt/wa-aj-gmt-pdf.pdf · Learn why the Google Web Toolkit (GWT) is ideal for Java™

application in this article. In Eclipse:

1. Select File > New > Web Application Project.

2. Enter gwtRESTTutorialView in the Project Name field andedu.ucar.cisl.gwtRESTTutorialView in the Package field in theNew Web Application Project window (see Figure 1).

3. Select Use Default SDK and choose GWT-2.0.0 or a newer version inGoogle SDKs.

Figure 1. Create the New Web Application Project

ibm.com/developerWorks developerWorks®

Build a dynamic organization tree using GWT and RESTful Web services© Copyright IBM Corporation 2010. All rights reserved. Page 5 of 27

Page 6: Build a dynamic organization tree using GWT and RESTful ...public.dhe.ibm.com/software/dw/ajax/wa-aj-gmt/wa-aj-gmt-pdf.pdf · Learn why the Google Web Toolkit (GWT) is ideal for Java™

The GWT plug-in in Eclipse automatically creates a sample remote service. You canoptionally remove it by deleting the files GreetingService.java andGreetingServiceAsync.java in the edu.ucar.cisl.gwtRESTTutorialView.client packageas well as GeetingServiceImpl.java in the edu.ucar.cisl.gwtRESTTutorialView.serverpackage. You will also need to remove the servlet configuration in the web.xml filefor the remote service and remove everything between <body> and </body> in theGwtRESTTutorialView.html file under the WAR folder.

developerWorks® ibm.com/developerWorks

Build a dynamic organization tree using GWT and RESTful Web servicesPage 6 of 27 © Copyright IBM Corporation 2010. All rights reserved.

Page 7: Build a dynamic organization tree using GWT and RESTful ...public.dhe.ibm.com/software/dw/ajax/wa-aj-gmt/wa-aj-gmt-pdf.pdf · Learn why the Google Web Toolkit (GWT) is ideal for Java™

The following sections cover the details about specific topics such as creating databeans, implementing the RPC proxy to access RESTful Web services and callbacks,and building the GWT Web interface. These components are located in the followingfour packages. (Create them in Eclipse if they don't exist.) The source codes areavailable for download in the Download section.

• edu.ucar.cisl.gwtRESTTutorialView.client.bean — Containsapplication Java beans for the client.

• edu.ucar.cisl.gwtRESTTutorialView.client.callback — Contains theimplementation of the callback classes.

• edu.ucar.cisl.gwtRESTTutorialView.client — Contains the moduleentry class GwtRESTTutorialView. It also contains several otherinterfaces, classes, and image files that are used to create the GWT Webinterface. The client-site classes for the RPC proxy are also located in thispackage.

• edu.ucar.cisl.gwtRESTTutorialView.server — Contains the class forthe server-side implementation of the RPC proxy.

Implement application data beans

In the article, I use a Tree widget to display an organizational structure. In GWT, aTree widget contains TreeItem widgets, which are usually used as tree nodes. Inthis case, a TreeItem widget is used as either a tree node or a tree leaf torepresent an organizational unit and an employee, respectively. I implemented anabstract base class ItemData (Listing 4), which has three properties: id,displayName, and dataReady. id is the ID for the data item and is used to buildRESTful Web service requests. It identifies the resource in the RESTful Web serviceserver. The property displayName is the name to be displayed. The propertydataReady is a flag to indicate if the detail data has been retrieved from theRESTful Web service server. It is used to help implement lazy loading. When aTreeItem widget is created, an ItemData bean is associated with the widget. Ithas only the resource ID and display name. The detail data declared in thesub-classes is loaded only when a user either selects the tree leaf or opens the treenode. An abstract method buildURI is used to build the URI for the RESTful Webservice request and will be implemented by its sub-classes, EmployeeItemData(Listing 5) and OrganizationItemData (Listing 6). EmployeeItemData containsthe detailed information for an employee, whereas OrganizationItemDatacontains the detailed information for an organizational unit.

Listing 4. edu.ucar.cisl.gwtRESTTutorialView.client.bean.ItemData

1. package edu.ucar.cisl.gwtRESTTutorialView.client.bean;

2. public abstract class ItemData {

ibm.com/developerWorks developerWorks®

Build a dynamic organization tree using GWT and RESTful Web services© Copyright IBM Corporation 2010. All rights reserved. Page 7 of 27

Page 8: Build a dynamic organization tree using GWT and RESTful ...public.dhe.ibm.com/software/dw/ajax/wa-aj-gmt/wa-aj-gmt-pdf.pdf · Learn why the Google Web Toolkit (GWT) is ideal for Java™

3. protected int id = -1;4. protected String displayName;5. protected boolean dataReady = false;

6. ...//setters and getters

7. abstract public String buildUri();8. }

Listing 5. edu.ucar.cisl.gwtRESTTutorialView.client.bean.EmployeeItemData

1. package edu.ucar.cisl.gwtRESTTutorialView.client.bean;

2. public class EmployeeItemData extends ItemData {3. protected String firstName;4. protected String lastName;5. protected String nickName;6. protected String phone;7. protected String email;8. protected String title;

9. ...//setters and getters

10. public String buildUri(){11. return "http://localhost:8080/gwtRESTTutorial/rrh/employees/" + id;12. }13. }

Listing 6.edu.ucar.cisl.gwtRESTTutorialView.client.bean.OrganizationItemData

1. package edu.ucar.cisl.gwtRESTTutorialView.client.bean;

2. public class OrganizationItemData extends ItemData {3. protected String name;4. protected String leadName;5. protected String leadTitle;6. protected int totalEmployees;

7. ...//getters and setters

8. public String buildUri() {9. return "http://localhost:8080/gwtRESTTutorial/rrh/organizations/" + id;10. }11. }

Implement the RPC proxy to request RESTful Web services

There are several strategies to integrate GWT with RESTful Web services. If theRESTful Web service server is running on the same domain and port, the obviousoption is using the GWT RequestBuilder class. However, the RequestBuilderclass can't get around the Same Original Policy (SOP) limitation, which prohibitsmaking requests to the Web services server from a different domain. To avoid theSOP limitation, I use an RPC proxy strategy. With this strategy, the GWT clientsends the RESTful Web service request to the RPC remote service, which then

developerWorks® ibm.com/developerWorks

Build a dynamic organization tree using GWT and RESTful Web servicesPage 8 of 27 © Copyright IBM Corporation 2010. All rights reserved.

Page 9: Build a dynamic organization tree using GWT and RESTful ...public.dhe.ibm.com/software/dw/ajax/wa-aj-gmt/wa-aj-gmt-pdf.pdf · Learn why the Google Web Toolkit (GWT) is ideal for Java™

passes the request to the RESTful Web service server.

Create a custom exception class

A special custom exception is needed so that the server can pass exceptions to theclient. GWT provides a very easy way to implement it. All you need to do is have thecustom exception class extend the Exception class and implement theIsSerializable interface. The custom exception is shown in Listing 7.

Listing 7.edu.ucar.cisl.gwtRESTTutorialView.client.RESTfulWebServiceException

1. package edu.ucar.cisl.gwtRESTTutorialView.client;

2. import com.google.gwt.user.client.rpc.IsSerializable;

3. public class RESTfulWebServiceException extends Exception implements IsSerializable {4. private static final long serialVersionUID = 1L;5. private String message;

6. public RESTfulWebServiceException() {7. }

8. public RESTfulWebServiceException(String message) {9. super(message);10. this.message = message;11. }

12. public RESTfulWebServiceException(Throwable cause) {13. super(cause);14. }

15. public RESTfulWebServiceException(String message, Throwable cause) {16. super(message, cause);17. this.message = message;18. }

19. public String getMessage() {20. return message;21. }22. }

Create a remote service interface

For each remote service, GWT requires two interfaces on the client side: a remoteservice interface and a remote service async interface. The remote service interfacemust extend the GWT RemoteService interface and define the signatures of theservice methods that will be exposed to the clients. The method parameters andreturn types must be serializable.

The remote service interface for this article is very simple (Listing 8). It declares onlyone method, invokeGetRESTfulWebService. The method has two parameters,uri and contentType. The former is the URI to identify the resource to request onthe RESTful Web service server. The latter indicates what content type is to beexpected for the result to be returned. The content type will be a standard HTTP

ibm.com/developerWorks developerWorks®

Build a dynamic organization tree using GWT and RESTful Web services© Copyright IBM Corporation 2010. All rights reserved. Page 9 of 27

Page 10: Build a dynamic organization tree using GWT and RESTful ...public.dhe.ibm.com/software/dw/ajax/wa-aj-gmt/wa-aj-gmt-pdf.pdf · Learn why the Google Web Toolkit (GWT) is ideal for Java™

content type such as application/json, application/xml, application/text, and so on.The method returns a string of content from the HTTP response and throws acustom exception in the case of a failure.

An annotation RemoteServiceRelativePath needs to be added to specify theURL path for the service (line 5 in Listing 8). A simple utility class is created to easilyget the instance of the async remote interface (lines 7-13 in Listing 8).

Listing 8. edu.ucar.cisl.gwtRESTTutorialView.client.RESTfulWebServiceProxy

1. package edu.ucar.cisl.gwtRESTTutorialView.client;2. import com.google.gwt.core.client.GWT;3. import com.google.gwt.user.client.rpc.RemoteService;4. import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;

5. @RemoteServiceRelativePath("RESTfulWebServiceProxy")6. public interface RESTfulWebServiceProxy extends RemoteService {7. public static class Util {8. public static RESTfulWebServiceProxyAsync getInstance() {9. RESTfulWebServiceProxyAsync10. rs=(RESTfulWebServiceProxyAsync)GWT.create(RESTfulWebServiceProxy.class);11. return rs;12. }13. }14.15. public String invokeGetRESTfulWebService(String uri, String contentType)16. throws RESTfulWebServiceException;17. }

Create a remote service asynchronous interface

A remote service asynchronous interface is based on the remote service interface. Aservice's asynchronous interface must be in the same package and have the samename, but with the suffix "Async." There is a corresponding asynchronous methodfor each remote service method. But asynchronous methods cannot have returntypes, and they must always return void. Asynchronous methods not only mustdeclare the same parameters in the same order but also an extra parameter of thegeneric type AsyncCallback<T>, where T will be return type of the remote servicemethod . Asynchronous methods don't throw the exceptions. Listing 9 is the remoteservice asynchronous interface for the sample application.

Listing 9.edu.ucar.cisl.gwtRESTTutorialView.client.RESTfulWebServiceProxyAsync

1. package edu.ucar.cisl.gwtRESTTutorialView.client;

2. import com.google.gwt.user.client.rpc.AsyncCallback;

3. public interface RESTfulWebServiceProxyAsync {4. public void invokeGetRESTfulWebService(String uri, String contentType,AsyncCallback<String> callback);5. }

developerWorks® ibm.com/developerWorks

Build a dynamic organization tree using GWT and RESTful Web servicesPage 10 of 27 © Copyright IBM Corporation 2010. All rights reserved.

Page 11: Build a dynamic organization tree using GWT and RESTful ...public.dhe.ibm.com/software/dw/ajax/wa-aj-gmt/wa-aj-gmt-pdf.pdf · Learn why the Google Web Toolkit (GWT) is ideal for Java™

Implement the proxy service on the server

Remote services are implemented in a server-side class that extends GWT'sRemoteServiceServlet class. In the RESTful Web service proxy (Listing 10), theclass implements the remote service invokeGetRESTfulWebService. Based onthe URI and content type, this method builds an HTTP request and sends it to theRESTful Web service server. If the response code is 200, it will buffer the contentfrom the HTTP response and use it as a return value for the method. Otherwise, itwill throw a custom exception. The method will catch other exceptions such asMalformedURLException and IOException and throw the custom exception sothat it can be caught by the GWT client.

Listing 10.edu.ucar.cisl.gwtRESTTutorialView.server.RESTfulWebServiceProxyImpl

1. package edu.ucar.cisl.gwtRESTTutorialView.server;

2. import java.io.BufferedReader;3. import java.io.IOException;4. import java.io.InputStream;5. import java.io.InputStreamReader;6. import java.net.HttpURLConnection;7. import java.net.MalformedURLException;8. import java.net.URL;9. import com.google.gwt.user.server.rpc.RemoteServiceServlet;10. import edu.ucar.cisl.gwtRESTTutorialView.client.RESTfulWebServiceProxy;11. import edu.ucar.cisl.gwtRESTTutorialView.client.RESTfulWebServiceException;

12. public class RESTfulWebServiceProxyImpl extends RemoteServiceServlet13. implements RESTfulWebServiceProxy {14. private static final long serialVersionUID = 1L;

15. public RESTfulWebServiceProxyImpl() { // must have16. }

17. public String invokeGetRESTfulWebService(String uri, String contentType)18. throws RESTfulWebServiceException {19. try {20. URL u = new URL(uri);21. HttpURLConnection uc = (HttpURLConnection) u.openConnection();22. uc.setRequestProperty("Content-Type", contentType);23. uc.setRequestMethod("GET");24. uc.setDoOutput(false);25. int status = uc.getResponseCode();26. if (status != 200)27. throw (new RESTfulWebServiceException("Invalid HTTP response status28. code " + status + " from web service server."));29. InputStream in = uc.getInputStream();30. BufferedReader d = new BufferedReader(new InputStreamReader(in));31. String buffer = d.readLine();32. return buffer;33. }34. catch (MalformedURLException e) {35. throw new RESTfulWebServiceException(e.getMessage(), e);36. }37. catch (IOException e) {38. throw new RESTfulWebServiceException(e.getMessage(), e);39. }40. }41. }

ibm.com/developerWorks developerWorks®

Build a dynamic organization tree using GWT and RESTful Web services© Copyright IBM Corporation 2010. All rights reserved. Page 11 of 27

Page 12: Build a dynamic organization tree using GWT and RESTful ...public.dhe.ibm.com/software/dw/ajax/wa-aj-gmt/wa-aj-gmt-pdf.pdf · Learn why the Google Web Toolkit (GWT) is ideal for Java™

Implement callbacks

Callback examples in most GWT books and online tutorials are implemented asanonymous inner classes. In this article, I created callbacks as real classes. Thereare several advantages for this approach. It makes code much cleaner. It allows theclient data to be associated with the callback class at run time. Callback classesoffer much more flexibility, extensibility, and code reuse. For example, an errorhandling method can be implemented in a callback base class so that it can be usedby all callbacks to ensure all remote service exceptions will be handled consistently.You can easily debug the code inside callback classes because not all IDEs supporttracing in the inner classes.

In this article, I created an abstract base class, RestServiceRpcCallback(Listing 11) as well as two sub-classes, EmployeeRpcCallback (Listing 12) andOrganizationRpcCallback (Listing 13). In Listing 11, the abstract base classimplements an interface AsyncCallback. The onSuccess method will be called ifthe request to the server is successful. Otherwise, the onFailure method will becalled. The onFailure method displays an error message passed over from theserver. The onSuccess method will invoke the processResponse method toprocess the string returned from the RESTful Web service server. The abstractmethod processResponse will be implemented by the sub-classes. The abstractbase class has a member treeItem that will be an instance of the TreeItemwidget in GWT and will be the client data with which the callback is associated whenthe callback class is used. This class member will contain the application object thatstores employee data or organizational data depending on what the TreeItemwidget represents. The TreeItem widget will also be used to help create sub-treesand position pop-up windows.

I created an enum type, EventType, and class member eventType. This classmember is used to keep track of which event triggers the request to the RESTfulWeb service server so that after the result comes back from the RESTful Webservice server, the callback will need it to decide how to proceed.

Listing 11.edu.ucar.cisl.gwtRESTTutorialView.client.callback.RestServiceRpcCallback

1. package edu.ucar.cisl.gwtRESTTutorialView.client.callback;

2. import com.google.gwt.user.client.rpc.AsyncCallback;3. import com.google.gwt.user.client.ui.TreeItem;4. import com.google.gwt.user.client.Window;

5. public abstract class RestServiceRpcCallback implements AsyncCallback <String> {6. TreeItem treeItem;7. public enum EventType {SELECT_EVENT, STATE_CHANGE_EVENT};8. protected EventType eventType;

9. public EventType getEventType() {10. return eventType;11. }

developerWorks® ibm.com/developerWorks

Build a dynamic organization tree using GWT and RESTful Web servicesPage 12 of 27 © Copyright IBM Corporation 2010. All rights reserved.

Page 13: Build a dynamic organization tree using GWT and RESTful ...public.dhe.ibm.com/software/dw/ajax/wa-aj-gmt/wa-aj-gmt-pdf.pdf · Learn why the Google Web Toolkit (GWT) is ideal for Java™

12. public void setEventType(EventType eventType) {13. this.eventType = eventType;14. }

15. public TreeItem getTreeItem() {16. return treeItem;}

17. public void setTreeItem(TreeItem treeItem) {18. this.treeItem = treeItem;19. }

20. public void onSuccess(String result) {21. if (result == null)22. return;23. processResponse(result);24. }

25. public void onFailure(Throwable caught) {26. String msg=caught.getMessage();27. if (msg != null)28. Window.alert(msg);29. }

30. protected abstract void processResponse(String response);

31. }

The processResponse method in EmployeeRpcCallback (lines 8 to 25 inListing 12) processes a string returned from the request to the RESTful Web service.The string contains the employee data in JSON format. This method uses GWTJSON utility classes to parse the JSON string, and stores the detailed employeedata in an application object EmployeeItemData, which is contained in classmember treeItem. Then it sets the dataReady flag to be true to indicate thatthere is no need to request employee data from the RESTfull Web service next timethe user clicks the node. At the end, the method brings opens a pop-up window todisplay the details for the employee.

Listing 12.edu.ucar.cisl.gwtRESTTutorialView.client.callback.EmployeeRpcCallback

1. package edu.ucar.cisl.gwtRESTTutorialView.client.callback;

2. import com.google.gwt.json.client.JSONObject;3. import com.google.gwt.json.client.JSONParser;4. import com.google.gwt.json.client.JSONValue;

5. import edu.ucar.cisl.gwtRESTTutorialView.client.EmployeePopup;6. import edu.ucar.cisl.gwtRESTTutorialView.client.bean.EmployeeItemData;7. import edu.ucar.cisl.gwtRESTTutorialView.client.bean.ItemData;

8. public class EmployeeRpcCallback extends RestServiceRpcCallback {9. protected void processResponse(String response) {10. JSONValue jsonValue = JSONParser.parse(response);11. ItemData iData = (ItemData) treeItem.getUserObject();12. JSONObject jobj = jsonValue.isObject();13. EmployeeItemData eItemData = (EmployeeItemData) iData;14. eItemData.setId((int) jobj.get("id").isNumber().doubleValue());15. eItemData.setFirstName(jobj.get("firstName").isString().stringValue());16. eItemData.setNickName(jobj.get("nickName").isString().stringValue());17. eItemData.setLastName(jobj.get("lastName").isString().stringValue());18. eItemData.setPhone(jobj.get("phone").isString().stringValue());

ibm.com/developerWorks developerWorks®

Build a dynamic organization tree using GWT and RESTful Web services© Copyright IBM Corporation 2010. All rights reserved. Page 13 of 27

Page 14: Build a dynamic organization tree using GWT and RESTful ...public.dhe.ibm.com/software/dw/ajax/wa-aj-gmt/wa-aj-gmt-pdf.pdf · Learn why the Google Web Toolkit (GWT) is ideal for Java™

19. eItemData.setEmail(jobj.get("email").isString().stringValue());20. eItemData.setTitle(jobj.get("title").isString().stringValue());21. iData.setDataReady(true);22. int left = treeItem.getAbsoluteLeft() + 50;23. int top = treeItem.getAbsoluteTop() + 30;24. EmployeePopup.show(left, top, (EmployeeItemData) eItemData);25. }26. }

The processResponse method in OrganizationRpcCallback (lines 10 – 31 inListing 13) processes the organizational data returned from the RESTful Webservice server. Like the employee data, the organizational data is returned as aJSON string also. The organizational data contains detailed information for theorganizational unit and some information for its employees in the organizational unitand immediate sub-organizations. The method uses GWT JSON utility classes toparse the JSON string, and stores the detailed organization data in an applicationobject OrganizationItemData contained in class member treeItem. Then itsets the dataReady flag to be true, which indicates that the detailed organizationaldata is in the memory already. The method will call the processEmployeesmethod to process the data for the employees within the organizational unit, andcalls processSubOrgs to process the data for its sub-organizations. At the end, ifthe event is Select, it opens a pop-up window to display the detailed organizationalinformation such as full name, leader name and title, and total number of employees,including those working in all its sub-organizations.

The processEmployees method (lines 44 – 54) processes a JSON array ofemployee data. It extracts id and displayName for each employee, creates anapplication object EmployeeItemData, creates a TreeItem widget, and binds theapplication object with the widget.

The processSubOrgs method (Lines 32 – 43) processes each sub-organization inthe JSON array. It extracts id and displayName, and stores them in an applicationobject OrganizationItemData. It then creates a TreeItem widget and binds theapplication object with the widget. It's common knowledge that in a desktop filemanager application you can have a folder regardless of whether it is empty. But inGWT, this action is not supported. As part of the lazy loading strategy, when anorganizational TreeItem widget is created, you don't have the data to create all ofits child widgets. However, you need to make the widget look like an organization(tree node), instead of like an employee (tree leaf). To work around this limitation, Icreated a dummy child TreeItem widget and set it to be invisible (lines 39, 40).

Listing 13.edu.ucar.cisl.gwtRESTTutorialView.client.callback.OrganizationRpcCallback

1. package edu.ucar.cisl.gwtRESTTutorialView.client.callback;

2. import com.google.gwt.json.client.JSONArray;3. import com.google.gwt.json.client.JSONObject;4. import com.google.gwt.json.client.JSONParser;5. import com.google.gwt.json.client.JSONValue;

developerWorks® ibm.com/developerWorks

Build a dynamic organization tree using GWT and RESTful Web servicesPage 14 of 27 © Copyright IBM Corporation 2010. All rights reserved.

Page 15: Build a dynamic organization tree using GWT and RESTful ...public.dhe.ibm.com/software/dw/ajax/wa-aj-gmt/wa-aj-gmt-pdf.pdf · Learn why the Google Web Toolkit (GWT) is ideal for Java™

6. import com.google.gwt.user.client.ui.TreeItem;

7. import edu.ucar.cisl.gwtRESTTutorialView.client.bean.EmployeeItemData;8. import edu.ucar.cisl.gwtRESTTutorialView.client.bean.OrganizationItemData;9. import edu.ucar.cisl.gwtRESTTutorialView.client.OrganizationPopup;

10. public class OrganizationRpcCallback extends RestServiceRpcCallback {11. protected void processResponse(String response) {12. JSONValue jsonValue = JSONParser.parse(response);13. OrganizationItemData oItemData = (OrganizationItemData)treeItem.getUserObject();14. JSONObject jobj = jsonValue.isObject();15. oItemData.setId((int) jobj.get("id").isNumber().doubleValue());16. oItemData.setDisplayName(jobj.get("acronym").isString().stringValue());17. oItemData.setName(jobj.get("name").isString().stringValue());18. oItemData.setLeadName(jobj.get("leadName").isString().stringValue());19. oItemData.setLeadTitle(jobj.get("leadTitle").isString().stringValue());20. oItemData.setTotalEmployees((int)21. obj.get("totalEmployees").isNumber().doubleValue());22. oItemData.setDataReady(true);23. treeItem.setText(oItemData.getDisplayName());24. processEmployees(jobj.get("employees").isArray());25. processSubOrgs(jobj.get("subOrgs").isArray());26. if (getEventType() == EventType.SELECT_EVENT) {27. int left = treeItem.getAbsoluteLeft() + 50;28. int top = treeItem.getAbsoluteTop() + 30;29. OrganizationPopup.show(left, top, (OrganizationItemData) oItemData);30. }31. }

32. protected void processSubOrgs(JSONArray jsonArray) {33. for (int i = 0; i < jsonArray.size(); ++i) {34. JSONObject jo = jsonArray.get(i).isObject();35. OrganizationItemData iData = new OrganizationItemData();36. iData.setId((int) jo.get("id").isNumber().doubleValue());37. iData.setDisplayName(jo.get("acronym").isString().stringValue());38. TreeItem child = treeItem.addItem(iData.getDisplayName());39. TreeItem dummy = child.addItem("");40. dummy.setVisible(false);41. child.setUserObject(iData);42. }43. }

44. protected void processEmployees(JSONArray jsonArray) {45. for (int i = 0; i < jsonArray.size(); ++i) {46. JSONObject jo = jsonArray.get(i).isObject();47. EmployeeItemData eData = new EmployeeItemData();48. eData.setId((int) jo.get("id").isNumber().doubleValue());49. eData.setDisplayName(jo.get("name").isString().stringValue());50. eData.setDataReady(false);51. TreeItem child = treeItem.addItem(eData.getDisplayName());52. child.setUserObject(eData);53. }54. }55. }

Because the GWT JSON library is used to parse out the JSON string, you need toinclude it in the GWT module configuration file (Listing 14). This file also declares theentry point class for the module (line 6). The file is located in theedu.ucar.cisl.gwtRESTTutorialView package.

Listing 14. GwtRESTTutorialView.gwt.xml

1. <?xml version="1.0" encoding="UTF-8"?>

ibm.com/developerWorks developerWorks®

Build a dynamic organization tree using GWT and RESTful Web services© Copyright IBM Corporation 2010. All rights reserved. Page 15 of 27

Page 16: Build a dynamic organization tree using GWT and RESTful ...public.dhe.ibm.com/software/dw/ajax/wa-aj-gmt/wa-aj-gmt-pdf.pdf · Learn why the Google Web Toolkit (GWT) is ideal for Java™

2. <module rename-to='gwtresttutorialview'>3. <inherits name='com.google.gwt.user.User'/>4. <inherits name="com.google.gwt.json.JSON"/>5. <inherits name='com.google.gwt.user.theme.standard.Standard'/>6. <entry-point class='edu.ucar.cisl.gwtRESTTutorialView.client.GwtRESTTutorialView'/>7. <source path='client'/>8. </module>

Declare the RESTful Web service proxy in the web.xml file

The RPC remote service is technically a servlet. All you must do is configure theservlet in the the web.xml file the same as you would any other servlet (Listing 15).

Listing 15. Part of web.xml to declare the RESTful Web service proxy remoteservice

1. <servlet>2. <servlet-name>RESTfulWebServiceServlet</servlet-name>3. <servlet-class>4. edu.ucar.cisl.gwtRESTTutorialView.server.RESTfulWebServiceProxyImpl5. </servlet-class>6. </servlet>7. <servlet-mapping>8. <servlet-name>RESTfulWebServiceServlet</servlet-name>9. <url-pattern>/gwtresttutorialview/RESTfulWebServiceProxy</url-pattern>10. </servlet-mapping>

Implement the GWT client interface

Create a main window

Listing 16 lists the entry point class for the module. This class must implement theEntryPoint interface. The method onModuleLoad is the first method to beexecuted after the module is loaded. The class also implements theSelectionHandler<TreeItem> and OpenHandler<TreeItem> interfaces tohandle tree node selection and open events. In earlier releases, GWT provided a lotof event listener interfaces. However, they have been replaced by event handlerssince the 1.6 release.

The method onModuleLoad instantiates a Tree widget and a TreeItem widget asthe tree widget's root to represent the highest level of an organization. An applicationobject OrganizationItemData is created and is associated with the rootTreeItem. The id for the object is set to 1, and can be set to any level of theorganization to be used as a starting point. Because the root node is meant torepresent an organization instead of an employee, it needs to behave and look like atree node that can be opened. Currently, the GWT TreeItem widget doesn'tprovide this capability. As a work-around, I created a dummy TreeItem as a child ofthe root and set the dummy TreeItem to be invisible. Now when the state for theroot TreeItem is set to be open (line 35), an Open event is launched and theonOpen method is invoked to create the first level organizational structure, including

developerWorks® ibm.com/developerWorks

Build a dynamic organization tree using GWT and RESTful Web servicesPage 16 of 27 © Copyright IBM Corporation 2010. All rights reserved.

Page 17: Build a dynamic organization tree using GWT and RESTful ...public.dhe.ibm.com/software/dw/ajax/wa-aj-gmt/wa-aj-gmt-pdf.pdf · Learn why the Google Web Toolkit (GWT) is ideal for Java™

a list of employees and sub-organizations. The Tree Widget is added toRootPanel, which is the top container for all widgets in GWT applications.

Tree widget event handler method onSelection (lines 38-51) is called when auser selects either the employee TreeItem or the organization TreeItem widget. Itretrieves application item data from the widget and opens a pop-up window todisplay the detailed data if the data has been loaded. Otherwise, it callsinvokeRESTfulWebService to send a request to the proxy server. The lattermethod is discussed in the next section.

Another Tree widget event handler method, onOpen, (lines 53-60) is called whenthe user opens the organization TreeItem widget. If the detailed data for theorganization, including employee data and immediate sub-organization data, is notavailable, this method, like onSelection, calls invokeRESTfulWebService tosend a request to the proxy server.

Listing 16. edu.ucar.cisl.gwtRESTTutorialView.client. GwtRESTTutorialView

1. package edu.ucar.cisl.gwtRESTTutorialView.client;

2. import com.google.gwt.core.client.EntryPoint;3. import com.google.gwt.core.client.GWT;4. import com.google.gwt.event.logical.shared.OpenEvent;5. import com.google.gwt.event.logical.shared.OpenHandler;6. import com.google.gwt.event.logical.shared.SelectionEvent;7. import com.google.gwt.event.logical.shared.SelectionHandler;8. import com.google.gwt.user.client.ui.RootPanel;9. import com.google.gwt.user.client.ui.Tree;10. import com.google.gwt.user.client.ui.TreeItem;11. import com.google.gwt.user.client.ui.Tree.Resources;

12. import edu.ucar.cisl.gwtRESTTutorialView.client.bean.EmployeeItemData;13. import edu.ucar.cisl.gwtRESTTutorialView.client.bean.ItemData;14. import edu.ucar.cisl.gwtRESTTutorialView.client.bean.OrganizationItemData;15. import edu.ucar.cisl.gwtRESTTutorialView.client.callback.EmployeeRpcCallback;16. import edu.ucar.cisl.gwtRESTTutorialView.client.callback.OrganizationRpcCallback;17. import edu.ucar.cisl.gwtRESTTutorialView.client.callback.RestServiceRpcCallback;

18. /**Entry point classes define <code>onModuleLoad()</code>.19. */20. public class GwtRESTTutorialView implements EntryPoint,21. SelectionHandler<TreeItem>, OpenHandler<TreeItem> {22. final static String contentType="application/json";

23. public void onModuleLoad() {24. TreeItem root = new TreeItem("Root");25. ItemData iData = new OrganizationItemData();26. iData.setId(1);27. root.setUserObject(iData);28. TreeItem dummyItem = root.addItem("");29. dummyItem.setVisible(false);30. Tree tree = new Tree((Resources) GWT.create(OrgTreeResource.class), true);31. tree.addItem(root);32. tree.addSelectionHandler(this);33. tree.addOpenHandler(this);34. RootPanel.get().add(tree);35. root.setState(true, true);36. }

37. @Override

ibm.com/developerWorks developerWorks®

Build a dynamic organization tree using GWT and RESTful Web services© Copyright IBM Corporation 2010. All rights reserved. Page 17 of 27

Page 18: Build a dynamic organization tree using GWT and RESTful ...public.dhe.ibm.com/software/dw/ajax/wa-aj-gmt/wa-aj-gmt-pdf.pdf · Learn why the Google Web Toolkit (GWT) is ideal for Java™

38. public void onSelection(SelectionEvent<TreeItem> event) {39. TreeItem item=event.getSelectedItem();40. ItemData iData = (ItemData) item.getUserObject();41. if (iData.isDataReady()) {42. int left = item.getAbsoluteLeft() + 50;43. int top = item.getAbsoluteTop() + 30;44. if (iData instanceof EmployeeItemData)45. EmployeePopup.show(left, top, (EmployeeItemData) iData);46. else47. OrganizationPopup.show(left, top, (OrganizationItemData) iData);48. } else49. invokeRESTfulWebService(item,50. RestServiceRpcCallback.EventType.SELECT_EVENT);51. }

52. @Override53. public void onOpen(OpenEvent<TreeItem> event) {54. TreeItem item = event.getTarget();55. ItemData iData = (ItemData) item.getUserObject();56. if (!iData.isDataReady()) {57. invokeRESTfulWebService(item,58. RestServiceRpcCallback.EventType.STATE_CHANGE_EVENT);59. }60. }

61. protected void invokeRESTfulWebService(TreeItem item,62. RestServiceRpcCallback.EventType eventType) {63. ItemData iData = (ItemData) item.getUserObject();64. RestServiceRpcCallback callback = null;65. if (iData instanceof EmployeeItemData)66. callback = new EmployeeRpcCallback();67. if (iData instanceof OrganizationItemData)68. callback = new OrganizationRpcCallback();69. callback.setEventType(eventType);70. callback.setTreeItem(item);71. RESTfulWebServiceProxyAsync ls = RESTfulWebServiceProxy.Util.getInstance();72. ls.invokeGetRESTfulWebService(iData.buildUri(), contentType, callback);73. }74. }

Send a RESTful Web service request to the RPC proxy server

Method invokeRESTfulWebService (lines 61–73) sends a RESTful Web servicerequest to the proxy server using an RPC service. It first retrieves application itemdata from the TreeItem widget and instantiates a callback instance of eitherEmployeeRpcCallback or OrganizationItemData depending on the nature ofthe application item data. It then associates the TreeItem widget and event typewith the callback instance so that it knows how to proceed after the data for theRESTful Web service is returned.

As required by GWT, before a remote service is called, an instance of the asyncremote interface must be created and used to invoke the remote service, with allparameters declared in the remote service and the instance of the callback class.Because the remote service call is asynchronous and non-blocking, the GWT clientdoes not wait for a response from the service. It continues executing until it receivesan asynchronous callback from the remote server. The callback informs the GWTapplication of whether the remote service call has been executed successfully. TheonSuccess method is called if the remote service is successful. Otherwise, the

developerWorks® ibm.com/developerWorks

Build a dynamic organization tree using GWT and RESTful Web servicesPage 18 of 27 © Copyright IBM Corporation 2010. All rights reserved.

Page 19: Build a dynamic organization tree using GWT and RESTful ...public.dhe.ibm.com/software/dw/ajax/wa-aj-gmt/wa-aj-gmt-pdf.pdf · Learn why the Google Web Toolkit (GWT) is ideal for Java™

onFailure method is called with an instance of Throwable, which contains acustom exception passed from the server. the callback class will process the datareturned from the server.

Create custom tree images

It's very easy to customize the tree images for the GWT Tree widget. You simplyneed to create a custom interface that extends the Tree.Resource interface andredeclare treeOpen, treeClosed, and treeLeaf methods (Listing 17). Then useGWT.create to instantiate an instance of the new interface and pass it to the Treewidget constructor when the Tree widget is created (Listing 16, line 30). Threeimage files with names starting with treeOpen, treeClosed and treeLeaf,respectively, need to be placed in the same folder.

Listing 17. edu.ucar.cisl.gwtRESTTutorialView.client.OrgTreeResource

1. package edu.ucar.cisl.gwtRESTTutorialView.client;

2. import com.google.gwt.resources.client.ImageResource;3. import com.google.gwt.user.client.ui.Tree.Resources;

4. public interface OrgTreeResource extends Resources {5. ImageResource treeOpen();6. ImageResource treeClosed();7. ImageResource treeLeaf();8. }

Implement pop-up windows

Two pop-up windows are created to display detailed information for an employeeand an organizational unit. Listing 18 lists the implementation for the employeepop-up window. The class extends the GWT PopupPanel widget. It is implementedas a singleton class. It uses six pairs of Label widgets to display the labels andvalues for first name, nickname, last name, title, phone, and e-mail. A Grid widget isused to handle the layout for Label widgets. To display the detailed employee data,all you need to do is to call the static method show and pass the location in terms ofleft and top offsets from the widget it refers to. In this case, the reference widget isthe TreeItem widget the user selects. The implementation for organizationalpop-up window is similar (Listing 19).

Listing 18. edu.ucar.cisl.gwtRESTTutorialView.client.EmployeePopup

1. package edu.ucar.cisl.gwtRESTTutorialView.client;

2. import com.google.gwt.user.client.ui.Grid;3. import com.google.gwt.user.client.ui.Label;4. import com.google.gwt.user.client.ui.PopupPanel;

5. import edu.ucar.cisl.gwtRESTTutorialView.client.bean.EmployeeItemData;

6. public class EmployeePopup extends PopupPanel {7. static protected EmployeePopup instance=null;8. protected Grid grid = new Grid(6, 2);

ibm.com/developerWorks developerWorks®

Build a dynamic organization tree using GWT and RESTful Web services© Copyright IBM Corporation 2010. All rights reserved. Page 19 of 27

Page 20: Build a dynamic organization tree using GWT and RESTful ...public.dhe.ibm.com/software/dw/ajax/wa-aj-gmt/wa-aj-gmt-pdf.pdf · Learn why the Google Web Toolkit (GWT) is ideal for Java™

9. protected Label firstNameLabel = new Label("First Name");10. protected Label firstNameValueLabel = new Label("First Name");11. protected Label nickNameLabel = new Label("Nickname");12. protected Label nickNameValueLabel = new Label("Nick Name");13. protected Label lastNameLabel = new Label("Last Name");14. protected Label lastNameValueLabel = new Label("Last Name");15. protected Label titleLabel = new Label("Title");16. protected Label titleValueLabel = new Label("Title");17. protected Label phoneLabel = new Label("Phone Number");18. protected Label phoneValueLabel = new Label("Phone Number");19. protected Label emailNameLabel = new Label("Email");20. protected Label emailValueLabel = new Label("Email");

21. protected EmployeePopup() {22. super(true);

23. grid.setWidget(0, 0, firstNameLabel);24. grid.setWidget(0, 1, firstNameValueLabel);

25. grid.setWidget(1, 0, nickNameLabel);26. grid.setWidget(1, 1, nickNameValueLabel);

27. grid.setWidget(2, 0, lastNameLabel);28. grid.setWidget(2, 1, lastNameValueLabel);

29. grid.setWidget(3, 0, titleLabel);30. grid.setWidget(3, 1, titleValueLabel);

31. grid.setWidget(4, 0, phoneLabel);32. grid.setWidget(4, 1, phoneValueLabel);

33. grid.setWidget(5, 0, emailNameLabel);34. grid.setWidget(5, 1, emailValueLabel);

35. grid.setWidth("300px");36. // grid.setHeight("400px");37. setWidget(grid);38. }

39. public void setEmployeeData(EmployeeItemData iData) {40. String firstName = iData.getFirstName();41. String lastName = iData.getLastName();42. String nickName = iData.getNickName();43. String phone = iData.getPhone();44. String email = iData.getEmail();45. String title = iData.getTitle();

46. firstNameValueLabel.setText(firstName);47. if (nickName != null && nickName.length() > 0) {48. nickNameValueLabel.setVisible(true);49. nickNameLabel.setVisible(true);50. nickNameValueLabel.setText(nickName);51. }52. else {53. nickNameValueLabel.setVisible(false);54. nickNameLabel.setVisible(false);55. }56. lastNameValueLabel.setText(lastName);57. phoneValueLabel.setText(phone);58. emailValueLabel.setText(email);59. titleValueLabel.setText(title);60. }

61. protected static EmployeePopup getInstance() {62. if (instance == null)63. instance = new EmployeePopup();64. return instance;65. }

developerWorks® ibm.com/developerWorks

Build a dynamic organization tree using GWT and RESTful Web servicesPage 20 of 27 © Copyright IBM Corporation 2010. All rights reserved.

Page 21: Build a dynamic organization tree using GWT and RESTful ...public.dhe.ibm.com/software/dw/ajax/wa-aj-gmt/wa-aj-gmt-pdf.pdf · Learn why the Google Web Toolkit (GWT) is ideal for Java™

66. public static void show(int leftOffset, int topOffset, EmployeeItemData eData) {67. EmployeePopup popup = getInstance();68. popup.setEmployeeData(eData);69. popup.setPopupPosition(leftOffset, topOffset);70. popup.show();71. }

72. }

Listing 19. edu.ucar.cisl.gwtRESTTutorialView.client.OrganizationPopup

1. package edu.ucar.cisl.gwtRESTTutorialView.client;

2. import com.google.gwt.user.client.ui.Grid;3. import com.google.gwt.user.client.ui.Label;4. import com.google.gwt.user.client.ui.PopupPanel;

5. import edu.ucar.cisl.gwtRESTTutorialView.client.bean.OrganizationItemData;

6. public class OrganizationPopup extends PopupPanel {7. static protected OrganizationPopup instance=null;8. protected Grid grid = new Grid(3, 2);9. protected Label nameLabel = new Label("Full Name");10. protected Label nameValueLabel = new Label("Full Name");11. protected Label leadNameLabel = new Label("Lead");12. protected Label leadNameValueLabel = new Label("Lead Name");13. protected Label totalEmployeesLabel = new Label("Total Employees");14. protected Label totalEmployeesValueLabel = new Label("Total Employees");

15. public OrganizationPopup() {16. super(true);

17. grid.setWidget(0, 0, nameLabel);18. grid.setWidget(0, 1, nameValueLabel);

19. grid.setWidget(1, 0, leadNameLabel);20. grid.setWidget(1, 1, leadNameValueLabel);

21. grid.setWidget(2, 0, totalEmployeesLabel);22. grid.setWidget(2, 1, totalEmployeesValueLabel);

23. grid.setWidth("700px");24. setWidget(grid);25. }

26. public void setOrganizationData(OrganizationItemData iData) {27. nameValueLabel.setText(iData.getName());28. leadNameValueLabel.setText(iData.getLeadName());29. totalEmployeesValueLabel.setText(new30. Integer(iData.getTotalEmployees()).toString());31. }

32. protected static OrganizationPopup getInstance() {33. if (instance == null)34. instance = new OrganizationPopup();35. return instance;36. }

37. public static void show(int leftOffset, int topOffset,OrganizationItemData oData) {38. OrganizationPopup popup = getInstance();39. popup.setOrganizationData(oData);40. popup.setPopupPosition(leftOffset, topOffset);41. popup.show();42. }43. }

ibm.com/developerWorks developerWorks®

Build a dynamic organization tree using GWT and RESTful Web services© Copyright IBM Corporation 2010. All rights reserved. Page 21 of 27

Page 22: Build a dynamic organization tree using GWT and RESTful ...public.dhe.ibm.com/software/dw/ajax/wa-aj-gmt/wa-aj-gmt-pdf.pdf · Learn why the Google Web Toolkit (GWT) is ideal for Java™

Put it all together

After all the classes are implemented, you should have the following folders and filesunder the src folder for the project in Eclipse (Figure 2).

Figure 2. Project folder in Eclipse

developerWorks® ibm.com/developerWorks

Build a dynamic organization tree using GWT and RESTful Web servicesPage 22 of 27 © Copyright IBM Corporation 2010. All rights reserved.

Page 23: Build a dynamic organization tree using GWT and RESTful ...public.dhe.ibm.com/software/dw/ajax/wa-aj-gmt/wa-aj-gmt-pdf.pdf · Learn why the Google Web Toolkit (GWT) is ideal for Java™

To run it, right-click on the project name in Project Explore, choose Run As > WebApplication or Debug As > Web Application. Copy the URL from the DeveloperMode window and paste it into your favorite browser. The application should look

ibm.com/developerWorks developerWorks®

Build a dynamic organization tree using GWT and RESTful Web services© Copyright IBM Corporation 2010. All rights reserved. Page 23 of 27

Page 24: Build a dynamic organization tree using GWT and RESTful ...public.dhe.ibm.com/software/dw/ajax/wa-aj-gmt/wa-aj-gmt-pdf.pdf · Learn why the Google Web Toolkit (GWT) is ideal for Java™

like Figure 3.

Figure 3. Org tree application in a browser

Conclusion

GWT is ideal for Java developers to build rich and responsive desktop-likeapplications, particularly large-scale Web apps. In this article, I demonstrated how touse GWT tree widgets to display the organizational structure of a company. I usedan RPC proxy to integrate with RESTful Web services. JSON is data format used byRESTful Web services. Organizational data and employee data are loaded onlywhen needed, and tree nodes (organizations) and leaves (employees) aredynamically created. Callbacks are implemented as real classes to help facilitatecode reuse and associated with client data at run time. the tree images arecustomized to show organizations and employees, and pop-up windows are used todisplay the details for organizations and employees.

This article was made possible by research supported in part by the NationalScience Foundation, pursuant to its cooperative agreement with the UniversityCorporation for Atmospheric Research. The National Center for Atmospheric

developerWorks® ibm.com/developerWorks

Build a dynamic organization tree using GWT and RESTful Web servicesPage 24 of 27 © Copyright IBM Corporation 2010. All rights reserved.

Page 25: Build a dynamic organization tree using GWT and RESTful ...public.dhe.ibm.com/software/dw/ajax/wa-aj-gmt/wa-aj-gmt-pdf.pdf · Learn why the Google Web Toolkit (GWT) is ideal for Java™

Research is sponsored by the National Science Foundation.

ibm.com/developerWorks developerWorks®

Build a dynamic organization tree using GWT and RESTful Web services© Copyright IBM Corporation 2010. All rights reserved. Page 25 of 27

Page 26: Build a dynamic organization tree using GWT and RESTful ...public.dhe.ibm.com/software/dw/ajax/wa-aj-gmt/wa-aj-gmt-pdf.pdf · Learn why the Google Web Toolkit (GWT) is ideal for Java™

Downloads

Description Name Size Downloadmethod

RESTful Web services gwtRESTTutorialView.zip 1365KB HTTP

Source code gwtRESTTutorial.war 9233KB HTTP

Database setup setup.sql 8KB HTTP

Information about download methods

developerWorks® ibm.com/developerWorks

Build a dynamic organization tree using GWT and RESTful Web servicesPage 26 of 27 © Copyright IBM Corporation 2010. All rights reserved.

Page 27: Build a dynamic organization tree using GWT and RESTful ...public.dhe.ibm.com/software/dw/ajax/wa-aj-gmt/wa-aj-gmt-pdf.pdf · Learn why the Google Web Toolkit (GWT) is ideal for Java™

Resources

Learn

• Read the companion article "A multi-tier architecture for building RESTful Webservices" (developerWorks, Jun 2009) to get an overview of the concept ofREST and RESTful Web services, then compare them toRPC-style/SOAP-based Web services.

• See "Build RESTful Web services and dynamic Web applications with themulti-tier architecture" (developerWorks, Jun 2009) to continue your training onbuilding RESTful Web services and dynamic Web applications using themulti-tier architecture.

• Learn more about GWT.

Get products and technologies

• Download Apache Tomcat 6.x.

• Download MySQL 5.1.

• Download DB2 Express-C.

• Download Eclipse IDE for Java EE Developers.

• Download GWT and the GWT plug-in for Eclipse.

About the author

Bruce SunBruce Sun is a Sun Microsystems certified Java architect. He has been developingJava-based Web applications since 1998. He is currently working as a SeniorSoftware Engineer at the National Center for Atmospheric Research (NCAR).

ibm.com/developerWorks developerWorks®

Build a dynamic organization tree using GWT and RESTful Web services© Copyright IBM Corporation 2010. All rights reserved. Page 27 of 27