
J2ME MIDP Device Fragmentation Tutorial with Marv The Miner
This tutorial shows how to configure the IDE to work with existing Java™
2, Micro Edition Platform (J2ME™ Platform)
MIDP projects and, specifically, how to use the NetBeans™ IDE's built-in solution
to the device
fragmentation
problem. Following this tutorial from start to finish will illustrate the following:
- How to port an existing fragmented MIDP project to NetBeans
- How to use the IDE's built-in device fragmentation solution
The example program this tutorial uses is the popular J2ME game "Marv
The Miner," which
was released under GPL and written to run on several different mobile platforms.
This tutorial should take approximately two hours to complete
and covers the following topics:
- Import sources from an existing MIDP project.
- Create and customize project configurations for each distribution Jar.
- Mark pieces of source code as being specific to each configuration.
- Build several distribution Jars for the project.
- Use external emulators from within the IDE.
To follow this tutorial you need the MarvTheMiner v1.2.0 source files.
Unfortunately they are no longer available from Digiment.
Fortunately, you can download the latest
version of NetBeans and work read the updated
Device Fragmentation Tutorial.
- Setting Up Your Environment
- Obtaining the Required Source Files
- Developing the Marv The Miner Application in NetBeans
- Building and Executing the Marv the Miner Application
- Exploring Configurations Further
- Using Non-UEI compliant Emulator Platforms
Setting Up Your Environment
This section describes how to set up your system before starting the tutorial.
Obtaining and
Installing the Required Software
The following software is required for the example:
Use the instructions provided at the download sites to install
the software.
Starting the IDE
To start the NetBeans IDE:
- On Microsoft Windows
Choose Start > Programs > NetBeans
version > NetBeans
IDE.
- On UNIX, or Linux environments
In a terminal window, type sh IDE-install-path/bin/runide.sh
The IDE-install-path variable stands for the path
to the IDE's home directory.
Obtaining the Required Source Files
The MarvTheMiner_120_all.zip file
contains the source files of the original Marv The Miner application.
The zip includes a MarvTheMiner directory, which contains the src and res subdirectories
that you will use in this tutorial.
To unzip the MarvTheMiner_120_all.zip file:
- In your file system, create a temporary location for the contents
of MarvTheMiner_120_all.zip.
For example, this tutorial refers
to this directory as the C:\temp directory.
- Use an application that unzips files to unzip the MarvTheMiner_120_all.zip file
to the temp directory.
The temp directory now has a MarvTheMiner directory,
which contains the following files and subdirectories:
| /products/index.htmlsrc |
The source files which make up the Marv The Miner program. |
| res
| Contains the resource files used by the program. This includes
graphics as well as .map files which are used to define the
game level's layouts. |
| MarvEditor |
A level editor (outside the scope of this tutorial). |
| Nokia.full |
A Nokia build of the game. |
| MIDP.full |
A generic MIDP build of the game. |
- Move the res directory to C:/temp/MarvTheMiner_120_all/src/.
This is a small work-around to make sure the resource files maintain
the correct relative path once we create a new NetBeans project.
Developing the Marv The Miner Application in NetBeans
IDE
In this section, you set up and work with the existing
project sources within the NetBeans IDE.
Import existing sources
Creating the Project
The first step is to create a new project in the NetBeans
IDE.
- Choose File > New Project from the main menu.
The New Project wizard is displayed.
- In the Categories list select Mobile. Then select Mobile
Project from Existing MIDP Sources and click Next.
- If you did not install NetBeans using the installer,
you are shown a panel here instructing you to install a
mobile platform. Follow the instructions and install some
version of the Wireless Toolkit. Then click next.
- For the Imported Sources Location, click the Browse button
and navigate to C:/temp/MarvTheMiner_120_all/src directory
that you created when you unzipped the
MarvTheMiner_120_all.zip file. Select the src directory,
and click Open. Click Next.
- Enter a name for your New Project. For example, name
it MarvTheMiner.
- Now select a directory where the new project directory
should reside. Make sure the Set as Main Project check
box is enabled, and click Finish.
A new project, MarvTheMiner, is
created and displayed in the IDE's Projects tab.
- Expand the MarvTheMiner root project node to see the
project's sources and resources. Expand the <default
package> node
and then double click on Main.java to open that file in
the editor.

