Getting to Know J2ME Polish

Tuesday Dec 20th 2005 by Robert Virkus
Share:

Discover how J2ME Polish can help you with the development of wireless Java applications.

In this sampe chapter from Pro J2ME Polish: Open Source Wireless Java Tools Suite:

  • Get to know the architecture of J2ME Polish—the build framework, client API, IDE plug-ins, and stand-alone tools layers.
  • Learn how J2ME Polish can help you with the development of wireless Java applications, as you design, implement, build, test, optimize, and deploy each J2ME application.

This chapter provides you with an overview of the architecture of J2ME Polish. It also shows you how J2ME Polish helps you in the different phases of the development of your J2ME applications.

J2ME Polish from 500 Miles Above

J2ME Polish is collection of components for the development of wireless Java applications. The various components can be separated into four different layers, as shown in Figure 5-1.

Each layer features several components:

Build framework: You use the build framework to build your J2ME applications. This Ant-based framework allows you to preprocess your source code before it is compiled, and it compiles, preverifies, and packages your application for multiple devices and locales. A logging mode can be used for tracing errors in your application. Take advantage of the device database and the preprocessing to adjust your application to various handsets, without losing the portability of your application.

Client framework: The client framework provides APIs for enhancing your wireless Java application. It includes an alternative to the high-level Mobile Information Device Profile (MIDP) user interface. The J2ME Polish GUI is designed outside the application code using simple Cascading Style Sheets (CSS) text files. The game engine allows the usage of the MIDP 2.0 game API on MIDP 1.0 devices, so you can easily port games to MIDP 1.0 platforms. The WMAPI wrapper enables you to use the Wireless Messaging API, even on devices that support only vendor proprietary methods for sending and receiving messages. Last, but not least, the utility classes provide common functionalities, such as the TextUtil or the BitMapFont classes. Thanks to the build framework, the client framework is automatically adjusted to the target devices, so that you can use a full-screen mode on almost all phones, for example.

IDE plug-ins: The IDE plug-ins ease the development of J2ME applications in the popular Eclipse IDE. The preprocessing-aware Java editor plug-in provides syntax highlighting for preprocessing statements, for example. Since the build framework is based on Ant, you can still use J2ME Polish from within any IDE or even from the command line.

Stand-alone tools: J2ME Polish also includes several stand-alone tools. The binary data editor is specialized for creating and modifying structured binary files, like level data, while the font editor creates bitmap fonts out of any True Type.

These layers are tightly integrated. The logging framework has a client-side API, but it is controlled with the help of the build framework, for example. In the following chapters, you will get to know each layer intimately.

Note: J2ME Polish is growing constantly, so make sure to check out the web site at http://www.j2mepolish.org to learn about the latest additions.

Managing the Application Life Cycle with J2ME Polish

Creating a J2ME application involves several distinct phases:

  • Design: In the design phase, you plan the architecture of the application.
  • Implementation: In the implementation phase, you realize the design and write the source code.
  • Build: In the build phase, you compile your source code and create the application bundles (JAR and JAD files).
  • Testing: In the testing phase, you check the implementation.
  • Optimization: In the optimization phase, you improve the application, focusing on performance, memory consumption, application size, and device adjustments.
  • Deployment: Finally, you install your application on the device in the deployment phase.

Here, we will take a closer look at each phase of the application life cycle. You'll see how you can use J2ME Polish for fast turnaround times in these phases, as well as learn some tips for each phase of the application life cycle.

Designing the Architecture

When you design the architecture of your application, you should strive to make it as simple as possible. You might already know that the pure object-oriented approach is not always the best one when designing a J2ME application. Each class adds overhead, and every abstraction slows down your application. But even so, you should try to create a clean and logical structure for your application, so that later changes do not result in unintentional side effects.

