Skip to main content

Integrate XForms with the Google Web Toolkit, Part 2: Creating an artist and album management form

Create a Web application for rock star hopefuls

Michael Galpin (mike.sr@gmail.com), Developer, Ludi Labs
Michael Galpin has been developing Java software professionally since 1998. He currently works at Ludi Labs, a start-up in Mountain View, Calif. He holds a degree in mathematics from the California Institute of Technology.

Summary:  This four-part series demonstrates how to use the Google Web Toolkit (GWT) and XForms together to create a dynamic Web application. Part 1 looked at the JavaScript underpinnings of each technology. Part 2 shows you how to use those JavaScript underpinnings to start mixing the two technologies together to build the rock star application.

View more content in this series

Date:  25 Sep 2007
Level:  Intermediate
Activity:  2737 views

Introduction

Part 1 of this four-part series provided a solid grounding in both GWT and XForms and explored how the two can work together to streamline the process of creating Web applications. Now in Part 2, you'll build a simple Web application, the rock star application, that has a two pages: one for viewing artists and one for viewing the albums recorded by those artists. The first page will be built using GWT, and it will use GWT's widgets and GWT's Ajax abstractions. It will link to your second page, which will be built using XForms, and it will use an XForms data model and XForms controls for creating its UI.

Prerequisites

Get up to speed! Read Part 1, Introducing GWT's JavaScript Native Interface, of this series.

This article uses GWT version 1.4 and the Mozilla XForms plugin 0.8 (see the Resources for download links). The Mozilla XForms plugin works with any Mozilla-based Web browser, such as Firefox and Seamonkey. GWT requires knowledge of the Java™ language, and Web technologies such as HTML and CSS. This article makes heavy use of JavaScript, as well. XForms makes heavy use of the Model-View-Control paradigm, so familiarity with that is helpful. Prior exposure to XForms and GWT is helpful of course, but is not necessary. The code in this article was developed using Eclipse 3.3, but it is not necessary to know Eclipse.


Using GWT to manage artists

The first thing you'll need to do in your rock star application is get a list of all of your artists. Of course, you'll also want to be able to add new artists to this list. Your list will also give you a way to navigate to your second page, where you'll be able to manage the albums recorded by a particular artist. You'll use GWT for the artist page. You'll make use of its built-in widgets for creating a nice UI for your page, and its Ajax abstractions for simplifying the loading and saving of data.

Application data

The data in your application will be stored in simple XML files. XML is a common format for transferring data, and it is, of course, native to XForms. You could easily keep the data in a relational database, though there is a good chance you'd wind up serializing it as XML for various purposes anyway. Using XML instead of a relational database will keep it simple so you can focus on the real stars of the application: GWT and XForms.

The artist model with GWT

You'll need a simple data model for our application to represent an artist. With GWT, this is as easy as creating a simple Java bean, as shown in Listing 1.


Listing 1. Artist model: Java Bean
                
package org.developerworks.rockstar.client;

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

public class Artist implements IsSerializable{
     private int id;
     private String name;
     private String genre;
     
     public Artist(){
          // needed for GWT's RPC mechanism
     }
     public Artist(int id, String name, String genre) {
          this.id = id;
          this.name = name;
          this.genre = genre;
     }
     public int getId() {
          return id;
     }
     public void setId(int id) {
          this.id = id;
     }
     public String getName() {
          return name;
     }
     public void setName(String name) {
          this.name = name;
     }
     public String getGenre() {
          return genre;
     }
     public void setGenre(String genre) {
          this.genre = genre;
     }
}

As mentioned, this is just a standard Java bean: three fields with corresponding getters and setters. You'll use a numeric ID for your artists just to make it easy to reference them. This is also what you'd probably have if there was a database table being used to persist the artists. Notice that this is in the client package of your application. Thus this class will be compiled into JavaScript. That doesn't matter to you, though. You can still program it in Java, paying no attention to the JavaScript behind the curtain. Finally, notice that your class implements the IsSerializable marker interface. This is needed for any class that is going to be sent over the wire, for example, as part of a request or a response on an Ajax call. Now let's examine how you can use GWT to create a UI for a list of Artist objects.


Use GWT widgets for artist list

