Server-side persistence
So far we do not have any persistence in our example application.
To make the example more realistic, we will now add persistence. As this is a GXT book
rather than a GWT book, we will only implement basic server-side persistence so that we
can concentrate on the client-side. However, we will put the actual persistence logic behind
an interface so that we can replace it with another implementation later if required. For the
initial implementation:
GWT Articles
- Buy GWT in Action from GWT Books Store
- Comparison of AJAX Frameworks
- Google Web ToolKit(GWT)
- When creating new feeds, we will simply save an XML file on the server-side.
- We will keep a list of the URLs of the feeds that we have created and any imported
feeds in a simple text file.
The persistence code implementation is not GXT-specific, so it can be treated as a black box.
The Persistence interface and a FilePersistence implementation of that interface can
be found in the example code. It is this that we are going to make use of to store and retrieve
RSS feeds.
Persisting an Existing Feed
In the second chapter, we created the Link feed button, the purpose of which was to
let our RSS reader import an existing RSS feed from the Internet. We will now create an
addExistingFeed method in the FeedService that with the help of the persistence layer
stores the URL of the feed for later retrieval. We will then connect this method to the add
button on the LinkFeedPopup.
Time for action – persisting a link to an existing feed
- Add an addExistingFeed method to the FeedService interface that takes the
URL of a feed as an argument:
void addExistingFeed(String feedUrl);
- Add a corresponding asynchronous version of the addExistingFeed method to
the FeedServiceAsync interface:
void addExistingFeed(String feedUrl, AsyncCallback<Void>
callback);
- Modify the addFeed method of the LinkFeedPopup class so that it retrieves the
FeedService and calls the addExistingFeed method with the URL that the user
has entered. If successful, the method should clear the URL TextField and hide
the Popup:
public void addFeed(final String feedUrl) {
final FeedServiceAsync feedService = Registry
.get(RSSReaderConstants.FEED_SERVICE);
feedService.addExistingFeed(feedUrl, new AsyncCallback<Void>()
{
@Override
public void onFailure(Throwable caught) {
Info.display("RSS Reader", "Failed to add feed at: " +
feedUrl);
}
@Override
public void onSuccess(Void result) {
tfUrl.clear();
Info.display("RSS Reader", "Feed at " + feedUrl
+ " added successfully");
hide();
}
});
}
- In the FeedServiceImpl class , create a new Java Logging logger for the class:
private final static Logger LOGGER =
Logger.getLogger(FeedServiceImpl.class
.getName());
- Again in the FeedServiceImpl class, create a new private method named
loadFeed . The method takes an URL string and uses JDOM to retrieve the XML
of an RSS from the Internet. It then parses the XML into a Feed object . This is
implemented as follows:
private Feed loadFeed(String feedUrl) {
Feed feed = new Feed(feedUrl);
try {
SAXBuilder parser = new SAXBuilder();
Document document = parser.build(new URL(feedUrl));
Element eleRoot = document.getRootElement();
Element eleChannel = eleRoot.getChild("channel");
feed.setTitle(eleChannel.getChildText("title"));
feed.setDescription(eleChannel.getChildText("description"));
feed.setLink(eleChannel.getChildText("link"));
return feed;
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "IO Error loading feed", e);
return feed;
} catch (JDOMException e) {
LOGGER.log(Level.SEVERE, "Error parsing feed", e);
return feed;
}
}
- Create a new instance of a HashMap to store Feed objects with their URL as a key:
private Map<String, Feed> feeds = new HashMap<String, Feed>();
- Create a new instance of the FilePersistence class:
private final Persistence persistence = new FilePersistence();
- Implement the addExistingFeed method so that it uses the loadFeed method
to retrieve the Feed object corresponding to the provided URL String. Check that
the Feed has a title and add it to the HashMap of Feed objects and then use the
saveFeedList method of the FilePersistence class to persist the updated list:
@Override
public void addExistingFeed(String feedUrl) {
Feed loadResult = loadFeed(feedUrl);
if (loadResult.getTitle() != null) {
feeds.put(feedUrl, loadFeed(feedUrl));
persistence.saveFeedList(feeds.keySet());
}
}
- Start the application and add an existing feed by clicking on the Link feed button,
entering an URL in the link feed popup, and clicking on the add button:

