Sun Java Solaris Communities My SDN Account Join SDN
 
Article

PeekAndPick 1.1 Design and Implementation

 

The PeekAndPick application allows you to browse news headlines and have story links emailed to your desktop. This article describes the client application from a developer's perspective. It covers relevant background information, provides a high-level view of the application, and describes components that you can use in your own applications.

PeekAndPick is an end-to-end Java application, consisting of both a MIDlet client and a simple servlet. This article presents the client side of PeekAndPick and discusses the protocol used between the client and server.

You may wish to download the source code so you can examine the files as you read the article. I'll also assume you are already familiar with PeekAndPick from a user's perspective; if you need to find out more, read the User's Guide.

The PeekAndPick source code is available as a zipped archive. There are two ways to build the application. You can use the J2ME Wireless Toolkit (J2MEWTK) graphic interface (KToolbar) to build PeekAndPick, or you can use Ant on the command line. Both methods rely on tools in the J2MEWTK, which in turn relies on an installation of Java 2, Standard Edition (J2SE) SDK. See Wireless Development Tutorial Part I for details about installing the J2MEWTK.

Building PeekAndPick

To build PeekAndPick using KToolbar, follow these steps:

  1. Unzip the source archive into the apps directory of the J2MEWTK installation. This will create a new project directory, PeekAndPick11, and upack files into bin, build, lib, res, and src subdirectories.
  2. Run KToolbar.
  3. Click on Open Project... and choose PeekAndPick11 from the list. Click on Open Project.
  4. Click on Build. The project should build without errors. You can now run PeekAndPick by clicking on Run.

To build PeekAndPick using Ant, follow these steps:

  1. Download and install Ant.
  2. Unzip the PeekAndPick source archive in the directory of your choice.
  3. Edit the build/build.xml script. You may need to adjust the value of the midp property to point to your J2MEWTK installation.
  4. Open a command window and change to the build directory of the source code. Type ant. The project should build without errors.
  5. To run the project in the emulator, type ant run.

If you wish to use the JAX obfuscator, you will need to download and install it separately. Make sure the jax property in build.xml points to the JAX classes and change the depends attribute of the preverify target from obfuscate_null to obfuscate_jax.

Similarly, if you wish to use the Retroguard obfuscator, make sure the retroguard and midp_lib_empty properties are properly defined. Change the depends attribute of the preverify target from obfuscate_null to obfuscate_retroguard. (For more information on Retroguard, see Obfuscating a J2ME MIDlet suite.)

The build.xml script provides several other targets that may interest you:

  • The clean target removes subdirectories of the build directory that are created during the build process.
  • The reallyclean target does what clean does and also removes the compiled project and other files.
  • The docs target uses javadoc to generate API documentation for the PeekAndPick classes. You can also browse this documentation online.

RSS Crash Course

To understand how PeekAndPick works, you'll need to understand something about RSS feeds. RSS stands for Rich Site Summary; it's an XML application. An RSS file (a feed) contains a description of the contents of a Web site. The site you are reading has an RSS feed located at http://wireless.java.sun.com/xml/wd.rss. (Depending on your browser and configuration, you may or may not be able to view this file easily.) This site's RSS feed lists the most recently added items on the site. For each item, the RSS feed contains a title, a URL, and a short description.

The power of this simple XML file is that any client application that recognizes RSS can now read a summary of this site. RSS clients are available for many different platforms. Such clients can easily pull news summaries from various feeds around the Internet and present them in a variety of ways to the user.

The Meerkat service, hosted by the O'Reilly Network, takes the idea of RSS one step further. Meerkat aggregates many different RSS feeds and can output the aggregated items as RSS again. Meerkat has a documented API which makes it an extremely powerful and flexible tool for extending other applications. You can ask for specialized results, for example retrieval of items that have been added in the last ten days that come from feeds that pertain to wireless technology. You can perform keyword searches. You can retrieve results in a variety of formats, not just RSS.

RSS is well documented and widely supported. For more information, try these resources:

PeekAndPick Architecture

PeekAndPick is an RSS client application written in Java for the Mobile Information Device Profile (MIDP). Its architecture looks like this:

PeekAndPick architecture
PeekAndPick architecture

PeekAndPick makes two different kinds of network connections. First, it connects to RSS feeds to download article information and display it to the user. Second, PeekAndPick connects to the PeekAndPick server to send email.

PeekAndPick can, in theory, connect to any RSS feed on the Internet. The current version is limited to several feeds that have been hardcoded in the application. PeekAndPick downloads and parses a feed and displays a list of the item titles. The user can browse through the titles, view details for an item, and check off items that look interesting.

After the user has finished checking items, the links for those items can be placed in an email message and sent to the user. The PeekAndPick client application makes an HTTP connection to the PeekAndPick servlet running on a Web server. The servlet connects to an email server and sends the message.

Internal Architecture

The PeekAndPick client consists of about 20 classes and interfaces:

PeekAndPick UML class diagram excerpt
PeekAndPick UML class diagram excerpt
(Click for a full size image.)

