Turn Your J2ME Mobile Devices into Web Service Clients

o, Web services are big and getting bigger, but what does that mean to Java development, specifically J2ME, for mobile devices? Until recently, the answer was “not much” unless you wanted to implement the entire Web services infrastructure yourself. However, in 2004, the Java Community Process approved and finalized JSR-172, the J2ME Web Services Specification. More recently, Sun and IBM have added implementations of this specification into their J2ME development environments, and importantly, some mobile products such as those running Symbian Series 60 OS now come with this optional J2ME API.

J2ME Web services are based on the general Web services architecture and specifications, but looking at them from strictly the client, or service consumer, vantage point, J2ME Web services consists of two optional packages: one for remote service invocation (Java API for XML-based RPC or JAX-RPC) and one for XML parsing (Java API for XML Processing or JAXP). By design, the packages are independent from one another; allowing for the use of one without the other. The APIs are meant to provide Web service access via profiles from either J2ME Connected Device (CDC) or Connected Limited Device Configurations (CLDC). To help you learn more about these two APIs and how they work to provide access to Web services in J2ME applications, this article explores a small, example Java Web service and J2ME MIDP MIDlet.

What You Need
To build and run the example, here is the list of tools you will need:

  • Sun’s J2ME Wireless Toolkit 2.2: Sun’s J2ME development toolkit provides build tools, utilities, and device emulators.
  • Tomcat 5.0 for Java WSDP: This Web container is based on Apache’s Jakarta Tomcat. It implements the JSP and servlet specifications. While it is not intended for production use, it provides an easy-to-learn and use platform for hosting a Web service.
  • Java Web Services Developer Pack 1.5: A Web service toolkit that can be integrated with the Tomcat Web container (above) that will allow you to build and test Web services.
  • Apache Ant: A Java-based tool for building and deploying your Web service.

Each of the above tools download and install in a matter of minutes. The tools to create and run the application will be used “as is.” Simply follow the instructions for installation with each product.

You will also need something to create and edit your Java code and XML files. The associated code with this article should be extracted right into the apps directory of your Wireless Toolkit download. Extract the code from the download file into your WTK22/apps directory.

The Example Application
Imagine you work for a large life insurance company. Insurance agents are meeting potential clients all the time. Using their J2ME mobile phones, these agents want to be able to gather some simple personal facts about their clients (name, age, whether the client smokes, etc.). They then want to send these facts off to the corporate office in order to get policy plans and quotes they can immediately share with their clients (see Figure 1). The example application in this article provides a Web service that serves up policy plans and a J2ME MIDlet that your insurance agents can use to access the Web service.

Figure 1. Tutorial Application User Interface: The life insurance agent enters data about a client into a J2ME MIDlet form (screen1), requests policy plans and quotes from the corporate Web service, and then shares the policy options and information with the client (screens 2 and 3).

Developing the Example Application
The formula for developing this application can be divided into two parts: developing the Web service and developing the J2ME MIDlet that accesses that Web service. The basic steps to create a Web service and deploy it to the Tomcat server are as follows:

  • Write the Web service interface class.
  • Write the Web service implementation class.
  • Write the associated descriptor files (all XML files).
  • Compile the service and generate Web services stubs/ties and WSDL file using tools provided with the Java Web Services Developer Pack.
  • Deploy the web service to the Tomcat server.

With the Web service ready to provide insurance information deployed and running, the basic steps to creating the J2ME Web service client are:

  • Use the generated WSDL file and the tools built into the Wireless Toolkit to generate the stubs and supporting code used by the MIDlet to access the Web service.
  • Code the MIDlet and associated classes using JAX-RPC to invoke the Web service and JAXP to process the SOAP message.
  • Build and test the MIDlet on the Wireless Toolkit emulator(s).

The Web Service
Those familiar with RMI, EJB, or other forms of distributed application development probably recognize the first two steps in developing a Web service. The interface class declares the methods on the insurance policy Web service that clients (in this case J2ME clients) can invoke. The code for the Web service is located in the server subdirectory of the InsuranceQuote folder you downloaded and set up earlier. Take a look at the com.roaminginsurer.QuoteService code in Listing 1. There’s not a lot to it. It defines the protocol or contract by which the client and Web service communicate. In this case, the client calls the service, the getQuote method, with a client’s name, age, marital status, number of children, salary, and smoking status. The Web service returns a string. The string is actually an XML document containing recommended life insurance policy information.

