This tutorial takes the background information on GWT History Management provided in the Managing History and Hyperlinks tutorial and uses it to create an RSS reader application that uses this history mechanism to load initialization parameters. The application that’s built in this tutorial takes the RSS feed URL as a parameter passed to the web app’s URL. The feed URL must be preceded by “#”. For example, to load this feed: http://feeds.feedburner.com/blogspot/NWLT, you would have to load the following URL in the GWT test browser (in hosted mode):
If you are unfamiliar with GWT basics, please refer to our GWT Intro, Anatomy of a GWT Project, and Hello World tutorials. To learn more about GWT, I recommend reading these good books on Safari Books Online – GWT Solutions, GWT Applications, AJAX Security.
ROME – Java RSS API
We are going to build a GWT service that actually loads the RSS feed using ROME – https://rome.dev.java.net/. It’s a very easy-to-use API that allows you to consume and generate various types of syndication feeds (RSS and Atom formats including RSS 0.90, RSS 0.91 Netscape, RSS 0.91 Userland, RSS 0.92, RSS 0.93, RSS 0.94, RSS 1.0, RSS 2.0, Atom 0.3, and Atom 1.0). When we get to the service implementation portion of the tutorial, I will show you how to use it, if you don’t already know how.
The RSS Reader App
This tutorial is meant to show you how to write an application that uses history. The Managing History and Hyperlinks tutorial gives you the background information you need, and shows you how to “think” about History when building your GWT app. This tutorial takes the next step and shows you a sample application that uses history to load an RSS feed. There are other ways to pass parameters to GWT apps that don’t involve using the History mechanism. However, the application in this tutorial will take this approach.
When you click on the links inside theis app, it uses GWT history to send the RSS Reader App the history token, which is a URL to load the RSS feed. This results in a service call to the RPC service that gets the contents of the feed and returns this data to the app. The app then displays this information in a grid. For deployment, the entire app can be loaded in an iframe. You can choose to deploy it using a div as well, but this would require you to include the style sheet for this app to your webpage’s HTML HEAD tag. If you don’t want to mess with the HTML HEAD tag to include the stylesheet, just use an iframe.
This app does a lot of things (load RSS feeds, create widgets, create and show popups, use history to pass parameters, etc). Let’s take a deeper look at each one of these in the following sections. You can download all the source code and IDEA project files here.
Using browser history to pass parameters
Let’s take a look at the code that integrates the GWT history mechanism into the RSS Reader App:
- The initHistory() method is called when the app is first launched from the ReaderEntryPoint class. This method registers a listener for history change events with the History class. When the history changes, the onHistoryChanged() method is called, which simply passes the token to the updateStateWithNewFeed() method – this method takes care of resolving the URI passed as the token, and displaying it in the app.
- When the initHistory() method is executed for the first time, when the app loads via it’s entry point class, it checks to see if there are any tokens that were passed to the app via the URI, and if none were passed, it sets an initial history token (NO_URL), and this lets the updateStateWithNewFeed() method know that there’s no URI to resolve into feed data. The app then displays the “Got a new browser history change token: INITIAL STATE” message (in a label on the bottom) and it will respond to you clicking on any of the 3 hyperlinks (Google Web Toolkit Blog RSS feed, Sun Developer News RSS feed, and SwingLabs Forum RSS feed).
- By the way, these 3 hyperlinks were created using the Hyperlink class, which can take a history token as a parameter. When you click on this hyperlink, it will trigger GWT’s history mechanism, and it causes the onHistoryChanged() method, which will then cause the RSS feed to be loaded and displayed in the app. So really, the hyperlink becomes the way to trigger functionality in your app, and it causes the state of the app to change, and based on this state change, you can activate different parts of your app’s functionality.
- Since the app itself is loaded in an iframe, once you’ve click on a few RSS feeds, you can go back and forth between the browser history (inside that iframe) by right clicking on the iframe and selecting Back and Forward.
So that’s the main driver for this application, hyperlinks with tokens embedded in them, that you can activate by clicking on these hyperlinks. Each click translates to a call to onHistoryChanged(), which then makes the app load the URI passed as the token.
Using ROME to get data from an RSS feed URI
Let’s take a look at the code that gets executed when you do click on any one of the 3 hyperlinks:
- The updateStateWithNewFeed() method takes the token that’s passed in the URI (from the Hyperlink that was created with the same token), and it displays it to the browser in a label. This label is styled using the CSS style “statuslabel“. You can change the way this label looks by changing that style in the Style.css file that’s provided in the source code.
- Once the feed URI is displayed on the bottom of the app, the app makes a call to the service GetFeedService’s getFeedEntries() method, and it passes the token as a parameter. The GetFeedServiceImpl then takes the URI/token parameter and uses ROME to load the RSS feed into a List of FeedEntry objects (which contain the name, description, link, and author of each feed entry). All the FeedEntry objects are sent back to the client in a FeedEntryList, which is then processed by the updateGrid() method.
Here are more details on the GetFeedServiceImpl’s getFeedEntries() method:
- The main class that we use from ROME is SyndFeed and SyndFeedInput. We ask SyndFeedInput to resolve the provided URI to a SyndFeed. Also, ROME uses JDOM to do it’s XML parsing.
- A SyndFeed object contains a list of SyndEntry objects, which are then queried to get the author, title, uri, and description out of. If you want to send back more information then just copy more fields out of the SyndFeed object and send it back to the client by passing it to the FeedEntry class.
In order to send data back from the SyndFeed to the GWT app, select fields are copied to a FeedEntry object:
- The FeedEntry class and FeedEntryList class are serializable by GWT.
The FeedEntryList class is made serializable using the typeArgs annotation:
- Since the ArrayList contains only objects of type FeedEntry, the typeArgs annotation is provided for the GWT compiler.
Once the client app gets the FeedEntryList, it creates HTML objects out of them and then adds them a Grid, and this is displayed in the browser.
You can see all the code that builds the Grid and PopupPanels here:
- The GridBuilder class is responsible for taking a FeedEntryList and populating a Grid with it. This Grid is then added to a ScrollPanel that’s contained in the MainPanel class that creates the UI.
- Note the use of PopupPanel again to display more details on each FeedEntry object. The author and description are put in a PopupPanel and then displayed on the right side of the app. If you want to change the appearance of this popup, change the following style in Style.css: “infopopuplabel“. The popup is displayed as a result of the user’s mouse entering each row of the grid. When the mouse leaves a row, it’s associated popup is supposed to go away (hide() gets called). If you find that a popup is still visible, even though you’ve moved your mouse away from it’s row in the grid, then just click on it, and it will hide.
Finally, here’s the MainPanel that assembles the UI:
- Essentially the main user interface is made up of a DockPanel to which some links get added on the top, and the grid containing FeedEntryList on the bottom. You can change the appearance of these links by changing this CSS rule: “linkspanel“. You can change the appearance of the ScrollPanel added to the DockPanel by changing this rule: “gridscrollpanel“.
- Note the call to initHistory() in the constructor. This constructor is called by the entry point class.
Application loading screen revisited
There are 2 loading messages displayed by the RSS reader app:
- “app loading” the 2nd message “Starting RSS Reader App” is shown when the app is executing, but hasn’t displayed the INITIAL STATE message or loaded the very first RSS feed (if a feed URI is passed as a token).
This application shows a loading screen until the INITIAL STATE message is displayed in a popup, or a feed is loaded if it’s passed in the URI the first time the app is loaded. In order to do this, the entry point class expects a div of id “appdiv” to exist in the HTML host page. Here’s the code for the entry point:
Here’s the HTML host page:
- The HTML host page has a div with id “loadingdiv”. This is where the “JS loading” message is created. This is removed as soon as the app’s entry point class executes GWTUtils.removeElementFromDOM(LoadingDiv).
- The second thing that happens when this module loads is the “app loading” message gets displayed on the browser, via a call to GWTUtils.addLoadingMessage(“loading.gif”, “Starting RSS Reader App”, AppDiv). This loading message is inserted in the div with id “appdiv” by the GWTUtils.addLoadingMessage() method. It basically inserts an HTML widget in the app’s div element, and this widget displays a message and an animated image to show something is loading.
- Also note that the MainPanel itself is created in a DeferredCommand. This is just to make it so that the browser stays responsive once the loading screen is displayed.
- In the MainPanel class, once the INITIAL STATE message is displayed in a popup or the first feed data is loaded, the “app loading” message is replaced with the MainPanel’s DockPanel. This is done using GWTUtils.replaceLoadingMessageWith() method.
This is a very simple way to ensure that the loading screen is displayed consistently on all browsers, and the code is relatively simple. Feel free to use GWTUtils in your own projects. Also, another advantage of using this technique is that you don’t have to do a whole lot in the HTML host page. Just make sure there’s are 2 divs in your app and you should be good to go to use GWTUtils:
- a div for the app, and make sure to assign it the id of “appdiv“
- a div for the JS loading message, and make sure to assign it the id of “loadingdiv”.