Add data storage capacities to your MIDlet apps
record management store)
Application Developer, Entigo
The Mobile Information Device Profile -- the platform for
mobile Java applications -- provides a mechanism for MIDP applications
to persistently store data across multiple invocations. This persistent
storage mechanism can be viewed as a simple record-oriented database
model and is called the record management system (RMS). Here, Soma Ghosh
shows how your J2ME application can use RMS to manage and interpret
data. You'll also get a demonstration of the concept through a sample
The J2ME record management
The J2ME record management
system (RMS) provides a mechanism through which MIDlets can
persistently store data and retrieve it later. In a record-oriented
approach, J2ME RMS comprises multiple record stores.
An overview of J2ME RMS and MIDlet interfacing is given in Figure 1.
Figure 1. Overview of J2ME RMS and MIDlet
Each record store can be visualized as a collection of records, which
will remain persistent across multiple invocations of the MIDlet. The
device platform is responsible for making its best effort to maintain the
integrity of the MIDlet's record stores throughout the normal use of the
platform, including reboots, battery changes, etc.
A record store is created in platform-dependent locations, like
nonvolatile device memory, which are not directly exposed to the MIDlets.
The RMS classes call into the platform-specific native code that uses the
standard OS data manager functions to perform the actual database
Record store implementations ensure that all individual record store
operations are atomic, synchronous, and serialized, so no corruption of
data will occur with multiple accesses. The record store is timestamped to
denote the last time it was modified. The record store also maintains a version, which
is an integer that is incremented for each operation that modifies the
contents of the record store. Versions and timestamps are useful for
When a MIDlet uses multiple threads to access a record store, it is the
MIDlet's responsibility to coordinate this access; if it fails to do so,
unintended consequences may result. Similarly, if a platform performs a
synchronization of a record store with multiple threads trying to access
the record store simultaneously, it is the platform's responsibility to
enforce exclusive access to the record store between the MIDlet and its
Each record in a record store is an array of bytes and has a unique
Managing the device
class represents a RMS record store. It provides several methods to manage
as well as insert, update, and delete records in a record store.
Managing record stores
open a record store, the
openRecordStore() method of
javax.microedition.rms.RecordStore is invoked.
static RecordStore openRecordStore(String recordStoreName, boolean
createIfNecessary) opens a record store with the given name
recordStoreName. If there is no record store of that name,
invoking this method creates one.
If the record store is already open, this method returns a reference to
the same record store object.Listing 1. Open a
RecordStore rs = RecordStore.openRecordStore("MyAppointments",true);
Once all operations are done, a call to Listing
2. Close a RecordStore
closes the record store with the given name. When a record store is
closed, it is disabled for further operations.
A named record store can be deleted by invoking the
Delete a RecordStore
MIDlet invokes the
addRecord() method of
javax.microedition.rms.RecordStore class to insert a new
record into the record store. This is a blocking atomic operation and
recordId for the new record. The record is
written to persistent storage before the method returns.
Listing 4. Insert
public int addRecord(byte data, int offset, int
numBytes) inserts a record represented by an array of bytes
offset as its starting index and
numBytes as its length.
String appt = "new record";
byte bytes = appt.getBytes();
a particular record involves getting a handle for that record and setting
Update a record
public int getRecord(int recordId, byte buffer, int
offset) returns the data stored in the given record in the byte
array represented by
getRecord(int recorded) returns a copy of the data represented by
public void setRecord(int recordId, byte
newData, int offset, int numBytes) sets new information, a stream
of bytes (
offset as its starting
numBytes as its length, at the record location
String newappt = "update record";
Byte data = newappt.getBytes();
Rs.setRecord(1, data, 0, data.length());
deleteRecord() method to delete a record from the
Listing 6. Delete a
public void deleteRecord(int recordId) deletes the record
recordId for this
record is not subsequently reused.
J2ME API provides certain interfaces to interpret the data stored in a
record store. This process involves comparing records to determine their
relative sort order. It also involves the filtering of contents depending
on given conditions.
Comparing recordsListing 7. Comparing
records and determine relative sort order
MIDlet implements the
RecordComparator interface and defines
compare (byte rec1, byte rec2) method to compare two
candidate records. The return value of this method must indicate the
ordering of the two records.
Int compare (byte b1, byte b2)
String s1 = new String(b1);
String s2 = new String(b2);
If (s1.compareTo(s2) > 0)
Else if (s1.compareTo(s2) == 0)
Enumerating recordsListing 8. Enumerating records
RecordEnumeration interface is responsible for enumerating
records in a record store. It logically maintains a sequence of the
recordIds of the records in a record store. The enumerator
will iterate over all of the records (or only a subset, if an optional
record filter has been supplied) in an order determined by a record
comparator. If neither the filter nor the comparator are specified, the
enumeration will traverse all records in the record store in an undefined
RecordEnumeration re = rs.enumerateRecords(null, null, false);
Byte nextRec = re.nextRecord();
Filtering recordsListing 9. Filtering
MIDlet implements the
RecordFilter interface, defining a
filter that examines a record to see if it meets application-defined
criteria. The application implements the
match() method to select the records to be returned by the
Public boolean matches(byte candidate)
String s1 = new String(candidate);
Developing a phone appointment
In this section, we'll demonstrate the functioning of
J2ME RMS by building a phone appointment diary. This application will
allow users to set appointments at certain dates and times, cancel
appointments, or view a list of appointments already set. A quick screen
view is shown in Figure 2.
Figure 2. The phone appointment diary at
A complete list of user interface elements which comprise the various
screens and screen elements of this application is available in the MID
Profile API documentation that accompanies the J2ME Wireless Toolkit; for
more detail on these elements, check out an earlier article I wrote for developerWorks
(see the Resources section below for links to both).
A record store can store a record as a stream of bytes. In our
application, the date and time entered by the user are concatenated into a
string, converted into bytes, and stored.Listing 10.
Add a new appointment to the database
Public boolean matches(byte candidate)
String appt = apptName + " " + apptTime;
byte bytes = appt.getBytes();
Similarly, the application retrieves the record as a stream of bytes
and converts it into a string. The string is in a ####AAAA format, where #
denotes numbers representing time information and AAAA denotes characters
representing a description of the appointment. The application parses the
string to get the date and time information and displays them in a
user-desired format, such as Listing 11. Retrieve a record from the
description - mm/dd/yyyy hh:mm
Parsing data obtained from record store and displaying in a user-desired
byte b = rs.getRecord(j);
String str = new String(b,0,b.length);
at += str.charAt(i);
name += str.charAt(i);
time = Long.parseLong(at);
java.util.Date date = new java.util.Date(time);
java.util.Calendar rightNow = java.util.Calendar.getInstance();
String year = String.valueOf
String month = String.valueOf
(rightNow.get(java.util.Calendar.MONTH) + 1);
String day = String.valueOf
String displayName = name
+ "-" + year + " " + day;
The user is allowed to select certain appointments and delete them from
the record store. Since the deleted Listing 13.
Mark a record as deleted
recordId is not reused so
as to maintain the original sequence in records, the record is marked as
invalid by a distinctive string pattern.
String deactive = "@";
byte b = deactive.getBytes();
As the application displays a list of appointments, it detects the
string pattern of those invalid records and skips them.Listing 14. Skip invalid records
// Record is valid
// Record is invalid.
One of the important aspects of this application is the user interface.
The various screens are as follows:
- Welcome form: The welcome form displays a list of
appointments already set and notifies the user if no appointments have
been set. It provides various options to continue or exit the
- Menu form: The menu form provides the user with the options
to view an appointment, set a new appointment, or cancel an appointment,
- Display form: The display form displays the list of
appointments already set.
- Set form: The set form provides a date selection field and an
input text field to provide the details of a new appointment. When the
user chooses to save, the information is stored in the database.
- Delete form: The delete form lists the set of appointments
and provides the option to select one or more. If the user chooses to
delete, the set of selected appointments is marked as invalid in the
The application implements
ItemStateListener interfaces that allow the application to
respond to various events.
ItemStateListener allows the
application to receive events that indicate changes in the internal state
Listing 15. Acquire values from the screen
DateField, an editable component for presenting date
TextField, an editable text component
ChoiceGroup, a group of selectable elements
// The date value is set to a variable when the
// DateField item is changed
if (item == apptDate)
date = apptDate.getDate();
apptTime = String.valueOf(date.getTime());
// The name of appointment is set to a variable
//when the name input field is changed
if (item == apptField)
apptName = apptField.getString();
// If the ChoiceGroup item state on Delete form is
//changed, it sets an array of appointments selected for deletion
if (item == cg)
Listing 16 contains the complete listing for the
sample application. See my previous article on J2ME in the Resources section for instructions on downloading a
device emulator that will allow you to run this program on your
The bottom line
article, we covered the ability of MID applications to persistently store
and retrieve data; the mechanism is modeled after a simple record-oriented
database. The J2ME API
provides a developers treasure chest of methods and interfaces to utilize
this unique feature of MID application. You should now be able to
integrate data storage into your own micro Java applications.
- Download the J2ME Toolkit to run and test your J2ME applications.
You can also browse through the MID Profile API documentation in the
toolkit to get information on J2ME record stores.
- Stay connected to the wireless world with the developerWorksWireless zone.
- The developerWorksJava technology zone keeps you up to date on events
in the Java arena.
- Check out the latest developments at IBM's Pervasive
- Build Java apps with IBM's Visual Age for
A graduate in computer science and engineering,
Soma Ghosh has developed a wide range of Java applications in the
areas of e-commerce and networking over the past seven years. She
believes that wireless commerce represents the near future of the
industry and has recently been drawn to wireless initiatives of
existing desktop components and models. Soma is currently an
application developer with Entigo, a pioneer and industry leader in
real e-business solutions and B2B sell- and service-side e-commerce
products. She can be reached at email@example.com.