Bear the following recommendations in mind when you design your application (but do not follow them slavishly):

  • Try to avoid abstract classes and interfaces. Often, you'll find preprocessing more effective for keeping your application flexible without using abstraction.
  • Remember that each class increases your application size, so try to group functionalities to minimize the number of classes.
  • Implement interfaces only when it is necessary. Instead of implementing the CommandListener interface in every screen, consider using a single dispatcher or controller class that is responsible for the application flow, for example. And don't create your own abstract event-handling system.
  • Design for reusability by defining independent classes or modules, which can be used in other contexts and applications. Check if you can parameterize them, and don't be afraid of using different packages. The obfuscation step and J2ME Polish will take care of putting all classes into the default package, so that the size of the application is minimized.
  • Do not overoptimize the design, such as by putting the complete application into one class. Leave drastic optimizations to the optimization phase, and remember that some devices accept classes only up to 16KB.
  • Do not duplicate functionality. If you're using the J2ME Polish GUI for example, try to use these classes instead of implementing your own additional GUI classes.
  • Try to use proven and stable third-party APIs instead of creating your own implementations, unless the needed functionality belongs to the core of your business. Thanks to the different behavior of the devices, creating stable APIs for J2ME is quite a challenging and complex task.

So to summarize these tips, your goal is to design a solid and clean architecture, but not overengineer it by using a heavy object-oriented approach.

Implementing the Application

You realize your application in the implementation phase. Along with the source code itself, you often need to create resources such as images and server-side application code.

For programming the actual source code, you can use an IDE or even a simple text editor, depending on your preferences. If you are new to Java programming, make sure to check out the free Eclipse and NetBeans IDEs. Both offer quite powerful environments and are excellent for J2ME programming. If you're using Eclipse, have a look at the compiler options under Window->Preferences->Java->Compiler. You can activate many different warnings, which will help you to create clean code.

J2ME Polish helps you to implement your application by providing a powerful API that covers the user interface, network, and utilities tasks. The IDE plug-ins ease the programming of preprocessing code and allow fast turnaround times in the implementation phase.

Building Your Application

Building J2ME applications is necessary for running them, either on the emulator or on the actual device. At the very least, you need to compile your source, preverify the classes, package the classes and resources into a JAR file, and create the Java Application Descriptor (JAD) file. Often, you also need to choose the appropriate resources, translate your application, pre-process the source code, and obfuscate your application.

Does this sound like hard work? It is, but fortunately, it is completely automated by J2ME Polish. Chapter 7 discusses the details of building your applications.

Testing the Application

After implementing and building your application, you are ready to test it by running it on emulators and real devices. J2ME Polish can invoke emulators automatically for you, so that you can test your application with a single mouse click. When your application encounters an exception, stack traces given out in the emulators often show only the binary offset of the code, such as at com.company.MyClass.myMethod(+20). J2ME Polish resolves such stack traces automatically when the Jad decompiler (discussed in Chapter 3) is installed.

Caution: Testing your application on real devices is crucial to its success. Never rely on an emulator. Test as early and as often as possible on the real device.

J2ME Polish also provides a logging framework, which offers different logging levels and the ability to view logging messages on real devices. You can specify logging levels for packages and classes, and deactivate the logging completely, so that no precious space is wasted in the final application.

You'll learn more about invoking emulators in Chapter 7, and you'll get to know the details of the logging framework in Chapter 9.

Optimizing Your Application

When you implement and test your first prototype, you usually discover shortcomings that need to be fixed in the optimization phase. Typical shortcomings include the following:

  • Device-specific bugs: You encounter bugs on some devices, but not on others. You can solve these problems by using preprocessing for circumventing device-specific bugs. Chapter 8 describes how to preprocess your application with J2ME Polish. In Chapter 15 you will learn what problems you might encounter in the real world and how you can solve them.
  • Application size: Your application is too large. Usually, you can use automatic resource assembling to optimize resources usage and adjust your application's architecture. The automatic assembling of resources is discussed in Chapter 7.
  • Application performance: The performance is not as good as expected. You can use a variety of techniques for improving your application's performance. Chapter 16 is devoted to optimization strategies.

Deploying Your Application

Deploying your application on real handsets is a crucial step in the lifetime of your application. You can use different methods for installing your application, ranging from data cables to over-the-air downloads.

Bluetooth, Infrared, and Data Cables

The easiest way to install your application is to use a Bluetooth connection, which most devices provide nowadays. Usually, it is sufficient to send the generated JAR file (which contains the classes and the resources of your application) to the phone. How this is done depends on your operating system and your setup. Often, you simply right-click the file and select Send to Bluetooth Device or a similar option. Modern devices start the installation automatically directly after they have received the JAR file, but sometimes you need to look in the phone's incoming messages folder and select the sent file to start the installation.