- In the war\data folder, check that there is now a text file named feed.txt
containing the URL that you entered in the user interface.
What just happened?
We used the server to retrieve the RSS XML from a specified URL and persist the URL on the
server for later use in the application.
At the moment, if we create a new feed and click on the Save button, a feed object is added
to the feed ListStore on the client, but this is just a cache and not a persistent data store.
In the last chapter, we created a GWT RPC service with a saveFeed method . This sent a
Feed object to the backend, but so far all it does is convert the feed object to XML and print
the result to the console. The XML is not saved, and any Feed objects created will be lost
when the application is restarted. We will now add to our implementation of the saveFeed
method so that it makes use of file persistence.
Time for action – persisting a feed as an XML document
- In the FeedServiceImpl class, remove the existing XML serialization code at
the end of the saveFeed method and in its place add a call to the saveFeedXml
method of the Persistence interface. The call should include the UUID of the
Feed object and the JDOM document generated from it. This will write a file
containing an XML representation of the Feed:
persistence.saveFeedXml(feed.getUuid(),document);
- Also append a call to the addExistingFeed method. The parameter for this call
should include the URL to the XML file created on the file system. This is retrieved
from the getUrl method of the Persistence interface:
addExistingFeed(persistence.getUrl(feed.getUuid()));
- Start the application and create a new feed using the Create feed button, complete
the form as follows, and click on the Save button:

- Check that Example Feed appears in the feeds ListField:

- Finally, check that a new file has appeared in the war\data folder. It will have a
filename in the format of <uuid>.xml: for example, 4a529f45-31af-4375-
9da4-4b03280a4784.xml. Check that the file contains the following content:
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
<title>Example feed</title>
<description>This is an example feed</description>
<link>http://www.example.com/example-feed.xml</link>
</channel>
</rss>
What just happened?
We created a mechanism to persist the XML representation of a Feed object as an XML file.
Server-side retrieval
Once feeds have been saved on the server, we need to be able to load them when we start
the application again. For this we will add a loadFeedList method to the feed service. This
will return Feed objects by loading RSS feeds from the URLs stored in the feeds.txt file.
We will then add any Feed objects we retrieve into the client’s feed store.
Time for action – loading feeds
- Add a loadFeedList method to the FeedService interface :
List<Feed> loadFeedList();
- Add an asynchronous version of the loadFeedList method to the
FeedServiceAsync interface :
void loadFeedList(AsyncCallback<List<Feed>> callback);
- In the FeedServiceImpl class , implement the loadFeedList method so
that it populates the feeds HashMap using the loadFeedList method of the
Persistence interface, and then returns a list of the Feed objects now contained
within it:
@Override
public List<Feed> loadFeedList() {
feeds.clear();
Set<String> feedUrls = persistence.loadFeedList();
for (String feedUrl : feedUrls) {
feeds.put(feedUrl, loadFeed(feedUrl));
}
return new ArrayList<Feed>(feeds.values());
}
What just happened?
We added the ability to retrieve Feed objects from previously persisted XML files via a call
to a GWT RPC service. We now have a service that persists Feed objects and allows us to
retrieve them again.
Using remote data
As well as populating stores with data on the client-side, we can also populate stores by
retrieving remote data. GXT provides facilities for loading and working with remote data, be
it XML or JSON retrieved via HTTP, or objects retrieved through GWT RPC. For each source,
GXT provides mechanisms to retrieve and read data. If necessary, it can also convert the raw
data into ModelData and then automatically add it into a Store.
There are several components involved in this process. They all perform a function in their
own right but come together to retrieve and process data:
- DataProxy—retrieves the raw data from the source
- DataReader—takes the raw data and converts it into ModelData
- Loader—loads the processed data into the store automatically
The interaction between the various components is summarized in this diagram:

DataProxy interface
A DataProxy is used to retrieve raw data. All data proxies implement GXT’s DataProxy
interface. There are a number of DataProxy implementations, that retrieve diff erent types
of data in diff erent ways:

objects already, we will need to convert it using a DataReader before it can be loaded
into a Store.
DataReader interface
Data readers translate raw data into ModelData objects. All data readers implement GXT’s
DataReader interface. There are several diff erent implementations of DataReader that
deal with diff erent raw data. A DataReader returns the results as one of the following:
- A set of ModelData objects.
- An object that implements the ListLoadResult interface. ListLoadResult
contains one method, getData() that returns the data as ModelData objects. - A PagingLoadResult object, which extends ListLoadResult to provide
support for paging—that is, the ability to return a subset of the data.
Paging is when the data is not displayed all at once, but instead presented
in pages. For example, if you had 100 results and wanted to display them
10 per page in a grid, you may have a control at the bottom that displays
1-10 of 100, and a button to move to the next page. We will cover paging in
later chapters.
There are a number of diff erent implementations of DataReader summarized in this table:


You may notice that an object called ModelType is used by many of the data readers to
perform conversion of the data.
GWT Articles
- Buy GWT in Action from GWT Book Store
- Comparison of AJAX Frameworks/li>
- Google Web ToolKit(GWT)