The application's center is PeekAndPick, which is a MIDlet. PeekAndPick controls all the other classes in the application. It also responds to the user's input from several different screens and figures out what to do next.

PeekAndPick calls on classes and interfaces in four packages. The contents of these packages are described below; later I'll go into more detail, especially about code that you might use in your own applications.

  • The default package contains classes that are specific to the PeekAndPick application. Instances of Feed represent the RSS feeds used by PeekAndPick. FeedStore provides persistent storage for Feeds, and Parameter also supports Feed.
  • The rss package is dedicated to parsing RSS documents. Parser is an abstract class that defines basic behavior. Concrete subclasses are expected to be able to parse an RSS document represented by an InputStream. While they parse, they should spit out events to registered ParserListeners. One concrete subclass, kXML12Parser, is provided. It uses the kXML 1.2 parser.
  • The util package contains a generalized Worker class that is used for threading support. PeekAndPick's performs its network access in a separate thread to avoid locking up the user interface. The Worker class maintains a queue of tasks that will be run in a single separate worker thread. The tasks are represented by instances of the WorkerTask interface, which contains only a run() method, just as Runnable does. When tasks are complete, or when tasks throw exceptions, a registered WorkerListener is notified.

    The util package also contains a generalized Preferences class and an associated GUI; PeekAndPick uses Preferences to store the user's email address and the address of the PeekAndPick server.
  • Finally, the display package contains generalized user interface components. ListCanvas, ItemCanvas, and DisplayItem handle display of the list of titles as well as details for a particular article. SplashScreen displays the starting image for the application, and WaitDisplayable shows an animated wait screen while PeekAndPick makes network connections.

Using a Worker Thread

util.Worker provides a general approach to the problem of running tasks in a separate thread. Worker maintains a queue of WorkerTasks, which are run in the order they are added to the queue. When one task finishes, the next is started. If the queue is empty, Worker patiently waits for a new task to be added.

An application is notified about task completion or exceptions if it implements the WorkerListener interface.

PeekAndPick uses Worker to execute two tasks. The first, ParseTask, retrieves and parses RSS files. The second, MailTask, connects to the PeekAndPick server to request that it send email.

Using the Worker class is straightforward. PeekAndPick begins by creating a Worker and registering itself as the listener object. This code is in PeekAndPick's initialize() method:

// mWorker is a member variable.
mWorker = new Worker();
mWorker.setWorkerListener(this);

It's easy to use the worker thread in an application of your own; just create an instance of WorkerTask and pass it to the Worker. For example, the following code from PeekAndPick's commandAction() shows how to create a task for parsing an RSS feed:

// mParser is a member variable, a Parser instance.
// feed contains the currently selected Feed.
ParseTask task = new ParseTask(mParser, feed, null);
mWorker.queue(task);

Creating a task isn't even that hard. All you do is implement the WorkerTask interface and put the code for the task inside the run() method. See ParseTask and MailTask for examples.

Why doesn't Worker just use java.lang.Runnable instead of the new WorkerTask interface? Worker needs to catch exceptions thrown by tasks. The run() method of Runnable throws no exceptions, so it doesn't provide the functionality that Worker needs.

You can read more about the general problem of running network activity in its own thread in Networking, User Experience, and Threads.

Persistent Preferences

One common problem faced by network client MIDlets is storing user preferences. PeekAndPick's Preferences class provides a generalized class for maintaining and storing user preferences.

User preferences are stored as key and value pairs, where each key and each value is a String. This is a lot like the java.util.Properties class in J2SE. You can add or replace a value using put(), or pass a key to get() to retrieve a value. Preferences also includes a putIfNull() method that you can use to initialize missing values. This excerpt from PeekAndPick's initialize() method shows how the Preferences object is created. If the preferences can't be loaded (if the application is being run for the first time), the values are initialized from system properties.

// mPreferences is a member variable.
mPreferences = new Preferences("PeekAndPick.preferences");
String email = getAppProperty("PeekAndPick.preferences.email");
String server = getAppProperty("PeekAndPick.server.URL");
mPreferences.putIfNull("Email address", email);
mPreferences.putIfNull("PeekAndPick Server", server);

Preferences store themselves using MIDP's RecordStore. When you create a Preferences object you pass the name of a record store to the constructor. Preferences attempts to load itself from that record store. To save a Preferences object after making changes, call the save() method.

Editing Preferences

PreferencesEditor is a user interface component that provides controls to allow users to modify the values of a Preferences object. It is a subclass of javax.microedition.lcdui.Form. To create a PreferencesEditor, pass a Preferences object and a String array of non-editable keys to the constructor. The PreferencesEditor will not display user interface controls for non-editable values.

PeekAndPick maintains an email address and a server URL in its Preferences object. The email address (key is "Email address") is entered by the user, but the server URL (key is "PeekAndPick Server") should not be editable and should not even be shown to the user. PeekAndPick's getPreferencesEditor() method creates the editor this way:

// mPreferences is a member variable.
String[] noShows = { "PeekAndPick Server" };
mPreferencesEditor = new PreferencesEditor(mPreferences, noShows);