Very similar to using Bluetooth is using an infrared connection or data or USB cable. Please refer to the documentation of your device for instructions on setting up such connections.

Over-the-Air Provisioning

The only standardized way to deploy your J2ME application is the over-the-air (OTA) download. In this scenario, you need a web server that delivers the JAD and JAR files of your application.

In a simple case, you can use a simple Wireless Markup Language (WML) page like the one in Listing 5-1. That page can be accessed with the Wireless Application Protocol (WAP) browser of the device and just provides a link to the JAD file. When the device reads the JAD file, it will forward the control to the Application Manager System (AMS). The AMS then shows some details (title, vendor, and size of the application) and prompts the user to download the actual application file (the JAR).

Listing 5-1. Sample WML Page That Links to a JAD File

<?xml version="1.0"encoding="ISO-8859-1"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"
 "http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
   <card title="Download"id="main">
      <p>
         <a href="myapplication.jad">Download Application</a>
      </p>
   </card>
</wml>

Most web servers are already configured to handle JAR and JAD files correctly. If your device does not recognize those files, you just need to add the text/vnd.sun.j2me.app-descriptor MIME type for .jad files and the application/java type for .jar files to the configuration of your web server.

If you have problems accessing the WML page, check your connection settings on your device. Some WAP gateways do not allow ports other than 80, so test this port as well if you encounter difficulties.

In a more complex scenario, you can generate the WML pages on the fly for the current device by evaluating the USER_AGENT HTTP header and using a server-side scripting technology such as JavaServer Pages (JSP) or PHP. You could also send links to the JAD files via binary short messages (as a WAP link) or with simple text messages.

Also, third-party OTA servers are available. These usually offer different provisioning technologies, device recognition, and payment solutions.

Note: Using OTA in the development phase is a pain, since you need to copy the application first to the web server, and then download it from the server again. This takes quite a lot of time and can be costly as well. So check if there are other installation options available for your device.
Multimedia Message Provisioning

Some devices can also receive J2ME applications by using the Multimedia Messaging Service (MMS). Users find this much more convenient than bothering with normal OTA downloads, since no additional interaction is required (apart from selecting the application and the device on a web page). You will need a Short Message Service (SMS) center to send those messages for you.

Tracking Your Installations

If you publish your application on the Internet, it isn't easy to find out how many times it has been installed. Fortunately, the J2ME standard allows notifications at each installation as well as removal of your application. The optional JAD attribute MIDlet-Install-Notify contains the HTTP address, which should be invoked after the application has been installed. The device will try to call the given address and report the status in its content, such as 900 Success. If the web server sets a cookie during the installation, this cookie might also be returned in the installation notification, as demonstrated in Listing 5-2.

Listing 5-2. A Notification of a Successful Installation

POST http://foo.bar.com/status HTTP/1.1
Host:foo.bar.com
Cookie:Name="abc";Domain=".foo.bar";Path="/app-dir";
       JSESSIONID="123";VERSION="1"
Content-Length:13
900 Success

Table 5-1 lists the possible status codes.

Table 5-1. Status Codes of the Installation Notification

Status Code Status Message
900 Success
901 Insufficient Memory
902 User Cancelled
903 Loss of Service
904 JAR Size Mismatch
905 Attribute Mismatch
906 Invalid Descriptor
907 Invalid JAR
908 Incompatible Configuration or Profile
909 Application Authentication Failure
910 Application Authorization Failure
911 Push Registration Failure
912 Deletion Notification

You can also track the deletion of your application by setting the JAD attribute MIDlet-Delete-Notify. The device will then try to send a POST request stating 912 Deletion Notification upon removal.

You can specify MIDlet-Install-Notify and MIDlet-Delete-Notify by defining the <info> attributes installNotify and deleteNotify in J2ME Polish. You'll learn more about setting attributes in Chapter 7.

Caution: Do not rely on receiving each installation or deletion notification. Network failures and user interactions can suppress this mechanism.

Updating Your Application

Updates are quite important for business applications, but they can be equally desirable for long-running networked games. Update options depend on the platform.

MIDP 1.0 Platforms

