Filtering and Ordering Records with RMS

If you’ve ever used the Record Management System mechanism in MIDP, you already know how useful the RecordStore class can be for storing persistent data. In a previous tutorial, Using RMS to Store Persistent Data, we used the RecordStore.getRecord(int) method to retrieve a record by its ID. However, sometimes you may have more complex retrieval criteria than simply the record ID. That’s where the enumerateRecords() method comes in handy. In this article we will discuss how to filter and order a subset of records in a RecordStore object using enumerateRecords()

The complete signature of the enumerateRecords() method looks like this:

public RecordEnumeration enumerateRecords(
RecordFilter, RecordComparator, boolean)
throws RecordStoreNotOpenException

This method returns an object that enumerates a set of records from the RecordStore. The RecordFilter argument allows the application to specify criteria that will used to return a subset of records. Similarly, the RecordComparator argument allows the application to define logic that will determine the order of the records that are returned.

For example, lets say we have an application with a record store containing ZIP codes.

/**
 * Initializes record store with some ZIP codes.
 */
public RecordStore initRecordStore() {
try {
    
    // Open or create RecordStore
    RecordStore recordStore
    = RecordStore.openRecordStore("zipCodes", true);

    // Add records if this record store hasn't yet 
    // been initialized
    if(recordStore.getNumRecords() == 0) {
        recordStore.addRecord("49120".getBytes(), 0, 5);
        recordStore.addRecord("90210".getBytes(), 0, 5);
        recordStore.addRecord("56921".getBytes(), 0, 5);
        recordStore.addRecord("10210".getBytes(), 0, 5);
        recordStore.addRecord("32010".getBytes(), 0, 5);
    }

    return recordStore;

} catch(RecordStoreException e) {

    System.err.println("Could not initialize record store");
    return null;

}
}

Now, let’s say we want to be able to return only ZIP codes that appear in a specific range, and we want them returned in lexicographical order. First we will create a class that implements RecordFilter to specify the filtering. The start and end of the range will be data members of this class.

import javax.microedition.rms.*;

public class RangeRecordFilter implements RecordFilter {

/**
 * Creates a new instance of RangeRecordFilter
 */
public RangeRecordFilter(String start, String end) {
    setStart(start);
    setEnd(end);
}

/**
 * Determines if candidate is in specified range.
 */
public boolean matches(byte[] candidate) {
    String candidateString = new String(candidate);

    return (getStart().compareTo(candidateString) <= 0
        && getEnd().compareTo(candidateString) >= 0);
}

public String getStart() {
    return start;
}

public void setStart(String start) {
    this.start = start;
}

public String getEnd() {
    return end;
}

public void setEnd(String end) {
    this.end = end;
}

private String start;
private String end;
    
}

Next, we will create a class that implements RecordComparator to specify the ordering.

import javax.microedition.rms.*;

public class StringRecordComparator implements RecordComparator {

public int compare(byte[] rec1, byte[] rec2) {
    
    // Convert to String objects
    String rec1String = new String(rec1);
    String rec2String = new String(rec2);

    // Do a string comparison
    int comparison = rec1String.compareTo(rec2String);
    if(comparison < 0) {
        return RecordComparator.PRECEDES;
    } else if(comparison == 0) {
        return RecordComparator.EQUIVALENT;
    } else {
        return RecordComparator.FOLLOWS;
    }

}

}

Now we can use these classes to return an ordered subset of ZIP codes in a specified range from our record store. For example:

RecordStore recordStore = initRecordStore();
if(recordStore != null) {

    // Create filter and comparator
    RangeRecordFilter filter =
        new RangeRecordFilter("40000", "60000");
    StringRecordComparator comparator
        = new StringRecordComparator();

    // Enumerate matching records
    RecordEnumeration records;
    try {
        records = recordStore.enumerateRecords(
        filter, comparator, false);
    } catch(RecordStoreNotOpenException e) {
        System.err.println("Could not enumerate");
        return;
    }

    // Output the results
    while(records.hasNextElement()) {
    byte[] rec;
    try {
        rec = records.nextRecord();
    } catch(Exception e) {
        System.err.println("Could not get record");
        return;
    }
    System.out.println(new String(rec));
}

For more information about record stores, be sure to read the javax.microedition.rms Package Documentation

Bookmark this Post

One Response to “Filtering and Ordering Records with RMS”

  1. Lea Hayes Says:

    Thanks for this interesting article. If you get a chance I would really appreciate it if you could take a look at my question below.

    Is it possible to enumerate records by “Record ID”? If I understand correctly, specifying “null” as the comparator will return records in an undefined order. From what you have written here I can understand how to write a comparator that looks at the actual record data.

    Do I need to store a duplicate copy of the “Record ID” actually in the record data, or is there a more efficient approach?

Leave a Reply