One of the many nice things about GWT is that it comes with a set of widgets for creating common UI structures. You get to use familiar Java syntax for creating UI elements. If you've done Swing or SWT programming, this is very familiar. In this case, you will use a FlexTable. This is a table that is dynamic and is well suited for your application because the number of artists is not set. The FlexTable will expand to fit the number of artists. The code for the populating the FlexTable is shown in Listing 2.


Listing 2. Creating an artist table
                
  private void populateTable(Artist[] artists){
      // clear the table
       int rowCount = this.artistTable.getRowCount();
       for (int i=0;i<rowCount;i++){
            this.artistTable.removeRow(i);
       }
      // create the header
      this.artistTable.getRowFormatter().addStyleName(0, "tableHeader");
      this.artistTable.setText(0, 0, "Name");
      this.artistTable.setText(0, 1, "Genre");
      // now add artists
      for (int i=0;i<artists.length;i++){
           this.artistTable.setText(i+1, 0, artists[i].getName());
           this.artistTable.setText(i+1, 1, artists[i].getGenre());
      }
      this.artistTable.setBorderWidth(4);
  }

The code in Listing 2 clears the table if it's already there. Then it creates a header. The only thing really special about the header is that you attach a style to it. Let's briefly take a look at that. Next the code iterates over the artists, adding them to the table. Let's take a look at the page it adds the table to in Listing 3.


Listing 3. The artist page
                
<html>
     <head>
          <title>RockStars</title>

          <!--                                           -->
          <!-- This script loads your compiled module.   -->
          <!-- If you add any GWT meta tags, they must   -->
          <!-- be added before this line.                -->
          <!--                                           -->
          <script language='javascript' src='org.developerworks.
		  rockstar.RockStarMain.nocache.js'></script>
          <style type="text/css">
               .tableHeader{
                    background-color:#AAAAAA;
               }
          </style>
     </head>
     <body>
     </body>
</html>

There's not much to the HTML! You let GWT do all the hard work. The only thing HTML-ish you've done is inlined some CSS for the header on your table. Now that you have the UI elements for your page, you just need some data. You'll get that using Ajax, GWT style.


Getting artist data: Using a Remote Procedure Call

You have a nice GWT widget ready to use for displaying your list of artists. Now you just need a list. To do this you'll create a service for managing artists. You'll use GWT to invoke this service asynchronously, for example, using Ajax. This is a typical GWT Remote Procedure Call (RPC). Start off by declaring an interface for the service, as shown in Listing 4.


Listing 4. Artist Service Interface
                
package org.developerworks.rockstar.client;

import com.google.gwt.user.client.rpc.RemoteService;

public interface ArtistService extends RemoteService {
     public Artist[] getAllArtists();
     public void addArtist(Artist newArtist);
}

Note that your service extends the GWT marker interface RemoteService. This is a necessary GWT convention. Also note that your getAllArtists() call returns an array of Artist objects. These are the same Artist objects defined earlier as your data model. You might be tempted to have this return a Collection<Artist> or List<Artist> but don't do it. GWT does not support generics in client code, for example, code that will be compiled into JavaScript. There are no generics in JavaScript, and generic-type information is not available at runtime, anyway. You could still return a java.util.List, as these are allowed, but an array works just as well and is strongly typed.

GWT requires an asynchronous version of any interface that's going to be invoked from the client. The corresponding asynchronous version of our interface is shown in Listing 5.


Listing 5. Asynchronous service interface
                
package org.developerworks.rockstar.client;

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

public interface ArtistServiceAsync {
     public void getAllArtists(AsyncCallback callback);
     public void addArtist(Artist newArtist, AsyncCallback callback);
}

The key here is the Async suffix on the service name. This is a naming convention that lets GWT match up this interface to the one shown in Listing 4. Also note how all the calls have been made asynchronous, meaning they have a void return type. They all have an AsyncCallback that allows GWT to invoke the callback once the server-side implementation of the interface finishes processing the request made to it. Let's take a look at the server-side implementation of our interface in Listing 6.


Listing 6. Server-side implementation of interface
                
package org.developerworks.rockstar.server;

import java.util.List;

import org.developerworks.rockstar.client.Artist;
import org.developerworks.rockstar.client.ArtistService;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