The implementation of the Web service com.roaminginsurer.QuoteImpl can be found in Listing 2. This Web service is constructed on JAX-RPC. Note that the interface extends java.rmi.Remote and the service method throws java.rmi.RemoteException. These are indications that Web services are very RMI like. The implementation class implements the javax.xml.rpc.server.ServiceLifecycle interface along with the Quote interface. By implementing the ServiceLifecycle methods, the Tomcat Web container can manage the Web service through the init and destroy methods.

Inside the getQuote method, the XML document response is created. The method creates a DOM object tree. The Document Object Model (DOM) is an API for working with XML documents and the API is used here to create a tree of policy objects. Inside of the init method, a document factory is created.

        this.context = (ServletEndpointContext) context;        factory = DocumentBuilderFactory.newInstance();        try {            builder = factory.newDocumentBuilder();        } catch (ParserConfigurationException e) {            builder = null;        }

Then, in the getQuote method, elements representing policies are attached to the document. Each element has attributes that contain the policy coverage amount and annual rate. Below is the code that creates the “Gold” policy.

			Element gold = document.createElement("Gold");			gold.setAttribute("coverage",coverage + "");			gold.setAttribute("cost",rate + "");			root.appendChild(gold);

The XML document must finally be converted to a string for transport to the client. This is accomplished in the toString method.

Compiling the Web Service
Three other descriptor files are required for completing the Web service and deploying it to Tomcat:

  • web.xml: The standard deployment descriptor describes how to deploy the components (in this case, the Web service component).
  • config.xml: An XML configuration file that describes the Web service.
  • jaxrpc-ri.xml: An XML configuration file that describes how to deploy the Web service.

Tools in Sun’s Java Web Services Developer Pack 1.5 use these last two files. When compiling the Web service, the interface and implementation classes must be compiled (good old javac), but another process is also required. The wscompile tool, using information from the config.xml, generates the stubs, ties, and the Web Services Description Language (WSDL) file. Stubs and ties are the low-level classes that the server needs to communicate with a client. More information on the WSDL file will be provided later.

The download code contain Ant scripts (build.xml) for compiling, building, and deploying the Web service. In the server directory, a build.properties file contains the root directory location for Tomcat, the project directory, etc. Before using the ant script, edit the properties in the file listed below to match your environment.

tomcat-root=C:/tomcat50-jwsdpjaxrpc-root=${tomcat-root}/jaxrpcj2ee-root=${tomcat-root}/jwsdp-sharedproject-root=C:/WTK22/apps/InsuranceQuote/server

Before compiling the service, take a look at the call to the wscompile tool in the ant script.

								   					

A very important argument to the wscompile task is the list of features to be enabled; namely wsi and documentliteral. As the JAX-RPC API for J2ME only supports the literal representation of a SOAP message (no XML encoding), these features will allow a simple J2ME client to communicate with the service.

To compile the Web service, simply call on Ant with the following directive:

ant compile

If all goes well, you should see the generated stubs and ties in a subdirectory of the server directory called generated and the compiled code in the WEB-INF subdirectory. The WSDL file should also be available in the WEB-INF/classes subdirectory.

Building and Deploying the Web Service
The last steps to providing this Web service is to build the .war file and deploy it to the server. As part of the build process, you will use the second of two tools, wsdeploy tool reads a .war file and the jaxrpc-ri.xml file and subsequently generates another WAR file that is ready for deployment. Run the following Ant directives to build your war file (and have wsdeploy rebuild the file) and deploy the war file to the Tomcat server. In the Ant script I have provided, the deploy task will also start Tomcat with the new web service running in it.

ant buildant deploy

Figure 2. Web Service Build and Deploy Success: If the compile, build, and deploy process are successful, you should see the status of your Insurance Quote Web service via your browser when you request the appropriate address.
 
Figure 3. The Entry Form: The GetQuoteMIDlet, on start up, displays the EntryForm in order to get client information.

To test whether your service has been properly built and deployed, you should be able to open a browser and enter the following http://localhost:8080/quoteservice/quoteservice in the address field and see something similar to what is shown in Figure 2 display in the browser window.

