ONJava.com    
 Published on ONJava.com (http://www.onjava.com/)
 See this if you're having trouble printing code examples


MIDlet Packaging with J2ME

by John W. Muchow
04/26/2001

In last months article, J2ME and MIDP Development, we covered the basics of Java 2 Micro Edition (J2ME) and the Mobile Information Device Profile (MIDP). We touched upon installation, configuring the environment, writing a simple MIDlet, as well as compiling, pre-verifying class files, and running a MIDlet on a mobile device emulator.

This article takes the next logical step: packaging MIDlets. It includes an introduction to the MIDlet Suite, including Java archive and application descriptor files. To put all this into practice, we'll write two short MIDlets and create a JAR and JAD to package these programs. We also look at how using Java packages changes our development process slightly. And, finally, interweaved with the development of the MIDlets in this article, you'll learn how to access MIDlets from a web server.

The MIDlet Suite

Although it's not a requirement to place MIDlets inside a Java Archive (JAR) file, this will be the most common means of distributing J2ME/MIDP applications. The MIDlet Suite is the name given to the entire collection of all files and resources that may be required as part of a MIDlet. The MIDlet Suite consists of

Application Manager

The application manager is a software program on the mobile device. This application is device dependent and implemented by the manufacturer of the device. It's responsible for installing, running, and removing MIDlets from the device. It provides error-handling support. The application manager may also provide an optional interface to allow users to start, stop, and delete MIDlets.

Java Archive File

A production, packaged application will generally consist of many files. In addition to Java classes, other files such as images and application data, known as resources, may be part of the package. You bundle all this information together into a single entity, a JAR file.

Note: Learning about JAR files
Visit Sun's Java Tutorial online for more information about jar files:

In addition to class and resource files, a JAR contains a manifest file which describes the contents of the JAR. The manifest has the name manifest.mf and is stored in the JAR file itself. The table below lists all available attributes that may be defined within the manifest file.

Table 1
Attribute Purpose
MIDlet-Name Name of the MIDlet "package". For example, "Game Pack"
MIDlet-Version Version number of the MIDlet
MIDlet-Vendor Who created the MIDlet
MIDlet-Icon Icon associated to show alongside the MIDlet-Name by the application manager. This is a graphics file stored as a PNG image.
MIDlet-Description Text describing the MIDlet
MIDlet-Info-URL URL that may have more information about the MIDlet and/or the vendor
MIDlet-<n>

This attribute contains up to three pieces of information:
  • MIDlet name
  • Icon for this MIDlet (optional)
  • Class name the application manager will call to load this MIDlet

Inside our "Game Pack" example, we may have two entries:
  MIDlet-1: Rogue, /images/rogue.png, rogue.rogueMIDlet
  MIDlet-2: Golf, /images/golf.png, golfMIDlet

MIDlet-Jar-URL URL of the JAR file
MIDlet-Jar-Size The JAR file size in bytes
MIDlet-Data-Size The minimum number of bytes required for persistent data storage.
MicroEdition-Profile What J2ME Profile is required by the MIDlet
MicroEdition-Configuration What J2ME Configuration is required by the MIDlet.

These attributes are not all required. However, without the following six, the application manager is required to refuse to load the JAR.

Here is an example of a simple manifest file:

MIDlet-Name: Rogue
MIDlet-Version: 1.0
MIDlet-Vendor: My Corporation Inc.
MIDlet-1: rogue, /images/rogue.png, rogue.rogueMIDlet
MicroEdition-Profile: MIDP-1.0
MicroEdition-Configuration: CLDC-1.0

Java Application Descriptor File

Although not required, you should typically include a JAD file along with the JAR. As with the manifest, this file contains information about a MIDlet. There are two reasons to create a JAD.

The JAD files uses the same attributes as in Table 1. If you need to create your own attributes, you can do that as well. As long as you use attribute names that do not begin with MIDlet- you're all set. An example of a custom attribute is shown below in the file showProperties.jad.

As with the manifest, there are certain attributes that must be defined. If not available, the application manager will not load the MIDlet.

The values of MIDlet-Name, MIDlet-Version, and MIDlet-Vendor must be identical to the value of the same attributes in the JAR's manifest. As you might guess, if there is a difference in the files, the application manager will not load the JAR.

If any other attributes names are duplicated in both files, and the values of those attributes are not the same, the application descriptor file (JAD) attributes will take precedence.

The 1.0 MIDP specification does not show the MIDlet-n attribute as one that is required in the JAD file. However, without this entry, I was not able to preview MIDlets in the device emulator. Including this attribute in both files is not a problem, and, actually, doing so may provide more clarity as to how these files are related. Thus, for completeness, all examples here will include the MIDlet-n attribute inside the JAD.

A very simple JAD file might look like

MIDlet-Name: Memo Pad
MIDlet-Version: 1.0
MIDlet-Vendor: My Corporation Inc.
MIDlet-Jar-URL: http://www.yourweb.com/MIDlets/memopad.jar
MIDlet-Jar-Size: 26248
MIDlet-1: MemoPad, /images/MemoPad.png, MemoPad.Main

Accessing JAR/JAD attributes from a MIDlet

A MIDlet can access all the attributes defined inside both the manifest file (which is part of a JAR) and those inside the JAD file. The complete package name to the method that will return information about the properties is

javax.microedition.midlet.MIDlet.getAppProperty(String name)

What follows is a short example to print various attributes from both those files.

manifest.mf is stored as part of showProperties.jar:

MIDlet-Name: Show Properties MIDlet
MIDlet-Version: 1.0.1
MIDlet-Vendor: My Corporation Inc.
MIDlet-1: ShowProps, , showProperties
MicroEdition-Profile: MIDP-1.0
MicroEdition-Configuration: CLDC-1.0
MIDlet-Description: A simple property list example
MIDlet-Data-Size: 1500

Contents of showProperties.jad:

MIDlet-Name: Show Properties MIDlet
MIDlet-Version: 1.0.1
MIDlet-Vendor: My Corporation Inc.
MIDlet-Jar-URL: file://showProperties.jar
MIDlet-Jar-Size: 1132
MIDlet-1: ShowProps, , showProperties
JadFile-Version: 1.5
MIDlet-Data-Size: 500

Contents of showProperties.java:

import javax.microedition.midlet.*;

public class showProperties extends MIDlet
{
public void startApp() throws MIDletStateChangeException
{
System.out.println("Vendor: " + getAppProperty("MIDlet-Vendor"));
System.out.println("Description: " + getAppProperty("MIDlet-Description"));
System.out.println("JadFile Version: " + getAppProperty("JadFile-Version"));
System.out.println("MIDlet-Data-Size: " + getAppProperty("MIDlet-Data-Size"));
}

public void pauseApp()
{ }

public void destroyApp(boolean unconditional)
{ }

}

Screen shot.
Figure 1

Here are a few important points:

Packaging Multiple MIDlets in the MIDlet Suite

Before we can talk about how to package more than one MIDlet, we'll need to have more than one MIDlet available. What follows is code for two simple MIDlets. The first displays a TextBox component with a short message.

Contents of MIDlet1.java:

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

public class MIDlet1 extends MIDlet implements CommandListener
{
  private Display display;  // Reference to Display object
  private TextBox tbxMain;      // A Textbox to display a message
  private Command cmdExit;      // A Command to exit the MIDlet

  // The constructor
  public MIDlet1()
  {
    display = Display.getDisplay(this);
    
    cmdExit = new Command("Exit", Command.SCREEN, 1);
    
    tbxMain = new TextBox("MIDlet 1", "Welcome", 50, 0);
    tbxMain.addCommand(cmdExit);
    tbxMain.setCommandListener(this);
  }

  // Called by application manager to start the MIDlet.
  public void startApp()
  {
    display.setCurrent(tbxMain);
  }

  // A required method
  public void pauseApp()
  { }

  // A required method
  public void destroyApp(boolean unconditional)
  { }

  // Check to see if our Exit command was selected
  public void commandAction(Command c, Displayable s)
  {
    if (c == cmdExit)
    {
      destroyApp(false);
      notifyDestroyed();
    }
  }
}

Here is the second MIDlet; it shows a message on the display using a List component (MIDlet2.java):

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

public class MIDlet2 extends MIDlet implements CommandListener
{
  private Display display;   // Reference to Display object
  private List lstMain;         // A List of items
  private Command cmdExit;      // A Command to exit the MIDlet

  // The constructor
  public MIDlet2()
  {
    display = Display.getDisplay(this);
    
    cmdExit = new Command("Exit", Command.SCREEN, 1);

    lstMain = new List("MIDlet 2", Choice.IMPLICIT);
    lstMain.append("Welcome Back", null);
    lstMain.addCommand(cmdExit);
    lstMain.setCommandListener(this);
  }

  // Called by application manager to start the MIDlet.
  public void startApp()
  {
    display.setCurrent(lstMain);
  }

  // A required method
  public void pauseApp()
  { }

  // A required method
  public void destroyApp(boolean unconditional)
  { }

  // Check to see if our Exit command was selected
  public void commandAction(Command c, Displayable s)
  {
    if (c == cmdExit)
    {
      destroyApp(false);
      notifyDestroyed();
    }
  }
}

Call the first MIDlet1.java. Call the second MIDlet2.java. In the directory where you save the files, run the following to compile and pre-verify the files.

javac -bootclasspath c:\j2me\midp-fcs\classes *.java

preverify -classpath c:\j2me\midp-fcs\classes;. -d . MIDlet1 MIDlet2

jar cvfm MIDlets.jar manifest.txt MIDlet1.class MIDlet2.class spin.png

* Note: the path c:\j2me\midp-fcs may vary depending on your installation

Create the JAR File

Create a new file called manifest.txt and then create a file with the following contents:

MIDlet-Name: MIDlet Examples
MIDlet-Version: 1.0
MIDlet-Vendor: My Corporation Inc.
MIDlet-1: MIDlet1, /spin.png, MIDlet1
MIDlet-2: MIDlet2, /spin.png, MIDlet2
MicroEdition-Profile: MIDP-1.0
MicroEdition-Configuration: CLDC-1.0

Create a JAR file by running the following command:

jar cvfm MIDlets.jar manifest.txt MIDlet1.class MIDlet2.class spin.png

This will create a JAR file called MIDlets.jar that contains the contents of the manifest.txt file and both class files.

Note: The name of the manifest file inside the JAR will be manifest.mf. The reference above to manifest.txt informs the JAR program to create manifest.mf using the contents of the file manifest.txt

Create the JAD File

Create a new file called MIDlets.jad and create a file with the following contents:

MIDlet-Name: MIDlet Examples
MIDlet-Version: 1.0
MIDlet-Vendor: My Corporation Inc.
MIDlet-Description: Two simple examples to show how to compile and run a MIDlet
MIDlet-Jar-URL: http://localhost/MIDlets.jar
MIDlet-Jar-Size: 2604
MIDlet-1: MIDlet1, /spin.png, MIDlet1
MIDlet-2: MIDlet2, /spin.png, MIDlet2

Notice the reference to both the MIDlets:

MIDlet-1: MIDlet1, /spin.png, MIDlet1
MIDlet-2: MIDlet2, /spin.png, MIDlet2

Each line above contains the name of the MIDlet to display on the device (MIDlet1 and MIDlet2); an (optional) image file that the application manager will show on the display next to the MIDlet name; and the class file to load to start the MIDlet (MIDlet1 and MIDlet2).

Running the MIDlets

You can run a MIDlet from either a local file system or a web server.

From the File System

Type the following at the command prompt to preview your MIDlet:

midp -transient file://MIDlets.jad

The -transient option notifies the emulator you want to run a descriptor file found at a specified url. In this case: file://MIDlets.jad, which looks for MIDlets.jad in the current directory. You could also give a full path to the JAD file if necessary. For example, the full path to my JAD file is

file://OnJava/MIDlets/welcome.jad

You should see output similar to figures below, showing the main screen of the application manager and the output of MIDlet1 and MIDlet2.

Main screen and output.
Figure 2

From a Web server

You can also run MIDlets from a web server. After uploading the JAR and JAD file, access the JAD file by changing the url:

midp -transient http://localhost/MIDlets.jad

This accesses MIDlets.jad file on the web server running on my computer. If you upload your files to a web server on the Internet, simply change the reference to the appropriate domain name:

midp -transient http://www.yourwebserver.com/path/MIDlets.jad

Project Management using Java Packages

Follow along with the steps below to create one last MIDlet.

  1. Create a directory for the new project. I used the name MIDletPackage, which I created as a subdirectory of f:\onjava.
  2. Within the new directory, create three new sub-directories:
        jclasses
        pclasses
        resources
    The additional directories make it clear where to find specific files. For example, all images and other resources will be in /resources. All class files created by the Java compiler will be in /jclasses. The pre-verified classes will be written in /pclasses. Here's the directory structure on my system:
    
    f:\onjava
      |
      MIDletPackage => Java source code and manifest.txt file
          |
          jclasses  => Output from the Java compiler
          pclasses  => Output from pre-verifier
          resources => Resource files (images, etc)
  3. Update the files: copy the Java source files (MIDLet1.java and MIDlet2.java) into the MIDletPackage directory, and add the package statement shown below to the top of each file. Also, if you have an image file you've been using, copy that file into the resources directory.

    MIDlet1.java:
    package simpleMIDlets;

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

    public class MIDlet1 extends MIDlet implements CommandListener
    {
    ...
    }

    MIDlet2.java:
    package simpleMIDlets;

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

    public class MIDlet2 extends MIDlet implements CommandListener
    {
    ...
    }
  4. Update manifest.txt and the JAD file to reference the new location of the images and the class files.

    manifest.txt:
    MIDlet-Name: MIDlet Examples
    MIDlet-Version: 1.0
    MIDlet-Vendor: My Corporation Inc.
    MIDlet-1: MIDlet1, /resources/spin.png, simpleMIDlets.MIDlet1
    MIDlet-2: MIDlet2, /resources/spin.png, simpleMIDlets.MIDlet2
    MicroEdition-Configuration: CLDC-1.0
    MicroEdition-Profile: MIDP-1.0


    MIDlets.jad:
    MIDlet-Name: MIDlet Examples
    MIDlet-Version: 1.0
    MIDlet-Vendor: My Corporation Inc.
    MIDlet-Description: Packaging multiple MIDlets
    MIDlet-Jar-URL: http://localhost/MIDlets.jar
    MIDlet-Jar-Size: 2884
    MIDlet-1: MIDlet1, /resources/spin.png, simpleMIDlets.MIDlet1
    MIDlet-2: MIDlet2, /resources/spin.png, simpleMIDlets.MIDlet2


    Note the changes to MIDlet-1 and MIDlet-2. The class files are now referenced using the package name simpleMIDlets.MIDlet1 and simpleMIDlets.MIDlet2.
  5. Compile: Compile the source:
    javac -bootclasspath c:\j2me\midp-fcs\classes -d jclasses *.java
    The -d option tells the compiler to write the classes files into the directory jclasses
    * Note: the path c:\j2me\midp-fcs may vary depending on your installation"-d" option tells the compiler to write the classes files into the directory jclasses
  6. Pre-verify:
    preverify -classpath c:\j2me\midp-fcs\classes; -d pclasses jclasses
    The -d option tells the pre-verifier to store the pre-verified classes in the directory pclasses. The last entry -- jclasses -- tells the preverify where to look for classes to pre-verify.
    * Note: the path c:\j2me\midp-fcs may vary depending on your installation
  7. Create the JAR: Run the jar program:
    jar cvfm MIDlets.jar manifest.txt -C pclasses . resources

    Creates a JAR file with the name MIDlets.jar, using the file manifest.txt as the contents of the manifest file (a file called manifest.mf will be stored in the JAR).

    -C pclasses . tells the jar program to change to the pclasses directory and archive all (".") the files
    resources informs the jar program to add all the files located in the directory named resources
    At this point, you have two files:
    MIDlets.jad -- Application descriptor file
    MIDlets.jar -- JAR file containing the MIDlets, a manifest and the image files
    Launch the MIDlets: To view your new files, once again, you have two options:
    From the File System:
    midp -transient file://MIDlets.jad
    From a web server: Upload the JAR and JAD files to a web server. Enter the following to view the MIDlets:
    midp -transient http://localhost/MIDlets.jad
    Change the path as in the previous example to reference the MIDlets on a different web server.

With our new hierarchy, we can now quickly determine the contents of each directory; that is, the location of the source code, Java classes files, pre-verified class file, and resources.

Screen shot.

F:\onjava
  |
  MIDletPackage => Java source code and manifest.txt file
    |
    jclasses => Output from the Java compiler
    pclasses => Output from pre-verifier
    resources => Images (and other resource files)

The directory simpleMIDlets (below jclasses and pclasses) was created by the Java compiler and the pre-verifier, respectively. Because we added the statement package simpleMIDlets to our source files, each program created the directory matching the package name and placed its output in that directory. That is, the Java compiler class files are written to

F:\onjava\MIDletPackage\jclasses\simpleMIDlets

The pre-verified classes file are written to:

F:\onjava\MIDletPackage\pclasses\simpleMIDlets

Summary

In the previous and current articles we've covered all the basics of MIDlet development. You should have all the necessary software installed and configured, and you should be comfortable with the complete development cycle.

We've also shown how you can use a JAR and JAD file to package one or more MIDlets. Finally, we've shown that running a MIDlet on the cellular phone emulator varies little, regardless of where the MIDlet reside, on a local file system or a web server.

You can download the source code for this article from the Core J2ME site.

John W. Muchow is an expert Java Developer and Trainer specializing in J2ME.


Return to ONJava.com.

Copyright © 2009 O'Reilly Media, Inc.