Beginning J2ME: Building MIDlets

Get a taste of MIDlet development

MIDP (Mobile Information Device Profile) applications are piquantly called MIDlets, a continuation of the naming theme begun by applets and servlets. Writing MIDlets is relatively easy for a moderately experienced Java programmer. After all, the programming language is still Java. Furthermore, many of the fundamental APIs from java.lang and java.io are basically the same in the MIDP as they are in J2SE. Learning the new APIs (in the javax.microedition hierarchy) is not terribly difficult.

The actual development process, however, is a little more complicated for MIDlets than it is for J2SE applications. Beyond a basic compile-and-run cycle, MIDlets require some additional tweaking and packaging. The complete build cycle goes like this: edit, source code, compile, preverify, package, test or deploy.

To show how things work, and to give you a taste of MIDlet development, this article is dedicated to building and running a simple MIDlet. In this article, you'll get a feel for the big picture of MIDlet development.

Tooling up

MIDlets are developed on regular desktop computers, although the MIDlet itself is designed to run on a small device. To develop MIDlets, you'll need some kind of development kit, either from Sun Microsystems or another vendor. Remember, MIDP is only a specification; vendors are free to develop their own implementations.

The world is full of MIDlet development tools if you know where to look. Furthermore, many of these tools are freely available.

The bare bones set of tools is Sun's MIDP reference implementation. This includes the preverify tool (more on this later), a MIDP device emulator, source code, and documentation. You can download the MIDP reference implementation from Sun. However, we don't recommend using the reference implementation unless you really enjoy being in the middle of the gritty details of building and packaging MIDlets. (You should also investigate the reference implementation if you are interested in porting the MIDP runtime to a new device or platform.)

A much better tool for beginners is Sun's J2ME Wireless Toolkit. The J2ME Wireless Toolkit (or J2MEWTK, as it's affectionately known) includes a GUI tool that automates some of the tedious details of building and packaging MIDlets, providing a simple path from source code to running MIDlets. At the same time, the J2ME Wireless Toolkit is a relatively lightweight solution, almost a miniature IDE, not something that will choke your machine.

Larger IDEs are available in abundance from device manufacturers, wireless carriers, IDE vendors, and open source communities, including the following (links to tools are available in Resources):

  • Borland JBuilder X Mobile Edition
  • IBM WebSphere Studio Device Developer
  • Research In Motion BlackBerry Java Development Environment
  • Sun Java Studio Mobility
  • NetBeans IDE 4.x
  • Eclipse J2ME plug-in
  • Nokia Developer's Suite for J2ME

You can use whatever development kit you wish. We suggest you start with the J2ME Wireless Toolkit, which is easy to use and authoritative. We'll be using the J2ME Wireless Toolkit (version 2.2, or WTK 2.2). Other development environments generally use the J2ME Wireless Toolkit as a plug-in anyhow, so your experiences are likely to be similar no matter what tool you use. You'll notice details about the development environment most in this article, where we'll go into detail about the build tools and the emulators.

Debugging your MIDlets

If you are using any of the previously listed IDEs, you will have an integrated full-featured debugger for stepping through and debugging your MIDlets. If you are using the WTK standalone, and an external text editor, you can debug most of your MIDlets using the familiar System.out.println() call to output to console. The WTK maintains a console that will show all your debug and stack traces.

Creating source code

Writing Java source code is the same as it always was: use your favorite text editor to create a source file with a .java extension. The example we'll build and run is Jargoneer, a MIDlet that looks up words in the Jargon File, a comprehensive lexicon of hacker slang.

When you enter a word into Jargoneer, it connects to a server to find the definition. Running this MIDlet will allow you to appear cool in the company of your hacker friends. When someone uses an unfamiliar word, like "cruft" or "grok," you can surreptitiously key the word into your mobile phone and see a definition in a few seconds.

Jargoneer's source code is provided in the listing below. Note: You can download all of this article's code examples from the downloads page at Apress.

Jargoneer's Source Code

 

import java.io.*;

import javax.microedition.io.*; import javax.microedition.midlet.*; import javax.microedition.lcdui.*;

