ONCE upon a time, not so long ago, Web services were going to be the next big thing. Web services referred to specific methods of making Web server functionality available to other applications, and everyone fully expected an interoperable nirvana of communicating systems. The air was pungent with the smell of unwieldy acronyms like WS-I, XML-RPC, WSDL, and UDDI, and everyone had to make sure that their products and technologies were going to work with the coming wave of Web services. Collectively, this approach is known as WS-*, and it is more about a distributed computing scheme (think CORBA or DCOM) than anything specific to the World Wide Web.
Web services did turn out to be one of the next big things. As usual, things didn’t turn out quite how everyone planned. While the cool kids like Google and Flickr are exposing their functionality to developers, and Web 2.0 seems well underway, the emphasis has faded from WS-*. A different, lighter approach called Representational State Transfer (REST) is a popular way to make Web services available to client applications.
The Extensible Markup Language (XML) is here to stay, regardless of the fate of its various Web services’ cousins.
Java ME got caught up in the WS-* hype, and the result was JSR 172, which defines an XML parsing (JAXP) API and a JAX-RPC API for consuming WS-* services. The XML parsing API will probably be useful well into the future, but the JAX-RPC API will most likely appeal only to developers who must connect a MIDlet to some existing SOAP service. Developers of entirely new systems should strongly consider a RESTful approach.
This chapter describes how to use the XML parsing API, how to call WS-* Web services using the JAX-RPC API, and how to work with RESTful Web services. Examples will show how to parse a Rich Site Summary (RSS) feed, how to invoke a WS-* Web service, and how to write a RESTful client for the Flickr photo-sharing service.
Regardless of the future of Web services, XML is an important part of the computing world. JSR 172’s JAXP API is useful in a wide variety of applications.
Several different flavors of XML parsers are available in the desktop world. The JAXP API conforms to the Simple API for XML (SAX) standard, defined here:
The SAX parts of the API live in org.xml.sax
, while the rest of the JAXP API is in javax.xml.parsers
.
A SAX parser is a push parser, which means it runs through an entire document, spitting out events as it goes. In your application, you supply a handler (a listener) that gets notified whenever the parser finds something in the document.
The parser itself is jaxp.xml.parsers.SAXParser
. You can get one from a SAXParserFactory
, like this:
You can use methods in SAXParserFactory
to change the options on the parser returned by newSAXParser()
. For example, you can specify whether or not you want a validating parser.
Once you’ve got a parser, you need to supply a handler and give it a document. Your handler should be a subclass of DefaultHandler
(in org.xml.sax. helpers)
, and the document to be parsed is represented by an InputStream
or an InputSource
.
Your DefaultHandler
subclass is where most of the action happens. DefaultHandler
has empty methods that get called by the parser. To do something interesting, override some or all of these methods in your handler subclass.
Here is a class, CheapHandler
, which overrides three of DefaultHandler
’s methods. It uses the startElement()
and endElement()
methods to keep track of the current element hierarchy. In addition, it overrides characters()
to find out when character data is parsed.
CheapHandler
is a simplified handler for XML parsing. I use it in the rest of the examples in this chapter. You can create a simple subclass of CheapHandler
and override the processCharacters()
method or processStart()
method. Each method is passed a tree
argument, which represents the parser’s current position in the document hierarchy. Nested tags are separated by a pipe character.
RSS is a simple XML format used for summaries of blogs, news Web sites, and other content. RSS files are placed in known locations at a Web site and updated to reflect updates to the main content of the Web site. RSS files are often called feeds.
This section presents a MIDlet that retrieves an RSS feed that contains the top ten songs sold in the iTunes music store. You could easily modify this MIDlet to retrieve other types of RSS feeds.
You can see the network connection and XML parsing happens in run()
, performed in a separate thread.
The SAX handler is TopTenHandler
, a simple subclass of CheapHandler
. Whenever characters are encountered that are part of a title
element, they are appended to the main form.
One of the nice features of TopTenMIDlet
is that information is placed on the screen as soon as it is parsed (see Figure 21.1). This capability is especially important on wireless devices that are likely to have relatively slow network connections.
Figure 21.1. Information is displayed as it is parsed
Not many current devices have support for either of the JSR 172 APIs. However, if you just want to parse XML in a MIDlet, you can embed a small parser in your application. kXML 2 is an excellent choice:
For a dated look at the world of XML parsers in Java ME, try this article:
http://developers.sun.com/techtopics/mobility/midp/articles/parsingxml/
The size of the XML parser adds directly to your MIDlet suite JAR file size, but if that’s not a problem, you can fairly easily incorporate XML parsing in your application without requiring JSR 172 support on your target devices.
The kXML 2 JAR file is only 43 KB, and if you use an obfuscator, the impact on your MIDlet suite JAR can be much smaller.
The example code for this chapter includes a rewritten TopTenMIDlet
that uses kXML. You can run this version of the application on any MIDP 2.0 device without worrying about JSR 172 support. Look in the kb-ch21-kxml
project for the rewritten TopTenMIDlet
and a rewritten CheapHandler
helper class. The obfuscated JAR file size for this project, including another MIDlet from later in this chapter, is just 16 KB!
Using the kXML parser, org.kxml2.io.KXmlParser
, is fabulously easy. Create one and point it at a Reader
using the setInput()
method:
Then sit in a loop and call the parser’s next()
method, which parses the next thing in the document. Call methods on the parser to find out what was just read. Here is an example that parses through the document until it reaches the end:
For example, if the event type is KXmlParser.START_TAG
, you can find out the name of the tag with getName()
. If the event type is KXmlParser.TEXT
, you can retrieve the text with getText()
.
WS-* Web services are a kind of distributed computing. To use a WS-* Web service, you have to generate stub classes (during development) that represent the Web service. At runtime, you call methods on the stub class to invoke methods on the Web service. In the Java platform, this is very similar to Remote Method Invocation (RMI).
WS-* Web services are described by a Web Service Description Language (WSDL) file. To use a Web service in your application, you first must generate stub classes based on the WSDL description. Your development tool should be able to do this for you. In the Sun Java Wireless Toolkit, choose File > Utilities…, then launch the Stub Generator utility.
In NetBeans Mobility Pack, right-click on your project and choose Properties. Select Platform in the left pane, then click on Manage Emulators… on the right side. Click on the Tools & Extensions tab, then click Open Utilities. Finally, launch the Stub Generator.
You have to specify the location of the WSDL file, the destination for the generated stub classes, and to which package you would like the stubs to belong.
Once you have stubs, using them is pretty easy. Suppose you want to use a Web service that returns speeches from Shakespeare’s plays:
http://www.xmlme.com/WSShakespeare.asmx
First, generate the service stubs. Here is how to invoke the service:
First, create a ShakespeareSoap
object that represents the Web service. Then you can call methods, like getSpeech()
. Methods called on remote objects can throw RemoteException
if something goes wrong with the network communication.
Following is the complete MIDlet example, BillMIDlet
. It assumes that the Shakespeare Web service stubs are generated in the bill
package. The code example downloads for this chapter include the stub package and classes.
The Shakespeare Web service returns results as very simple XML documents, so BillMIDlet
uses the JAXP API to parse the results and present them on the screen. BillHandler
is a simple CheapHandler
subclass that takes care of the details. (See Figure 21.2 on page 307.)
Figure 21.2. Web services and William Shakespeare
To run BillMIDlet
, enter a few words from a speech and choose the Go command.
The Web services programming model that is spanking traditional WS-* Web services is Representational State Transfer, or REST. REST is an awful name, and it’s hard to understand exactly what it means. Like the Pirate Code, it is more of a set of guidelines than a specification or definition.
The main principles of REST are as follows:
In general, REST Web services are lighter and more flexible than WS-* Web services. For an allegorical look at the Web services debate, try Elliotte Harold’s essay here:
http://cafe.elharo.com/web/rest-vs-soap-a-parable/
The Java platform community seems to be catching up with the REST philosophy, as evidenced by the recent appearance of JSR 311:
http://jcp.org/en/jsr/detail?id=311
The Flickr photo sharing service is a great example of a RESTful Web service. The API for Flickr is documented here:
http://www.flickr.com/services/api/
To use this API, and to run this example, you need to get a developer key from Flickr. For experimentation, it is easy and free, but if you’re going to create commercial applications, you must follow a more rigorous application process. Consult Flickr’s Web site for complete details.
FlickrMIDlet
loads the developer key from an application property. To successfully run this example, you must place your developer key in the flickr-apikey
application property.
FlickrMIDlet
makes three calls into the Flickr API.
flickr.people.findByUsername
returns an identification number (NSID) that corresponds to a Flickr user name. An example URL for this method is here, split across multiple lines for readability:
This method returns a very brief XML document that associates the user name to an NSID. Here is an example response:
flickr.people.getPublicPhotos
returns a list of information about the public photos for a given NSID. Here is an example request URL:
The response, again, is a simple XML document, something like this:
The photos themselves are retrieved by creating URLs based on the information returned from flickr.people.getPublicPhotos
. In particular, the id
, secret
, server
, and farm
attributes are used. The URL scheme is described in the Flickr API documentation. FlickrMIDlet
uses a special designation to retrieve thumbnail photos, which are at most 100 pixels on a side, great for little mobile screens. Here is the image URL corresponding to the first item in the list above.
http://farm1.static.flickr.com/154/390271118_7676416608_t.jpg
In FlickrMIDlet
, two handler classes (FlickrUserHandler
and FlickrPhotoListHandler
) extract the important parts of each XML reply.
The photos themselves are returned as a byte stream of JPEG image data. Many MIDP implementations can decode JPEG data, and MSA requires this capability.
Here is the source code for FlickrMIDlet
, which runs the whole show. The network connections are implemented in lookupUser()
, lookupPictures()
, and lookupPicture()
, all of which are called from run()
, which lives in a separate application thread. The MIDlet keeps track of the current user name so that it doesn’t perform any unnecessary network work.
Both parser handler classes inherit from CheapHandler
, which you’ve already seen. Here is the handler that extracts an NSID from a user name query response.
The handler for a user’s public photo list is a little more complicated. As it reads the document, it creates an URL for retrieving each photo.
To run FlickrMIDlet
, just enter a Flickr user name and select the Next command. FlickrMIDlet
retrieves the user’s NSID, photo list, and the first photo in the list (see Figure 21.3).
Figure 21.3. Flickr pictures on your phone!
Keep choosing Next to see the rest of the photos in the user’s list.
In the source code download, the kb-ch21-kxml
project contains a rewritten version of FlickrMIDlet
that uses the kXML 2 parser instead of the JSR 172 API. You can run this version of FlickrMIDlet
on any MIDP 2.0 device.
FlickrMIDlet
is a nice toy and a great example of infusing a MIDlet with the massive power of the Internet. If you’d like to explore this example further, here are some ideas for improvements:
Error handling could be better. For example, if you enter a user name that does not exist, FlickrMIDlet
quietly reverts to the previous user name without telling you why. What about valid user names that have no public photos?
It would be wise for FlickrMIDlet
to keep a cache of the current user’s images. Network access is expensive in terms of time (and sometimes money), so caching loaded images would enable repeated viewing of a single user’s images.
FlickrMIDlet
would benefit from a custom Canvas
user interface for easier browsing and a prettier look.
It would be nice to save the current user name in a record store so it pops up automatically next time you start FlickrMIDlet
. A fancier approach would be to keep a list of favorite user names for quick browsing.
XML is a great format for structured data. The JSR 172 JAXP API provides basic tools for parsing XML documents. Most of the work is in a DefaultHandler
subclass, which gets notified about interesting events as the parser works through a document. XML is used as the basis for Web services, whether they are the heavy WS-* Web services or lighter RESTful Web services. The JSR 172 JAX-RPC API provides stub-based access to WS-* Web services. RESTful Web services can be invoked with specially constructed URLs, while XML results can be parsed using JAXP.
3.149.249.174