public class ArtistServiceImpl extends RemoteServiceServlet implements ArtistService {

     private static final long serialVersionUID = -1801240935065207659L;
     
     private List<Artist> artists;
     private ArtistDao dao;
     
     public ArtistServiceImpl(){
          this.dao = new ArtistFileDao();
          this.artists = this.dao.getAllArtists();
     }

     public void addArtist(Artist newArtist) {
           newArtist.setId(this.artists.size());
          this.artists.add(newArtist);
          dao.saveArtists(this.artists);
     }

     public Artist[] getAllArtists() {
          Artist[] array = new Artist[this.artists.size()];
          return this.artists.toArray(array);
     }
     
}

There are a few things you should notice about this class. One is that it extends RemoteServiceServlet as well as implementing the interface you defined. The RemoteServiceServlet is a classic Java servlet designed to handle Ajax requests. At runtime, the superclass's methods will be invoked by requests from our client code, and the superclass will use reflection to invoke the actual method requested by the client. Finally, note that you are using a Data Access Object (DAO) interface, ArtistDao. You are using a file-based implementation, ArtistFileDao, but you could easily swap this out for a database-based implementation. That class also has all the messy code for reading/writing to our files as well as parsing XML. Let's give our app a test.


Viewing artists: Hosted mode

So far everything has been pure GWT. One of the nice things with GWT is that you can use hosted mode. If you're using Eclipse, you can launch the application from there and view it. First you'll need some data, though. A simple data file is shown in Listing 7.


Listing 7. Test data
                
<?xml version="1.0" encoding="UTF-8"?>
<Data>
     <Artist>
          <Id>0</Id>
          <Name>The Struts Five</Name>
          <Genre>Classic Rock</Genre>
     </Artist>
     <Artist>
          <Id>1</Id>
          <Name>Spring Flow</Name>
          <Genre>Techno</Genre>
     </Artist>
     <Artist>
          <Id>2</Id>
          <Name>The Holy Grails</Name>
          <Genre>Funk</Genre>
     </Artist>
     <Artist>
          <Id>3</Id>
          <Name>The Rails Way</Name>
          <Genre>Pop</Genre>
     </Artist>
     <Artist>
          <Id>4</Id>
          <Name>Cake Clone</Name>
          <Genre>Pop</Genre>
     </Artist>
     <Artist>
          <Id>5</Id>
          <Name>Obscure Tapestry</Name>
          <Genre>Techno</Genre>
     </Artist>
     <Artist>
          <Id>6</Id>
          <Name>Dojo Darling</Name>
          <Genre>Classic Rock</Genre>
     </Artist>
     <Artist>
          <Id>7</Id>
          <Name>Cairingorm</Name>
          <Genre>Progressive</Genre>
     </Artist>
     <Artist>
          <Id>8</Id>
          <Name>ProtoStripes</Name>
          <Genre>Thrash</Genre>
     </Artist>
</Data>


Now that you have test data, you can launch your application. It should bring up an interface like the one shown in Figure 1.


Figure 1. Viewing artists in hosted mode
viewing artists in hosted mode

There's your list of artists from the test data. Now you just need a simple form to enter in a new artist.


Adding a new artist: Using GWT to create a form

You need a simple data-entry form to enter in your new artists. Luckily GWT also includes widgets for creating forms. With GWT, you can create your form programmatically, as shown in Listing 8.


Listing 8. Data entry form with GWT
                
public class RockStarMain implements EntryPoint {

     // Widgets for the page
     final FlexTable artistTable = new FlexTable();
     final VerticalPanel outerPanel = new VerticalPanel();
     final HorizontalPanel formPanel = new HorizontalPanel();
     final Label artistLabel = new Label("Artist Name:");
     final TextBox artistInput = new TextBox();
     final Label genreLabel = new Label("Genre:");
     final TextBox genreInput = new TextBox(); 
     final Button addButton = new Button("Add Artist");
     
