Welcome!

Hayden Marchant

Subscribe to Hayden Marchant: eMailAlertsEmail Alerts
Get Hayden Marchant via: homepageHomepage mobileMobile rssRSS facebookFacebook twitterTwitter linkedinLinkedIn


Related Topics: Java Developer Magazine

Java Developer : Article

The Challenges of Porting a Java ME Application to Multiple Devices

Coping with idiosyncrasies, the unexpected, and complexity

The familiar phrase attributed to Java applications of "write once, run everywhere" sadly does not apply to applications developed on Java ME.

While the Java ME standard ensures that runtime environments are consistent across devices, the many idiosyncrasies that exist outside the Java specification require that all ME applications be tailored to each device. The differences in behavior can range from unexpected exceptions when calling certain API calls to performance issues in certain operations on the device. These problems cause many difficulties for developers, who have to ensure that their applications will work well on all required devices and to an acceptable level.

Fixing a bug on one device can often cause a worse bug to emerge on another. In turn, adding simple features to an existing application can turn into an inflated task due to the unexpected behaviors that some devices take on when doing seemingly trivial operations. This makes testing Java ME applications that are being deployed on multiple devices a very complicated task that needs careful project planning to cope with the unexpected and manage the large volume of platforms on which to test.

So porting a Java ME application to multiple devices can be a daunting task. In this article, we'll discuss some of the common challenges encountered when developing a Java ME application designed to run on multiple devices and some approaches to overcoming them.

A View into the Java ME World
For a thorough understanding of the complexities of Java ME projects, let's walk through the lifetime of a Java ME application project.

First Steps
The typical Java ME application is generally developed against a standard Java ME device. Usually it will be a middle-of-the-range device, most probably selected following the suggestions of the target mobile operator.

One of the first decisions that the developer makes is selecting an IDE. A few IDEs support Java ME application development, NetBeans being the most mature. In the last year, both Eclipse and Intellij IDEA began to catch up and released versions of their IDE with more than sufficient support for Java ME development. The IDE for a Java ME project should be selected against the same criteria as other Java projects - basically, anything that helps the programmer with productivity, while ensuring quality code. Since the introduction of ant into the mainstream Java programming world, cute wizards/build utilities that certain IDEs offer are less of a buying point than they used to be.

After selecting the relevant Java ME emulator, the developer will tend to spend a large chunk of his development time testing the current status of the application on the Java ME emulator, and only towards the end will the application be tested on the actual device. Very often new bugs will arise when testing on the device, so deploying to the device should be done as early and as often as possible.

Unit Tests
As with all Java applications developed, it's imperative to write unit tests for the Java ME application. This becomes even more important when the number of devices needing to be supported increases, since unit testing will be one of the principal methods of weeding out different behavior in devices at an earlier stage in the development cycle.

The specific runtime environment in which the unit tests are executed becomes increasingly important as the number of supported device increases. For the first device it's generally acceptable to run the tests on the emulator most of the time, and every now and then to run the tests on the actual device.

Since most Java ME applications are heavily GUI-oriented, it's imperative to separate the layers of the application in a typical MVC pattern. This way it will be possible to unit test much of the Model and Controller part of the application. (Special attention should be paid to the memory cost of each additional class when the device has small JAR size restrictions. However, this is becoming less relevant as most devices on the market today have respectable JAR size capabilities.) If this separation isn't done, it will substantially reduce the benefit of the unit tests and you'll have to rely heavily on manual testing your application - something you want to avoid at all costs, since each device is, in essence, a different platform. So, the need to undertake manual testing should be reduced as much as possible in these areas by covering this functionality with unit tests.

J2MEUnit is the natural choice for a unit test framework. It's based on the popular JUnit framework and can be run as a J2MEMIDlet suite.

Porting to Other Devices
When the application is working at a reasonable quality level, demands for support on extra devices usually roll in. At the stage you might suddenly be presented with a list of 20 devices you've never seen before, with your customer inevitably asking, "How long will it take to get it running on these?"

This is the real challenge in Java ME development - porting to multiple devices. The challenges are multi-faceted. In the world of the unknown, you have to understand the cost of porting the application to each device as early as possible, while always ensuring the high quality of the application!

Get To Know Your Device
To provide an accurate cost estimate for a device, it's to know your device. There are several bits of information that you have to know. Some of this information will be documented on the Web, and some you'll only be able to discover by running tests on the device.

Most device vendors have a Web site devoted to application developers. On these sites you can generally find useful information, whether it be in an official Developers Guide published by the vendor, or in a post on the site's forum. At one end of the spectrum, there are vendors that have sites with a large, active community of developers, as well as great documentation. At the other end, there are vendors whose developer sites are either non-existent or so poorly supported that they may as well be non-existent. Table 1 shows some of the larger device Web sites.

You should aim to find out as much as possible about the following aspects of the device from these external resources:

  1. Which emulator to use
  2. Developer Guides
  3. I/O capabilities
  4. UI specifications
  5. API specifications
  6. Supported JSRs
  7. Memory limitations
  8. Security/signing issues
  9. Known issues
