What is Ext GWT 2.0?

«»

SHARE & COMMENT :

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

  • 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

    1. Add an addExistingFeed method to the FeedService interface that takes the
      URL of a feed as an argument:

 void addExistingFeed(String feedUrl);
 
    1. Add a corresponding asynchronous version of the addExistingFeed method to
      the FeedServiceAsync interface:

 void addExistingFeed(String feedUrl, AsyncCallback<Void>
 callback);
 
    1. 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();
 }
 });
 }
 
    1. In the FeedServiceImpl class , create a new Java Logging logger for the class:

 private final static Logger LOGGER =
 Logger.getLogger(FeedServiceImpl.class
 .getName());
 
    1. 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;
 }
 }
 
    1. 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>();
 
    1. Create a new instance of the FilePersistence class:

 private final Persistence persistence = new FilePersistence();
 
    1. 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());
 }
 }
 
    1. 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:

  1. 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

    1. 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);
 
    1. 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()));
 
    1. Start the application and create a new feed using the Create feed button, complete
      the form as follows, and click on the Save button:

    1. Check that Example Feed appears in the feeds ListField:

    1. 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

    1. Add a loadFeedList method to the FeedService interface :

 List<Feed> loadFeedList();
 
    1. Add an asynchronous version of the loadFeedList method to the
      FeedServiceAsync interface :

 void loadFeedList(AsyncCallback<List<Feed>> callback);
 
    1. 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:

Once we have retrieved data using a DataProxy, if it is not represented as ModelData
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:

There is also a TreeModel-specific DataReader that we will cover in later chapters.

You may notice that an object called ModelType is used by many of the data readers to
perform conversion of the data.

GWT Articles

«»

Comments

comments

Pages: 1 2 3

About Krishna Srinivasan

He is Founder and Chief Editor of JavaBeat. He has more than 8+ years of experience on developing Web applications. He writes about Spring, DOJO, JSF, Hibernate and many other emerging technologies in this blog.

Speak Your Mind

*

Close
Please support the site
By clicking any of these buttons you help our site to get better