  /**
   * This is the entry point method.
   */
  public void onModuleLoad() {
     // add the outer panel, then add to it
     RootPanel.get().add(outerPanel);
     outerPanel.add(artistTable);
     outerPanel.add(formPanel);
     
     // arrange form elements horizontally
     formPanel.add(artistLabel);
     formPanel.add(artistInput);
     formPanel.add(genreLabel);
     formPanel.add(genreInput);
     formPanel.add(addButton);
     
     // add event listener to our button
     ClickListener listener = new ClickListener(){

          public void onClick(Widget sender) {
               addNewAritst();
          }
          
     };
     addButton.addClickListener(listener);
     
    // load the artists now all the widgets are ready
    this.loadArtists();
  }

This code is once again refreshingly straightforward. You create a set of widgets: labels, text boxes, and buttons (and the FlexTable you've been working with.) You also use a couple of panels that act like layout managers for laying out your widgets. You then add an event listener to one of your buttons for adding a new artist. The event listener will invoke your back-end service. Let's take a look at it in Listing 9.


Listing 9. Add new artist method
                
  private void addNewAritst(){
       Artist artist = new Artist(-1, artistInput.getText(), genreInput.getText());
       ArtistServiceAsync artistService = getArtistService();
       
       AsyncCallback callback = new AsyncCallback(){

          public void onFailure(Throwable caught) {
               // remove last row because of failure
               removeLastArtist();
          }

          public void onSuccess(Object result) {
               // nothing to do here since we added optimistically
          }
            
       };
       
       artistService.addArtist(artist, callback);
       // we'll be optimistic and go ahead and add to the table
       int size = this.artistTable.getRowCount();
       this.artistTable.setText(size, 0, artist.getName());
       this.artistTable.setText(size, 1, artist.getGenre());
  }

In this code you see the asynchronous version of your interface being called. An anonymous callback method is created. In this case it is very simple, and only does anything if the call fails. That's because you go ahead and add the artist to your table without waiting for the server. This provides a good user experience as adding artists will be instantaneous, but it assumes that failures will be very rare. The full source code is available for download at the end of the article. Let's take a look at your UI now that you've added the form, as shown in Figure 2.


Figure 2. View artists and add new artists
view artists and add new artists

Fill out the form and click the Add Artist button. Your UI should be instantly updated, as shown in Figure 3.


Figure 3. Artist added
artist added

You've seen how GWT can be used for creating UI elements and using Ajax to retrieve and save data to back-end services. Let's take a look at how you can use XForms to create a page for managing albums.


Using XForms to manage albums

For the second part of your application, you'll view a list of albums by an artist. Obviously you want to create a single page for displaying albums that can be used for each artist. So how will you know which albums to show? There are obviously a few different ways to do this, but you'll use a command pattern. The command should tell you everything you need to know to create the page. In this case you'll need to know whose albums to show, in other words, which artist's albums to show. To do this you'll need a request parameter that specifies an artist, so you'll just call it artistId. You'll need a link to your second page from the first page, and that link will need to have the artistId parameter.


Linking from GWT page to XForms page

Let's go back to your first page and a create a link to your second page. This will only take a small change to the code, as shown in Listing 10.


Listing 10. Adding links to the Artist list
                
  private void populateTable(Artist[] artists){
      // clear the table
       int rowCount = this.artistTable.getRowCount();
       for (int i=0;i<rowCount;i++){
            this.artistTable.removeRow(i);
       }
      // create the header
      this.artistTable.getRowFormatter().addStyleName(0, "tableHeader");
      this.artistTable.setText(0, 0, "Name");
      this.artistTable.setText(0, 1, "Genre");
      // now add artists
      for (int i=0;i<artists.length;i++){
           //this.artistTable.setText(i+1, 0, artists[i].getName());
           String html = "<a href=\"Albums.jsp?artistId=
		     "+artists[i].getId()+"\">"+artists[i].getName()+"</a>";
           this.artistTable.setHTML(i+1, 0, html);
           this.artistTable.setText(i+1, 1, artists[i].getGenre());
      }
      this.artistTable.setBorderWidth(4);
  }

All that you changed is the code that sets the left column in your table. Instead of using setText(...), you used setHTML(...). This allows you to put HTML in the table, and thus create a simple link to a new page "Albums.jsp". You used a JSP so that way you can do some dynamic construction of the page. The dynamic part is that you only want to show the albums recorded by the artist specified via the artistId. Notice that the artistId parameter is part of your link. Now you just need to create this page.


Creating an XForms page using GWT

You can create the JSP just like any other Web resource such as HTML or CSS pages. You can still use GWT on your page. All you have to do is reference the JavaScript file that GWT generates. For now you'll use server-side code to load the albums recorded by the specified artist. You'll write this data directly to your XForms model instance data, as shown in Listing 11.


Listing 11. Inline data using server logic
                
<?xml version="1.0" encoding="UTF-8"?>
<xhtml:html xmlns:xforms="http://www.w3.org/2002/xforms" 
xmlns:xhtml="http://www.w3.org/1999/xhtml">
<%@page import="org.developerworks.rockstar.client.*" %>
<%@page import="org.developerworks.rockstar.server.*" %>
<%@page import="java.util.List" %>
    <xhtml:head>
        <xhtml:title>Albums</xhtml:title>
        <xforms:model id="albums">
            <xforms:instance id="albumData" xmlns="">
                 <Data>
                 <%
                      int artistId = Integer.parseInt(request.getParameter("artistId"));
                      AlbumDao dao = new AlbumFileDao();
                      List<Album> albums = dao.getAllAlbums();
                      for (Album album : albums){
                           if (album.getArtistId() == artistId){
                 %>
                      <Album>
                           <Title><%= album.getTitle() %></Title>
                           <Year><%= album.getYear() %></Year>
                      </Album>
                 <% 
                           }
                      }
                 %>
                 </Data>
            </xforms:instance>
        </xforms:model>
</xhtml:head>
    <xhtml:body>
         <xhtml:div id="albumList">
              <xforms:repeat id="repeatItem" nodeset="/Data/Album">
                   <xhtml:div>
                        <xforms:output ref="Title">
                             <xforms:label>Title:</xforms:label>
                        </xforms:output>
                        <xforms:output ref="Year">
                             <xforms:label>Year:</xforms:label>
                        </xforms:output>
                   </xhtml:div>
              </xforms:repeat>
         </xhtml:div>
    </xhtml:body>
</xhtml:html>

The Java scriptlet handles the logic to figure out which albums to show. Again you are loading this data from an XML file. The filtering logic is contained in an external class that can be downloaded as part of the source code for this article. Note once again you'll create some test data in an XML file. The test data is also included with the article's source code.


Testing XForms pages in Web mode

Now you're ready to test your XForms albums page. So far you've been testing your GWT artists page using GWT's hosted dode. You can launch in hosted mode once again, but you'll need to switch over to GWT's Web Mode for testing your new page. Why is this? XForms relies on a browser plugin that would not be present in GWT's hosted mode. Figure 4 shows how to switch to Web mode.


Figure 4. Switching to Web mode
switching to Web mode

Clicking on Compile/Browse will bring up the application in Web mode, as shown in Figure 5.


Figure 5. Application in Web Mode
Application in Web Mode

You should see the application now running in your default Web browser. Now you can click on one of the artists and you should see the interface shown in Figure 6.


Figure 6. Testing the Artists Page
Testing the Artists Page

Your page shows a list of albums for the artist. It uses some simple XForms controls to iterate the XML data from the model's instance data. In Part 3 you'll see how you can add XForms controls for data entry and wire this to GWT Ajax calls to allow for record company executives to add new albums on this page.


Summary

In this article, Part 2 of the rock star series, you've seen how you can build an interactive page using GWT and link it to a page that uses XForms. In Part 3, you'll refactor the rock star application built in this part. You won't actually change the functionality of the application created here, but you'll see how you can start using GWT elements on the same page as XForms elements to make the application more interactive.



Download

DescriptionNameSizeDownload method
Part 2 sample coderockstar2_src.zip12KB HTTP

Information about download methods


Resources

Learn

Get products and technologies

Discuss

About the author

Michael Galpin has been developing Java software professionally since 1998. He currently works at Ludi Labs, a start-up in Mountain View, Calif. He holds a degree in mathematics from the California Institute of Technology.

Comments (Undergoing maintenance)



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=XML, Java technology
ArticleID=258197
ArticleTitle=Integrate XForms with the Google Web Toolkit, Part 2: Creating an artist and album management form
publish-date=09252007
author1-email=mike.sr@gmail.com
author1-email-cc=ruterbo@us.ibm.com

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Special offers