J2ME Web Service Client
Whew! With the Web service in place, you can now focus on the J2ME application that will call on the Web service. For this, you will need Sun’s J2ME Wireless Toolkit, as it offers an important tool to create the necessary client side stubs and test your J2ME application’s communications with the Web service through device emulators.

Open the Wireless Toolkit and request to Open Project. If you have placed the code provided into the apps directory of the Wireless Toolkit’s root directory, then InsuranceQuote should be one of the projects listed. Open the InsuranceQuote project.

Generating J2ME Client Side Stubs
Remember the WSDL file you generated building the Web service? That file is going to be used by the Wireless Toolkit to generate the client-side stub code used by your MIDlet to access the Web service. This stub is a class that is a local Java object that acts as a proxy for the Web service instance. Your MIDlet makes a local method call to the stub and the stub, in turn, calls the Web service on the server.


Figure 4. The PolicyList: After getting and parsing the policy quote list XML document from the Web service, the GetQuoteMIDlet allows the user to select a policy for display through the PolicyList screen.
 
Figure 5. Policy Data Displayed in an Alert: After selecting a policy form the PolicyList screen, the policy data is displayed in an Alert screen.

Open the WSDL file with your favorite text or XML editor. It should be in your [WTK22]appsInsuranceQuoteserverWEB-INFclasses directory. The wscompile tool generated the WSDL and left you with one job. You must change the last line of the WSDL file to specify the actual address location of your service.

Change:

To:

With that change, select the Project?>Stub Generator option on the Wireless Toolkit tool bar. In the window that displays, select the quoteservice.wsdl file you just edited and enter com.roaminginsurer.quoteservice as the package for the stub code that is generated. If you take a look in the ./InsuranceQuote/src/com/roaminginsurer/quoteservice directory, you should now see a set of Java files that define the stub and associated objects needed to communicate with the Web service.

Figure 6. Navigating the GetQuoteMIDlet Screens: When the GetQuoteMIDlet launches, it displays the EntryForm. After entering in client information and hitting the GetQuote command, the list of policy quotes is displayed in the PolicyList. Finally, the policy quote data for the policy selected is displayed in an Alert screen.

The MIDlet User Interface
Now you have a Web service and the client-side classes necessary to communicate with the Web service. On to developing the MIDlet application!

The MIDlet provided as part of this sample application uses a J2ME MIDP Form and a List screen (both from the javax.microedition.lcdui package) to drive the user interface. The MIDlet uses an instance of the form EntryForm to collect client information that the MIDlet will pass to the Web service (see Listing 3). The EntryForm as seen on an emulator screen is shown in Figure 3.

The MIDlet uses a List called PolicyList (see Listing 4) to display the policies returned by the Web service (see Figure 4).

When the insurance agent selects one of the policy quotes from PolicyList, an instance of javax.microedition.lcdui.Alert is used to display the policy information (see Figure 5). The entire MIDlet user interface navigation is modeled in Figure 6.Calling the Web Service with J2ME JAX-RPC
In the commandAction method of the GetQuoteMIDlet, when the user has hit the GetQuote command, the first of the two methods is invoked. Namely, the MIDlet calls the requestQuote method.

		if (label.equals("Get Quote")) {			requestQuotes();		}

The requestQuote method collects all the client data out of the EntryForm and then requests to start a separate GetQuoteMIDlet thread.

       new Thread(this).start();

You might have noticed that the GetQuoteMIDlet implements the Runnable interface. Why does requestQuote start a new thread? If the operation was done in the commandAction method or other MIDlet method, then the MIDlet would have to wait for the Web service to respond. This could end up blocking the main Event Loop and other operations. Putting the call to the Web service in its own thread allows the MIDlet to continue to respond to the user (to answer the phone for example). In fact, if you place the call to the Web service in the same thread, you get the following warning when you run your application:

Warning: To avoid potential deadlock, operations that may block, such as networking, should be performed in a different thread than the commandAction() handler.

As the GetQuoteMIDlet implements the Runnable interface, it is in the run method creates an instance of the Web service stub class you generated earlier (Quote_Stub), sets up some properties on that instance, and makes a call to the Web service.