Creating Project Configurations
The NetBeans device fragmentation solution is based on the use of
project configurations. A project should have one project configuration
for
each distribution Jar/Jad you would like created for that project.
If you examine the file Main.java, you will see that
the the authors support multiple platforms with a combination of
comments (for Nokia's FullCanvas) and Class.forname().
They also define a variable vendor that is used to track on which phone
the application is running. Based on this information, you can see
that they are supporting five different groups of phones:
- Nokia Series 60
- Other Nokia
- Motorola
- Vodafone
- Other
As
such, you will create four configurations to handle differences
between these distributions.
Creating a Configuration
- Right-click on the MarvTheMiner project node and
select Properties.
This opens the Project Properties page
that is used to control most aspects of the project.
- Click the Manage Configurations button at the top
of the page. This opens the Manage Configurations
dialog.
- Click Add and then type
NokiaSeries60 and press OK.
- Repeat the previous step for
Motorola, Vodafone,
and NokiaOther. Click Close
to close the Manage Configuration dialog.

The Project Configuration combo box at the top of the
Project Properties page should now contain five configurations.
We will use these configurations in a moment, but for
now
lets add
some emulators into the IDE.
Adding Emulators
to the IDE
To run the project using the emulator
platforms you have installed on your computer, you must first
register them with the IDE.
- Select DefaultConfiguration in the Project Configuration
combo, and then select the Platform node. Click the Manage
Emulators button. The Platform Manager dialog appears.
Note that
this dialog
can also be accessed from the main menu at Toeols>Java
Platform Manager.
- Click Add Platform and navigate to the directory where
you installed your Nokia Series 60 emulator. Click Next.
- Ensure that the emulator settings were detected correctly,
and then click Next.
- Here you can point to the source and
javadoc files for the emulator if you want. Otherwise just
hit Finish
to complete the installation of the platform.
Repeat these steps for each emulator platform you have
installed on your machine and that you want to use from
within the IDE.
Note that only emulators that comply with UEI standards
will be detectable by the IDE. Unfortunately, this
means that the Motorola 7.5 emulator that the developers
used for Marv The Miner can not be detected. A later
section in the tutorial will explain a work-around
for using non-UEI emulators from within the IDE.
Customizing
Project Settings for Configurations
Each panel in the Project Properties page
can be customized separately for each project configuration.
By default, configurations will use the settings defined
in the default configuration.
- Open the Project Properties page and select the Platform
panel. Make sure DefaultConfiguration is selected in the
Project Configuration combo box.
- Select J2ME Wireless Toolkit 2.x in the Emulator Platform
combo box. Toggle the radio buttons to CLDC-1.0 and MIDP-2.0.
By default, all configurations will use this emulator for
building and executing the project. This isn't
what we want, however, as the code references several
platform-specific libraries.
- Select the NokiaSeries60 configuration from the Project
Configuration combo.
The Platform panel is now entirely
grayed out. This is because we are currently using the
values from DefaultConfiguration
for this panel.
- Uncheck the
Use Values from "DefaultConfiguration" check box at the
top of the panel.
All
elements in the panel should now be enabled. Select the
Series 60 MIDP
Concept SKD Beta 0.3.1 Nokia platform from the Emulator
Platform combo box.
If you toggle between the each configuration, you'll
see that all are now using the value specified in
DefaultConfiguration except for the NokiaSeries60 configuration.
If you change any of the configuration settings in
the DefaultConfiguration Platform panel, the changes
will propagate to all configurations except NokiaSeries60.
- Select the NokiaOther configuration in the Project Configuration
combo box. Uncheck the Use Values from "Default Configuration" checkbox
and select one of the other Nokia platforms you installed.
- Repeat these steps for the Vodafone platform as well.
- As mentioned above, the Motorola 7.5 emulator is not
UEI-compliant and could therefore not be installed into
the IDE. However, we can still point to its APIs for compilation
purposes. Activate the Motorla configuration and select the Libraries & Resources panel.
- Uncheck
the Use Values from "DefaultConfiguration" checkbox.
- Click
Add Jar/Zip and navigate to
{motorola install
directory}\Emulator7.5\lib.
Select each .zip file (using ctl+mouse) and click Open.
- Click OK to exit the project properties. You are done
creating projects configurations for now.
Creating Custom Code
Blocks for each Configuration
The second part of the device fragmentation
solution is the ability to specify certain blocks of code
in your source files as being specific to one or more configurations.
This is accomplished by using actions in the right-click
context menu of the editor, or from the Edit > Preprocessor
Blocks menu.
- Open Main.java, and examine the initStaticData() method.
Here, the method is determining at runtime which device-specific
APIs are available, and then behaving accordingly. This
is a very clever solution to some parts of the device
fragmentation problem. Unfortunately, it also has the
problem of being increasing the size of the distribution
Jar, impacting
runtime performance, adding complexity to the sources,
and does not solve all fragmentation problems (as you
will see
later).
Here is the pertinent part of initStaticData():
vendor = 0;
try
{
// Nokia
Class.forName("com.nokia.mid.sound.Sound");
vendor = 1;
try
{
Class.forName("com.nokia.mid.ui.DeviceControl");
com.nokia.mid.ui.DeviceControl.setLights(0,100);
vendor = 2;
}
catch(Exception ex2){}
}
catch(Exception ex){}
try
{
// Vodafone
Class.forName("com.vodafone.v10.system.device.DeviceControl");
com.vodafone.v10.system.device.DeviceControl.getDefaultDeviceControl().
setDeviceActive(com.vodafone.v10.system.device.DeviceControl.BACK_LIGHT,
true);
vendor = 3;
}
catch(Exception ex){}
try
{
// Motorola
Class.forName("com.motorola.multimedia.Vibrator");
Class.forName("com.motorola.multimedia.Lighting");
com.motorola.multimedia.Lighting.backlightOn();
vendor = 4;
}
catch(Exception ex){}
- Remove all of the functionality
that is only dealing with determining
which device
the program is running on, so the code
you are left looks like following:
// Nokia
com.nokia.mid.ui.DeviceControl.setLights(0,100);
// Vodafone
com.vodafone.v10.system.device.DeviceControl.
getDefaultDeviceControl().
setDeviceActive(com.vodafone.v10.system.device.DeviceControl.BACK_LIGHT,
true);
// Motorola
com.motorola.multimedia.Lighting.backlightOn();
You now have
three blocks of code that should be
associated with your different
configurations.
- Highlight the Motorola-specific lines, then
right-click on the editor and select
Preprocessor Blocks>Motorola.
- Repeat this step
for the Vodafone block
(Preprocessor Blocks > Vodafone).
- For the Nokia code, select Preprocessor
Blocks>Manage
Preprocessor
Block.
This
opens the
Manage
Preprocessor
Block dialog.
- Select the
options for
both NokiaOther
and NokiaSeries60
and click OK.
These code blocks are now associated
with the configurations listed
in the headers and footers of the preprocessor
blocks. Changing the project's
active configuration will trigger a preprocessor
that will comment in and out
blocks based on if the active configuration
is a part of the preprocessor
block's header and footer.

- Change the project's active configuration by
using the combo box in the main toolbar.
You can also do this by right-clicking on the project
node>Set
Active Project Configuration>select configuration from
the same menu in the main Build menu, or by toggling
the
Configuration combo in the main toolbar (if your project
is currently the main project).
Notice that the code block highlighting switches colors
to identify which blocks are active or inactive. The active
configuration name is also
highlighted a different color in the header/footer of
the code blocks.
- Remove all the instances of class.forName()
from the
beep() method. If you also condense
the if blocks, you are
left with the following code:
if (midlet.muteSound == 0)
{
// Nokia 3650, 7650
com.nokia.mid.sound.Sound sound = new com.nokia.mid.sound.Sound(1000,100);
sound.play(1);
// All other Nokias
com.nokia.mid.sound.Sound sound = new com.nokia.mid.sound.Sound(1000,100);
sound.play(1);
}
if (midlet.useVibra == 1)
{
// Nokia
com.nokia.mid.ui.DeviceControl.startVibra(50,500);
// Vodafone SDK
com.vodafone.v10.system.device.DeviceControl.
getDefaultDeviceControl().
setDeviceActive(
com.vodafone.v10.system.device.DeviceControl.VIBRATION,
true);
vibra_delay = 10;
// Motorola 7.5
com.motorola.multimedia.Vibrator.
setVibrateTone(
com.motorola.multimedia.Vibrator.VIBRATE_LONG);
com.motorola.multimedia.Vibrator.vibrateFor(500);
}
You should be able to associate each block with the correct configuration. Remember to associate
the Nokia vibration control call with both Nokia configurations.
- The run() method also contains a Vodafone-specific call. Remove
the try/catch blocks and associate the two lines with the
Vodafone configuration.
We're almost done. The final step is to somehow handle
Nokia's FullCanvas.
- Activate the NokiaSeries60 configuration.
- Right click on the FullCanvas declaration and select
Create If/Else Block (NokiaSeries60).
- Right click on the first block and add NokiaOther.
- Right click on the second block and add NokiaOther.
- The second block is an Inverted block. Change the inverted
block class definition to extend Canvas.
When you are done,
your class definition should appear like so:
Building and Executing the Marv the Miner
Application
Building
and Executing the Application
At this point, we should be able to compile and run the
program for all of our configurations. Clicking any of the
icons in the main toolbar will execute the selected action
for the Active configuration.
- In the main menu, select Build > Build All Main Project
Configurations.
Assuming everything is set up correctly,
all configurations should now be built.
If you did not have access to one or more of the
emulator platforms containing the correct APIs, this
step might fail. If that is the case, you should manually
comment out any line making a call to an API that
you don't have.
Preverification will fail for the Motorola configuration
if you have not followed the steps to manually install the motoral
emulator described in the section for non-UEI emulators.
To make this configuration compile without manually adding the emulator,
you can comment out all motorola API calls and remove the motorola libs
from the Libraries & Resources panel.
- Select the Files tab in the upper left hand side of
the IDE and expand the dist folder. In this
folder you should have directories containing Jar/JADs
for each configuration that was successfully built, as
well as a Jar/Jad that represents the DefaultConfiguration
build.
- Press F5 to run the program for the currently
selected configuration. You can switch configurations and
press F5 again to run multiple versions of the program
at the
same time.
Exploring Configurations Further
This tutorial should have given you a good understanding of how you can import your existing MIDP projects into the NetBeans environment, but it does not cover all of the Device Fragmentation issues solved by the IDE. Below are some more examples of common problems and how they can be solved within the IDE.
- Each panel in the project properties page can be configuration-specific
(except the General page). This gives you a great amount of flexibility.
For example, you can have different MIDlet-Version values
(Application Descriptor panel) for each configuration's uniquely
named (Creating
Jar panel) distribution Jar.
-
When setting up dependencies between projects, especially when
using Project Configurations, make sure to select the correct
output jar in the Project Jar Files list box of the Select Project
dialog. A project Jar will appear for each configuration in the
project you have selected.
If, for example, you have two projects MyLibrary and MyApplication, both containing two configurations ReleaseConfiguration and DebugConfiguration, then you would take the following steps to set up the dependency correctly:
- Open Project Properties for MyApplication. Select ReleaseConfiguration in the Project Configuration combo.
- Select Libraries & Resources panel, and click the Add Project
button.
- Navigate to the location of MyLibrary project. The Project Jar Files listbox will now contain three Project Jars. Select the one in path dist/ReleaseConfiguration/ and click Add Project Jar Files
- Switch to DebugConfiguration and repeat these steps, except
this time add the project jar located in dist/DebugConfiguration/
This is the manner in which you should set up dependencies between projects when configurations are involved.
- The solution is VCS-friendly. All source files will always be
saved to the hard drive as if DefaultConfiguration was selected.
This prevents conflicts during VCS check-in or update resulting
from have a different active configuration. Be sure to also share
your
project.properties file (located in {projecthome}/nbproject)!
- Projects can be run from the command line without the use of
the IDE. Just type ant run in the project home directory
and the project will be run using the active configuration. You
can
pass a different configuration to the ant script by typing ant
run -Dconfig.active={config_name}
- Projects that used existing preprocessor solutions should be easy to import. Though the NetBeans preprocessor is less complex than some, any situation can be expressed using the provided directives.
- The Libraries & Resources panel or the Filtering panel can be
used to determine which version of a resource should be deployed
to
a distribution
Jar.
- Libraries & Resources: Create multiple versions of a Jar
file containing all resources for the application and then
point to
the correct version of the Jar for each configuration.
So you might have 3 jars:
large_res.Jar, medium_res.Jar, small_res.Jar each
containing resources of the same name, but different resolutions.
Then point your Nokia_large, Nokia_med, Nokia_small
configurations at the correct version.
- Filtering: Include your resources directly in or under the src directory then use the Filtering tree to control which version of the resources are included in the distribution Jar.
Using Non-UEI Compliant Emulator Platforms
Though only 3rd party emulator platforms that follow the UEI specification can be automatically detected by the IDE, non-UEI complient emulators can still be used. This section describes how it can be done.
Adding Non-UEI Compliant Emulators
- In your userhome directory (the Windows default
is C:\Documents
and Settings\{username}\.netbeans and
the Linux default is /home/{username}/.netbeans),
examine the {userhome}\config\Services\Platforms\org-netbeans-api-java-Platform directory.
This
directory contains xml files that define the installed
emulator platforms. You can manually
create these files for any emulator which is not UEI-compliant.
The DTD for this xml file can be found at http://www.netbeans.org/dtds/j2me-platformdefinition-1_0.dtd
- Save the following as SDK_4.1_MRI_7.5.xml to
use the Motorola 7.5 emulator needed for this tutorial.
Note that the use of " is intentional,
and should be saved as such.
<?xml version='1.0'?>
<!DOCTYPE platform PUBLIC '-//NetBeans//DTD J2ME PlatformDefinition 1.0//EN'
'http://www.netbeans.org/dtds/j2me-platformdefinition-1_0.dtd'>
<platform name="Motorola_7_5"
home="C:\WTK\Motorola\SDK v4.1 for J2ME\Emulator7.5"
type="custom"
displayname="Motorola 7.5"
srcpath=""
preverifycmd=""{platformhome}/bin/preverify.exe"
-classpath "{classpath}" -d "{destdir}"
"{srcdir}""
runcmd="">
<device name="Motorola_7_5" securitydomains="trusted,untrusted"
description="Motorola_7_5">
<configuration name="CLDC" version="1.1" displayname="CLDC"
classpath="${platform.home}/lib/cldc.zip"
dependencies="" default="true"/>
<profile name="MIDP" version="2.0" displayname="MIDP"
classpath=";${platform.home}/lib/midp.zip"
dependencies="" default="true"/>
</device>
</platform>
You will need to restart the IDE after saving this XML file. Once
you have done so, you will be able to choose Motorola
7 5 as a platform and Motorola_7_5 as a device. You should associate the Motorola configuration
with this new platform. Note that you may need to delete the cache files
located in {userhome}\var\cache in order for the manually installed platform to be detected.
Also, you should not delete the mdrstorage folder that may also be located there.
Notice that the runcmd attribute
is set to empty string. This is because the command
to start this Motorola emulator takes the MIDlet
to execute as one of its parameters. This
is nothing like UEI standards, and cannot be directly
supported in the IDE. However...
-
If the emulator platform you're using does not require more
information than that provided to UEI emulators, then you can
skip this step. The following
information is provided to UEI emulators:
- Security Domain
- Platform Type
- Platform Home
- Jad Location
- Jad Destination Directory / Jad Name
If your emulator requires additional information (such as the
location of project Jar or the name of the MIDlet to execute),
you can execute emulators
by modifying the build.xml file located in your project home directory.
This file controls all project actions. We can create a new
target here that executes the motorola emulator and passes
all appropriate data whenever
the Run action is invoked on the Motorola configuration.
Add the following code your project's build.xml:
<target description="Run MIDlet suite." depends="init" name="run">
<condition property="run.motorola">
<!-- arg2 must match the configuration name
you would like to use the special emulator -->
<equals arg1="${config.active}" arg2="Motorola"/>
</condition>
<ant inheritrefs="true" inheritall="true" target="run_normal"/>
<ant inheritrefs="true" inheritall="true" target="run_motorola"/>
</target>
<target description="Run MIDlet suite the normal way." depends="init"
name="run_normal" unless="run.motorola">
<nb-run commandline="${platform.runcommandline}"
securitydomain="${evaluated.run.security.domain}"
execmethod="${run.method}" platformtype="${platform.type}"
platformhome="${platform.home}" device="${platform.device}"
jadurl="${dist.jad.url}" jadfile="${dist.dir}/${dist.jad}"/>
</target>
<target description="Run MIDlet suite for motorola's non-UEI emulator."
depends="init" name="run_motorola" if="run.motorola">
<property name="project.home" location="."/>
<!-- the last arg line contains an value "Miner".
This must match the name of the midlet you want to execute -->
<java dir="${platform.home}/bin"
fork="true"
classname="com.mot.tools.j2me.emulator.Emulator"
classpath="${platform.home}/bin/Emulator.jar;${platform.home}/bin/configtool.jar">
<jvmarg value="-Djava.library.path=${platform.home}/lib"/>
<arg value="-classpath${project.home}/${dist.dir}/${dist.jar}"/>
<arg line="-deviceFile"/>
<arg value="${platform.home}/bin/RESOUR~1/T720I~1.PRO"/>
<arg line="javax.microedition.midlet.AppManager Miner -JSA 1 1"/>
</java>
</target>
So the run_motorola target will be run whenever
the active configuration is Motorola. Otherwise, the run_normal target (which uses the normal emulator execution)
will be invoked.
This concludes the Marv the Miner tutorial.
|
Glossary
MIDP
For the J2ME platform, the Mobile Information Device Profile (MIDP) defines
standard set of Java APIs that, together with the Connected Limited Device
Configuration (CLDC). provides a complete J2ME application runtime environment
targeted a mobile information devices, such as cellular phones, two-way pagers,
and wireless personal organizers.
The MIDP profile addresses:
- A display toolkit
- User input methods
- Persistent data storage using a simple record-oriented
database model
- HTTP 1.1-based networking using CLDC Generic Connection framework
The MIDP 1.0 standards are defined in Java Specification Request (JSR)-37.
The MIDP 2.0 standards are defined in JSR-118.
Device Fragmentation
The situation that arises when vendor-specific, proprietary, or optional APIs
are added to mobile devices to expand device functionality.
Other device attributes, such as screen size, color depth, available memory,
and others, also contribute to device fragmentation.
Unified Emulator Interface (UEI)
Set of standards specifying command-line access to emulator functionality.
Related Documents
A short guide to getting your existing J2ME MIDP
applications into NetBeans IDE 4.0 Beta.
Quickly create, build, and execute a simple J2ME
MIDP application.
Guides you through the process of creating, building, and executing a J2ME
MIDP application.
|