This editor form is shown when you choose the Prefs command. PreferencesEditor creates one TextField for each editable value in the Preferences object. For PeekAndPick, the "Email address" is the only editable value, so the PreferencesEditor contains a single TextField:

PreferencesEditor with a single field
PreferencesEditor with a single field

You can reset an existing PreferencesEditor to the new values of a Preferences object by calling its initialize() method. To retrieve the edited values from the form, call the extract() method. This method returns a Hashtable with keys and values for each of the fields in the form. Note that the returned Hashtable does not contain any of the non-editable key and value pairs. You can take the values returned by extract() and pass them to the set() method in Preferences, which adds to or overwrites the existing values.

Pluggable Parsing

Parsing RSS is one of the simpler tasks in PeekAndPick. I designed the parsing classes so it would be easy to swap in different XML parsers with minimal changes to the code in the rest of the application. In PeekAndPick, the job of parsing XML is implemented by a concrete subclass of the abstract rss.Parser.

Parser is relatively simple. It contains the plumbing for maintaining a list of listeners, and protected methods for firing various events to those listeners. Its one abstract method is parse(). This method is expected to parse the given RSS byte stream and notify the listeners appropriately.

rss.kXML12Parser is a concrete subclass that uses the kXML 1.2 parser. It's relatively simple; it just walks through the document, searching for item tags and pulling out the information it needs.

Fortunately for code maintenance, PeekAndPick doesn't know much about kXML12Parser. The only place the name even comes up is at creation time, in PeekAndPick's initialize() method. PeekAndPick creates the parser and adds itself as an event listener.

// mParser is a member variable of type rss.Parser.
mParser = new kXML12Parser();
mParser.addParserListener(this);

Thereafter, PeekAndPick treats the object as a Parser instance, which means it would be easy to drop in a different implementation. Suppose kXML 2.0 is released. I could write a kXML20Parser class that uses the new version and change the initialization in PeekAndPick to use the new class. Everything else would stay the same.

Instead of creating the parser subclass explicitly, I could even use Class.forName() and use a system property to specify the name of the implementation class, but I feel that going this far would be overkill.

For more information about using XML parsers in MIDP and the specific task of parsing RSS, read Parsing XML in J2ME.

Lists and Details

The class that displays PeekAndPick's list of article titles is display.ListCanvas. It is not specific to PeekAndPick or RSS. It can display any list of items, where each item consists of a name, a description, and another piece of text that is not shown to the user. In addition, ListCanvas allows the user to check or uncheck each item in the list.

ListCanvas in action
ListCanvas in action

You can add items to ListCanvas by calling addItem(). Item information can be retrieved using the getShortText(), getLongText(), and getExtra() methods, each of which takes an index to the item. Alternately, you can retrieve a complete item with getItem(), which returns an instance of DisplayItem.

ListCanvas is a subclass of Canvas and handles key events. Specifically, a press on the right-arrow key of the device will cause ListCanvas to display details for a single item using ItemCanvas. You can also request this behavior using the details() method. Similarly, ItemCanvas will respond to a left-arrow key press by returning to the original ListCanvas.

The setMarkingAllowed() method in ListCanvas controls whether or not marking (checking) will be supported. If it is, ListCanvas will toggle the check mark for an item each time the select key is pressed. You can find out whether an item is checked by calling the isMarked() method.

This class is similar, functionally, to the MULTIPLE type of javax.microedition.lcdui.List. I created ListCanvas to allow more sophisticated navigation without relying on Commands exclusively. Note that, like List, ListCanvas adjusts itself to the available screen size, so it looks right on a mobile phone as well as a Palm OS device.

A Simple Splash Screen

The display.SplashScreen class is a simple implementation of a splash screen that displays an image. To create it, pass the constructor the name of the image file, a Display object, and the next screen that should appear after the splash screen goes away.

The splash screen dismisses itself after a hardcoded time-out (two seconds). It will also dismiss itself in response to a key press or a pointer press.

Client-Server Protocol

You already understand how PeekAndPick parses RSS feeds. In this section I'll describe how the PeekAndPick client MIDlet talks to the PeekAndPick server. The purpose of this communication is to allow the MIDlet to request the server to send email. The protocol is very simple; the client MIDlet sends an HTTP POST request whose body is of this form:

log line
destination line
message line 1
message line 2
...
message line n

The first line contains information that the servlet can write into the server log. In PeekAndPick's current implementation this line is blank. The second line is the destination email address, which is the address the user entered into the preferences screen. The remainder of the request body is the message itself. The MIDlet creates this message from the items that are marked in the title list.

On the server side, the servlet simply parses out the information from the HTTP POST request and uses the Java Mail API to create a message and send it.

Summary

In this article you learned about the design and implementation of the PeekAndPick client MIDlet. You encountered many classes you can use in your own applications. PeekAndPick is a useful application and a demonstration of MIDP client programming. It should give you a taste of how an end-to-end Java solution works. Please feel free to use pieces of PeekAndPick in your own applications, subject to the license.



Back To Top