try {	service = new Quote_Stub();	service._setProperty(Quote_Stub.SESSION_MAINTAIN_PROPERTY, new Boolean(true));	String xmlStr = service.getQuote(name, age, married, children, salary, smoker);	parseQuotes(xmlStr);} catch (Exception exception) {	Alert serviceProblem = new Alert("Service problem","Try your request later",null, AlertType.ERROR);	serviceProblem.setTimeout(Alert.FOREVER);	display.setCurrent(serviceProblem, form);	}

Because of the potential for a remote exception (remember the RMI RemoteException that was part of the Web service interface?), the call is wrapped in a try catch block. A small part of the java.rmi package has been bundled with JAX-RPC just for this purpose. Where else do you see JAX-RPC here? If you look at the generated code, the Quote_Stub class implements the Stub interface from JAX-RPC and the other classes and methods are also from the J2ME JAX-RPC package.

Parsing the XML Using JAXP
Once the Web service has been called and the J2ME application has received the XML document (in the form of a string), the MIDlet will take advantage of the second Web service API, the JAXP API, to parse the XML and offer the life insurance client some information about policies.

Most of the parsing work in the sample application is done in the parseQuote method of the MIDlet. This method is called by the run method and is sent the string received in the Web service. It sends the XML string to a SAX parser and Handler to extract the element data out of the XML document into POJOs (plain old Java objects?in this case InsuranceQuote Java objects).

An instance of com.roaminginsurer.QuoteParserHandler (which inherits from org.xml.sax.helpers.DefaultHandler) were created with the MIDlet initialization in the startApp method.

	parserHandler = new QuoteParserHandler();    try {         SAXParserFactory factory = SAXParserFactory.newInstance();         saxParser = factory.newSAXParser();    } catch (Exception e) {

The SAXParser and superclass DefaultHandler are both from the JAXP API. When the XML document is received the parser and handler are engaged to extract data from the document.

	parserHandler.reset();	saxParser.parse(new ByteArrayInputStream(xml.getBytes("UTF-8")), parserHandler);

The SAXParser (SAX stands for Simple API for XML Parsing) reads the XML document and detects the beginning and end of the document, start and end of each element in the document, and so on. As it detects or parses the parts of the document, it calls on the associated handler instance to do something with the information located.

As seen in Listing 6, the QuoteParserHandler overrides the DefaultHandler's startElement method. As the SAXParse detects the start of each new element (in this case the start of each new policy quote) it puts the element's attribute information into a plain old Java object (POJO).

The POJOs are collected and then passed on to the displayQuote method where the policies are listed in the List screen and the details are shown in an Alert screen when requested by the user.

	displayQuotes(parser.getQuoteObjects());
Figure 7. The Final Product: The GetQuoteMIDlet can be tested through any of the emulators provided with the Wireless Toolkit.

Building and Running the MIDlet
All that is left to do is to build and test your MIDlet. The Wireless Toolkit makes this easy. Simply push the Build button on the tool bar, fix any compile errors, and then push the Run button to execute your MIDlet in the emulator selected. Make sure your Web service in Tomcat is still up and running so that it can respond to the J2ME client's request.

Limited Functionality
The J2ME Web services APIs (JAX-RPC and JAXP) are still subsets of the enterprise versions of these packages. J2ME devices, by nature, are limited and so too are the Web service features they can support. Below is a list of some of those limitations and features the current implementations do not support.

  • No support for service endpoints (no J2ME device based web services?only clients).
  • No service discovery support (UDDI).
  • Validating parsers are not required given memory and processor needs.
  • SOAP 1.1 encoding is not supported.
  • SOAP messages with attachments are not supported.
  • SOAP message handlers are not supported.
  • XSLT is not supported.
  • DOM is not supported.
  • No support for dynamic proxies or dynamic invocation interface (DII).

A simple search for "J2ME Web services issues" in Google will give you plenty of additional information about the shortcomings of this new set of J2ME APIs. The issues range from the size of the packages, to security, to handling loss of connectivity. You should also know that there are also some alternatives in open source side (kSOAP and kXML).

The calls for "more" and "better" are not unfamiliar in our industry, but don't let that overshadow what these new APIs can do. I view these calls as harbingers that Web services for J2ME devices are here to stay and coming soon to expand your enterprise systems.

Share the Post:
Share on facebook
Share on twitter
Share on linkedin

Overview

Recent Articles: