Record Management System di J2ME
Data storage and retrieval is an essential aspect of application development. The data that is stored will depend on the type and complexity of the application. In some cases the only persistent data to be stored is the application user preferences. In other cases you may need to store and manage a repository of contact information. On the high end, you could be designing a data storage solution for a full range of supply-chain data. No matter what the case, there is just one all-purpose data storage and management solution for MIDP-enabled devices, and that is the Record Management System (RMS).
In this article, the first of a companion series to the two-part J2ME 101 tutorial series, we’ll explore the inner workings of MIDP’s persistent storage system. We’ll start with a quick overview of RMS, but most of the article (like the tutorial series) will be hands-on. Together, we’ll build MIDlets that will help you understand how data records are written to and read from the RMS, as well as the variety of sorting, searching, and retrieval options that are available within this remarkably well-rounded and compact data management system.
Please note that this article assumes that you are familiar with MIDlet development in the J2ME environment. You will need to have a J2ME development environment installed on your system in order to compile the code examples. See the Resources section for links to installation instructions for the J2ME Wireless Toolkit (WTK).
Put simply, the MIDP Record Management System (RMS) provides a means to store application data that persists across invocations of a MIDlet. You can visualize the RMS record store as a very simple database, where each row consists of two columns: one containing a unique row identifier, the other a series of bytes representing the data in the record. Table 1 illustrates a simple record store database.
Table 1. A record store database
Record ID Data
1 Array of bytes
2 Array of bytes
3 Array of bytes
…
The unique row identifer is an integer value. The first entry will have the ID of 1, the next of 2, and so on. Row identifiers are not re-used if a row is deleted. That is, if we have three rows in a table with the IDs 1, 2, and 3, deleting ID 2 will remove this identifier permanently from the record store. If we were to add another row to this table, it would have an identifier of 4.
Record stores are identified by name. A name may consist of up to 32 characters, and all characters are case sensitive. No two record stores within a MIDlet suite (that is, a collection of one or more MIDlets packaged together) may contain the same name.
Each record store has a version number as well as a date/time stamp. Both values are updated whenever a record is added, replaced, or deleted.
Creating a record store
No constructor exists for creating a record store. Instead, we use a set of three dual-purpose methods to create and/or open record stores. Each method is shown in Listing 1.
Listing 1. Creating and opening record stores
Deleting a record store
When a MIDlet suite is deleted from a device, any record stores created by the suite will also be removed.
The first method opens the named record store if it exists. If the named record store does not exist, and if the parameter createIfNecessary is set to true, the method can be used to create a new (named) record store. The second method operates in the same fashion but employs two additional parameters to specify the record store’s access restrictions. The first parameter specifies whether or not only those MIDlets in the same suite can access the record store. The second one specifies whether MIDlets that have access to the record store, can create new records. The last method provdes a means for a MIDlet to open a record store in another MIDlet suite.
A handful of methods are available for working with a record store. These range from adding, deleting, and replacing record contents to enumerating through a record store. Each available method is shown in Listing 2.
Locking a record
Unlike a traditional database, RMS offers no methods to lock a record store. It is up to the device implementation to ensure that all operations are synchronous. Should you use separate threads to access a record store, it is up to you to ensure that threads accessing resources do not interfere with each other.
You’ll learn more about the RecordStore API and many of its methods as we work through the examples in the sections that follow.
Our first illustrative example is the ReadWrite MIDlet. This MIDlet has the ability to create a record store, write several records into persistent storage, read back those same records, and delete the record store upon exiting. As you study the code below, note that the MIDlet contains several “convenience” methods, which are methods used time and again when working with the RMS. Convenience methods are the methods used to open, close, and delete record stores.
Take a look at the complete code for the ReadWrite MIDlet and then we’ll discuss it in more detail.
A couple of points are worth mentioning before we move on. First, note that in this example we created a new record store by passing true for the createIfNecessary parameter when calling RecordStore.openRecordStore(REC_STORE, true), as previously explained.
Second, when we wrote to the record store with writeRecord(String str), we first converted the Java string parameter into a byte array. This byte array was then passed to addRecord(rec, 0, rec.length) to insert a record into the record store.
Finally, in the readRecords() method we allocated a byte array to store any record data we read from the RMS. This allows us to make a specific check on each read to ensure that the array is large enough to hold the data. Once the record has been retrieved, we can output the contents to the console.
Figure 1 shows the output of the ReadWrite MIDlet when it is run from within the J2ME WTK.
Figure 1. Record output from the ReadWrite MIDlet
Read and write Java primitives
The ReadWrite MIDlet only writes text strings to the record store. For the next example, we’ll add the ability to store and manipulate arrays of integer, boolean, and string values. We’ll also add support for reading and writing using Java streams. As with the previous example, we’ll write several records and then read them back from the store.
As with any MIDlet that needs to access the record store, we begin by using the openRecordStore() method to allocate and open (or create) a record store, as shown in Listing 3.
Listing 3. Create a record store
Listing 4 shows the primitive data types we’ll write to the record store.
Listing 4. Java primitive data types
If you’re familiar with using streams in the Java language, you’ll find little difference between working with a MIDlet and with a more traditional Java application. The steps are as follows:
- Allocate streams
- Write the data
- Flush the stream
- Transfer the stream data into an array
- Write the array to the record store
- Close the streams
Listing 5 shows how to write to RMS using a stream:
Next we want to read from the record store. We begin by creating the necessary input streams, then loop through each record, storing its contents in a byte array. Accessing the data input stream we read each Java primitive type from the byte array and print the associated contents to the console, as shown in Listing 6.
Listing 6. Reading a stream from the record store
Now check out the source code for the ReadWritePrimitives MIDlet. Study it carefully, and then run the code in your WTK emulator to view the output if you like.
The console output for the ReadWritePrimitives MIDlet should look as shown in Figure 2.
Figure 2. Output of the ReadWritePrimitives MIDlet

For the most part, the code for the IntegerSort MIDlet (see the complete source code) won’t differ much from that of our previous MIDlets. The biggest change is the addition of a comparator class (Listing 13) and the methods for extracting the appropriate fields and performing the actual sorting. Following is the ComparatorInteger class that handles all the details for the IntegerSort MIDlet.
Listing 13. The ComparatorInteger class
Pay close attention to the code for reading the Java primitives. We need to retrieve the integer value from each record. However, this value is the second “field” stored in each record. Therefore, we simply read the string (UTF) value and toss it aside. The second read stores the integer value in a local variable (x1 or x2). These values are then compared to determine the proper sort order.
With the comparator code written, we next create an enumerator, referencing an instance of the ComparatorInteger class. The enumerator will create a result set of records from the record store, using the comparator as the sorting algorithm. Listing 15 is a partial listing of the readStream() method which creates the comparator as well as the enumerator, and loops through the result set displaying record contents on the console.
Listing 15. readStream() method
Back to top
Sorting with a comparator is one option when working with an enumerator, searching with a filter is the other. A minor difference between a comparator and a filter is that a comparator returns the entire record store in sorted order, whereas a filter returns only those records that match a specified criteria. If you apply both a comparator and a filter, records that match the search criteria will be returned in sorted order.
Like the RecordComparator, the RecordFilter is implemented by the addition of a single method, matches(), to the enumerator code. The enumerator calls thematches() method for each record in the store. Based on the boolean return value, the record either becomes a member of the result set or is tossed aside as a record that does not meet the search criteria.
Listing 16. The RecordFilter API’s matches() method
Listing 17 shows a class that implements the RecordFilter interface. Notice that the search string is specified as a parameter to the constructor SearchFilter. The string is saved in a private variable so we have access to the string when the enumerator calls the matches() method to create the result set. For this example, the search string is also converted to lowercase, resulting in a search that is not case-sensitive.
Listing 17. Building a RecordFilter
Note that the actual code that performs the search in this example is quite trivial. Using the Java string method indexOf(), we look for the specified search string and return a boolean value indicating success or failure.
We’ll build one last MIDlet to illustrate what you’ve learned so far. (Here’s the complete source for the StringSearch MIDlet.) In addition to allowing us to search the RMS for records, this MIDlet beefs up the user interface we’ve worked with so far. Instead of using only the console for output, we’ll display a TextField component (which you should recall from the tutorial series!) that will prompt the user for a text string. When requested, we’ll search the record store for the string. Any and all matches will be appended on the display, showing the search results.
Listing 18 shows the search strings that will be written into the record store.
Listing 18. Entries to the record store
Figure 4 shows the MIDlet with two different search results.
No related posts.
Related posts brought to you by Yet Another Related Posts Plugin.