public class Jargoneer extends MIDlet implements CommandListener, Runnable { private Display mDisplay;

private Command mExitCommand, mFindCommand, mCancelCommand;

private TextBox mSubmitBox; private Form mProgressForm; private StringItem mProgressString;

public Jargoneer() { mExitCommand = new Command("Exit", Command.EXIT, 0); mFindCommand = new Command("Find", Command.SCREEN, 0); mCancelCommand = new Command("Cancel", Command.CANCEL, 0);

mSubmitBox = new TextBox("Jargoneer", "", 32, 0); mSubmitBox.addCommand(mExitCommand); mSubmitBox.addCommand(mFindCommand); mSubmitBox.setCommandListener(this);

mProgressForm = new Form("Lookup progress"); mProgressString = new StringItem(null, null); mProgressForm.append(mProgressString); }

public void startApp() { mDisplay = Display.getDisplay(this);

mDisplay.setCurrent(mSubmitBox); }

public void pauseApp() {}

public void destroyApp(boolean unconditional) {}

public void commandAction(Command c, Displayable s) { if (c == mExitCommand) { destroyApp(false); notifyDestroyed(); } else if (c == mFindCommand) { // Show the progress form. mDisplay.setCurrent(mProgressForm); // Kick off the thread to do the query. Thread t = new Thread(this); t.start(); } }

public void run() { String word = mSubmitBox.getString(); String definition;

try { definition = lookUp(word); } catch (IOException ioe) { Alert report = new Alert( "Sorry", "Something went wrong and that " + "definition could not be retrieved.", null, null); report.setTimeout(Alert.FOREVER); mDisplay.setCurrent(report, mSubmitBox); return; }

Alert results = new Alert("Definition", definition, null, null); results.setTimeout(Alert.FOREVER); mDisplay.setCurrent(results, mSubmitBox); }

private String lookUp(String word) throws IOException { HttpConnection hc = null; InputStream in = null; String definition = null; try { String baseURL = "http://65.215.221.148:8080/wj2/jargoneer?word="; String url = baseURL + word; mProgressString.setText("Connecting..."); hc = (HttpConnection)Connector.open(url); hc.setRequestProperty("Connection", "close"); in = hc.openInputStream();

mProgressString.setText("Reading..."); int contentLength = (int)hc.getLength(); if (contentLength == -1) contentLength = 255; byte[] raw = new byte[contentLength]; int length = in.read(raw);

// Clean up. in.close(); hc.close();

definition = new String(raw, 0, length); } finally { try { if (in != null) in.close(); if (hc != null) hc.close(); } catch (IOException ignored) {} }

return definition; } }

Compiling a MIDlet

Writing MIDlets is an example of cross-compiling, where you compile code on one platform and run it on another. In this case, you'll be compiling a MIDlet using J2SE on your desktop computer. The MIDlet itself will run on a mobile phone, pager, or other mobile information device that supports MIDP.

The J2ME Wireless Toolkit takes care of the details as long as you put the source code in the right directory.

  1. Start the toolkit, called KToolbar
  2. Choose New Project from the toolbar to create a new project
  3. When the J2ME Wireless Toolkit asks you for the name of the project and the MIDlet class name, use "Jargoneer" for both
  4. Click the Create Project button and then the OK button to dismiss the project settings window

Figure 1 shows the New Project dialog box.

Figure 1. Creating a new project with the J2ME Wireless Toolkit. Click on thumbnail to view full-sized image.

The J2ME Wireless Toolkit represents projects as subdirectories of its apps directory. The following shows the contents of the Jargoneer directory after the new project is created:

 <J2ME Wireless Toolkit directory>
   apps
      Jargoneer
         bin
         lib
         res
         src

Save the source code as Jargoneer.java in the project's src directory. You can simply click the Build button in the J2ME Wireless Toolkit toolbar to compile the open project.

Behind the scenes, the J2ME Wireless Toolkit uses J2SE's compiler. Normally, when you're compiling J2SE source code, the CLASSPATH environment variable points to all the classes that your source code needs to know about. When you use javac to compile a file, there are some implied APIs that get included, like the classes in java.lang. With MIDlets, however, the situation is a little more complicated. Say that you use the java.lang.System class in your MIDlet. How do you (or how does the J2ME Wireless Toolkit) let the compiler know that you want to use the MIDP version of this class, not the J2SE version?

The answer is a command line option, -bootclasspath. This option lets you point to a classpath that describes the fundamental APIs against which you will be compiling your source code. In this case, this option should be used to specify the classes directory in the MIDP reference implementation installation. If you install the MIDP reference implementation, the command line looks like this:

 javac -bootclasspath \midp\classes Jargoneer.java

You will need to adjust the path to classes if you installed the MIDP reference implementation in a different location.

Preverifying classfiles

Now comes an entirely new step in building your program, preverifying. Because the memory on small devices is so scarce, MIDP (actually, CLDC, or Connected Limited Device Configuration) specifies that bytecode verification be split into two pieces. Somewhere off the device, a preverify step is performed. The device itself is only required to do a lightweight second verification step before loading classes.

If you are using the J2ME Wireless Toolkit, you don't have to worry about preverifying classfiles, and you may not even notice that it's happening when you click the Build button. If you'd like to understand more about preverifying, read the rest of this section. Otherwise, you can just skip ahead.

As you may recall, bytecode verification is one of the foundation stones of Java's runtime security model. Before a classloader dynamically loads a class, the bytecode verifier checks the classfile to make sure it behaves well and won't do nasty things to the JVM. Unfortunately, the code that implements the bytecode verifier is bulky, too large to fit on a small device like a mobile phone. The CLDC dictates a two-step bytecode verification:

  1. Off the device, classfiles are preverified. Certain checks are performed, and the classfile is massaged into a format that the lightweight second-step verifier can easily handle. This format is really just a regular classfile, with some additional data attached by the preverifier.
  2. On the device, the second step of verification is performed as classes are loaded. If a classfile has not been preverified, it is rejected.

The MIDP reference implementation and the J2ME Wireless Toolkit contain a tool called preverify that performs the first step.

The preverify tools takes, as input, a classfile. It produces a preverified classfile. You need to specify a classpath so that the tool can find the class you want to preverify as well as any referenced classes. Finally, you can specify an output directory using the -d option. To overwrite an existing classfile with a preverified version, you could do something like this:

 preverify -classpath .;\ midp\ classes -d . Jargoneer

In this example, the -d option tells preverify to write the preverified classfile to the current directory. Don't forget about inner classes, which must also be preverified.

Note: Splitting bytecode verification into two pieces like this has important security ramifications. Devices should only download code from trusted sources, using a secure method, because some bytecode verification is performed off the device. An attacker could supply malicious code that appeared to be preverified, even if it violated the rules of the full J2SE bytecode verifier. To the MIDP second-step verifier, the code would look okay and it would be loaded and run.

Sun's J2ME Wireless Toolkit emulators

The J2ME Wireless Toolkit includes several different emulators that you can use to test your applications. When you click the Run button in the J2ME Wireless Toolkit, your application is launched in the currently selected emulator.

The Wireless Toolkit devices

The J2ME Wireless Toolkit 2.2 contains four main device emulators:

  • DefaultColorPhone is a device with a 240-by-320-pixel color screen. This is the device shown later in Figure 2.
  • DefaultGrayPhone has a 108-by-208-pixel grayscale screen.
  • MediaControlSkin is similar to the default phone emulator and has a color screen of 108-by-208 pixels, but its buttons are labeled with controls like a music player: a square for stop, a triangle for play, volume control buttons, etc.
  • QwertyDevice is a smartphone with a 636-by-235 color screen and a miniature QWERTY keyboard.

Running MIDlets

Sun's MIDP reference implementation includes an emulator named midp. It emulates an imaginary MID, a mobile telephone with some standard keys and a 182-by-210-pixel screen. The J2ME Wireless Toolkit includes a similar emulator, as well as several others.

Once you've got a preverified classfile, you can use the midp emulator to run it. The emulator is an application that runs under J2SE and acts just like a MIDP device. It shows itself on your screen as a representative device, a generic mobile phone. You can run your MIDlet by typing the following at the command line, assuming you added \midp\bin to your PATH:

 midp Jargoneer

If you're using the J2ME Wireless Toolkit, you can simply choose an emulator from the Device combo box and click the Run button to fire up your application.

If all goes well, you'll see something like the window shown in Figure 2 in the next section. Congratulations! You've just built and run your first MIDlet.

Using the emulator controls

The J2ME Wireless Toolkit emulator appears as a generic mobile phone, as shown in Figure 2.

Figure 2. Buttons on the J2ME Wireless Toolkit emulator. Click on thumbnail to view full-sized image.

Sun's J2ME Wireless Toolkit emulator exhibits several qualities that you are likely to find in real devices:

  • The device has a small screen size and limited input capabilities. (It's not as small as the earlier J2ME Wireless Toolkit 1.x emulators, which included emulated devices with 96-by-128-pixel and 96-by-54-pixel screens.)
  • Two soft buttons are available. A soft button does not have a fixed function. Generally, the function of the button at any given time is shown on the screen near the button. In MIDlets, the soft buttons are used for commands.
  • Navigation buttons are provided to allow the user to browse through lists or other sets of choices.
  • A select button allows the user to make a choice after moving to it with the navigation buttons. (Think "Yes, that's my final answer.")

Summary

This article took you on a tour of MIDP development. Creating source code is much the same as in J2SE development, but the build process is different. First, the source code must be compiled against the MIDP classes using javac's -bootclasspath option. Second, the classfiles must be preverified using the preverify command line tool. With the J2ME Wireless Toolkit, these steps are conveniently automated. Just click the Build button to build and preverify. Applications can be easily tested in emulators using the J2ME Wireless Toolkit.

Jonathan Knudsen is a Java developer and noted author of several books, including Wireless Java: Developing with J2ME, Second Edition, Mobile Java, The Unofficial Guide to LEGO MINDSTORMS Robots, Learning Java, and Java 2D Graphics. Knudsen began his object-oriented programming career in Objective-C on the NeXT OS, soon thereafter suffering through a couple of purgatorial years in Microsoft's Visual C++, before graduating to Java in 1996. He has written extensively about Java and LEGO robots, including five books, a monthly online column called "Bite-Size Java," and articles for JavaWorld, EXE, NZZ Folio, and the O'Reilly Network. Jonathan holds a degree in mechanical engineering from Princeton University. Bitten by the computer bug in 1978, Sing Li has grown up with the microprocessor revolution. His first PC was a 9 do-it-yourself COSMIC ELF computer with 256 bytes of memory and a 1-bit LED display. For more than two decades, Li has been a developer, author, consultant, speaker, instructor, and entrepreneur. His wide-ranging experience spans distributed architectures, Web application/service systems, computer telephony integration, and embedded systems. Li has been working with (and writing about) Java, Jini, and Jxta since their first alpha releases, and is an evangelist of P2P technology and a participant in the Jxta community.

Learn more about this topic

Join the discussion
Be the first to comment on this article. Our Commenting Policies
See more