Depending on the functionality of the application, you'll typically need a variety of information for your device. Some of it will be formal definitions and capabilities that can be obtained from online resources.

War Stories
The following are typical examples of problems that can occur on devices. I can truly say that most devices have at least one war story, albeit not as severe as some of these examples.

Requirement: Your application needs to read and write up to 500KB of data to local storage on the device. This capability is something that can usually be discovered on the Web, and can be extremely valuable in providing estimates for particular devices.
Limitation A: According to the official Web site, Device X can only hold 256KB in its RMS (Record Management System, which is an API for persistent storage for Java ME devices). To support this device, an expensive change in the product's architecture might be required in which data is saved to a remote server. However, before believing the documentation, you run a quick check to confirm this limitation.
Limitation B: According to the Web site, Device X can hold 500KB. However, when running the application, it works satisfactorily until the amount of data saved on the device reaches 150KB after which the application crashes. This is an example of an undocumented restriction. To support this device, research will be required and possibly a change in the product architecture.

Requirement: Your application displays a set of graphic images that fit neatly on a 208*208 screen.
Limitation A: Device X's screen dimensions are only 200*200, which means that the images won't fit on the device. To support it, a new set of images will have to be created that will fit on this smaller device. The application's image layout algorithm will also have to be enhanced (if it ever existed).
Limitation B: Device Y's screen dimensions are big enough, but when the application runs, besides it taking nearly 10 seconds to paint the images to the screen, they appear very strange. After a lot of painstaking research and debugging, the device is discovered to be notoriously slow at rendering images to the screen and doesn't support the exact format of the current images. After generating very low-resolution images and changing the device's image display algorithm, you manage to get the time down to five seconds and the images look reasonable.

Requirement: Your application gets incoming messages through SMS messages received on a specific port.
Limitation A: When Device X gets an SMS message on this port, the application gets the message correctly. Device X is considered a new state-of-the-art device and has excellent performance and API capabilities. Shortly before releasing the application on this device, it's discovered that if two or more SMS messages are sent to the device within 10 seconds, the application crashes and the device has to be rebooted! This turns out to be a bug in the device's operating system and the only workaround is to develop an alternative communication channel using TCP/IP. This means developing a server-side component to manage this new mode of messaging plus a different cost-model for the mobile provider to handle this application's messaging.
Limitation B: Installing the application frequently fails on Device Y. After days of painstaking research, it's discovered that if the port number that the SMS messages come in on is changed to a different range, the installation completes and the application works fine. The mobile operator is perturbed at the news of the change in port number since it doesn't usually support messaging over those ports, and following this, there's a substantial amount of annoying politics to go through to get the change approved.

Reducing Risk
To decrease the element of surprise in porting the application to a device, it's advantageous to discover as many of the problems as early as possible. Many of these issues can be discovered both in the online resources and by running a thorough set of unit tests on your suite.

However, to add a greater level of protection, another level of testing framework can be used that will expose many of the problems mentioned above, which would otherwise be discovered much later in the development cycle. This testing framework is, in essence, a tailor-made application that has several sections to it. Each section should cover a large area of functionality, like image rendering, key mappings, menu behaviors, internationalization, GUI, I/O, or performance, with menu items that test each of these areas (see Figures 1 - 2 - 3 - 4 - 5). These tests cover areas of the application on a higher level than regular unit tests since there are some areas where automatic unit testing can't be applied such as performance issues and GUI errors.

The testing framework can typically contain several sections from which manual testing of application behavior can be carried out. A detailed test plan should accompany the test framework so the tester understands the success or failure of any particular test. This test package, consisting of the test framework together with the test plan, is an excellent tool to have when initially analyzing a device - it can make all the difference in arriving at accurate time estimates.

The testing framework should be updated as new functionality is added to the application. Just as important, whenever serious problems are discovered in a device, new tests should be added to detect the same problems in future devices. Only this way is it possible to add support for a large number of devices in a scalable manner. With a good testing framework and unit test suite, the development team should feel significantly more comfortable in committing to new devices (see Figure 6).

However, for any Java ME application porting project to succeed, the customer must always keep the priority of each device in the back of its mind, since, for example, it would be a bad idea for a mobile operator to commit to two months of redesigning a device that only covered 0.3% of its mobile device market, where the other 99.7% work well. On the other hand, if that device had 25% of the market, it might be the correct decision to take.

Keep the Code Clean
In the same way that a thorough level of testing is required, it's also very important to keep the code base clean and easy to maintain. Without this, the code base can quickly become very messy in direct proportion to the number of devices supported. When each device has slightly different behaviors, size differences, etc., the code will slowly begin to get scattered with # if preprocessor directives.


More Stories By Hayden Marchant

Hayden Marchant is a Software Engineer in the Information Integration Solutions group at IBM. He has 10 years of experience in software engineering. Hayden has a 1st class honors BA in mathematics from Cambridge University, England, and is a Sun Certified Programmer.

Comments (0)

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.