Unfortunately, on MIDP 1.0 platforms, there is no way to trigger an update from within your application. Here are a few update strategies to consider:

  • Query the current version whenever you make your first handshake with the server-side application. Depending on the business requirements, you could then notify the user that an update is available, or the server can deliver content specific to the version of your client J2ME application. When an active user chooses to update the application, you could send an SMS text message containing the link to the latest JAD file on the server. Most devices can now identify HTTP-based links in SMS messages and start the WAP browser directly.
  • Send a binary message that contains a WAP-link to the user. The user can then save and invoke that link.
  • Send the complete application via an MMS message to the user's handset. This is the most user-friendly way, but not all devices support deployment via MMS.
MIDP 2.0 Platforms

On MIDP 2.0 platforms, you can start the update process directly from within your application by issuing a platform request. Since platform requests are handled differently by real-world devices, you should prepare to exit your application after requesting an update. In any case, your application will be shut down before the update is actually put into place. Listing 5-3 shows an example of a MIDlet that persists its current version in a RecordStore so that it can detect updates.

Listing 5-3. Issuing an Update Request from Your Application (MIDP 2.0)

package com.apress.update;
import javax.microedition.io.ConnectionNotFoundException;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;
import javax.microedition.rms.RecordStore;
import javax.microedition.rms.RecordStoreException;

public class UpdateMidlet extends MIDlet {
   private static final int VERSION =125;  //1.2.5
   public UpdateMidlet(){
      super();
}
protected void startApp()throws MIDletStateChangeException {
   try {
      RecordStore versionStore =RecordStore.
         openRecordStore("version",false );
      versionStore.closeRecordStore();
      byte [] versionData == versionStore.getRecord(
                             versionStore.getNextRecordID()-1 );
      String versionStr = new String(versionData );
      int version = Integer.parseInt(versionStr );
      if (version != VERSION ){
         //app has been updated:
         showUpdateMessage();
         //remove version record store:
         RecordStore.deleteRecordStore("version");
      return;
   }
   }catch (RecordStoreException e){
      //no update has been requested
   }
showMainMenu();
}
protected void requestUpdate(){
   //#ifdef polish.midp2
      try {
         //request update:
         //#if updateUrl:defined
            //#=platformRequest("${updateUrl}");
         //#else
            platformRequest("http://www.company.com/app/update.jad");
         //#endif
         //persist current version:
         RecordStore versionStore = RecordStore.openRecordStore(
                                    "version",true );
         byte [] versionData ==Integer.toString(VERSION ).getBytes();
         versionStore.addRecord(versionData,0,versionData.length );
         versionStore.closeRecordStore();
      }catch (ConnectionNotFoundException e){
         //#debug error
         System.out.println("Unable to issue update request"+e );
      }catch (RecordStoreException e){
         //#debug error
         System.out.println("Unable to persist current version"+e );
      }
   //#endif
   }
   protected void showMainMenu(){
      //TODO implement showMainMenu
   }
   protected void showUpdateMessage(){
      //TODO implement showUpdateMessage
   }
   protected void pauseApp(){
      //ignore
   }
   protected void destroyApp(boolean unconditional)throws
             MIDletStateChangeException {
      //exit gracefully
   }
}

Devices should ask users whether they want to keep the data when an update is installed. In most cases, it is at least possible to keep the data that has been stored in the record store. Depending on your application's needs, you should also consider storing the user data on the server before an update is requested. You can then add the user's ID to the JAD file that is used for the update. When your application is started and there is no user data, you can check that ID and download the data from the server.

Obviously, there are some security risks here, because JAD files can be changed very easily. So you need to ensure both that the user is really the intended user (authentication) and that any valid user who ended up with an invalid ID for some reason can change that ID.

Summary

The chapter introduced you to the general architecture of J2ME Polish. You gained an insight in the four main layers: the build framework, client framework, IDE plug-ins, and stand-alone tools. You also learned about the life cycle of wireless Java applications and how J2ME Polish can help you in each phase.

Pro J2ME Polish: Open Source Wireless Java Tools Suite
by Robert Virkus for Apress

# # #

Share:
Home
Mobile Site | Full Site
Copyright 2017 © QuinStreet Inc. All Rights Reserved