Ordered Traversal: Comparators and Record Enumerations

So far, you've accessed records by their primary index only. But what if you want to sort the journeys in the previous example's travel list by the length of the trip or the date, without requiring that they all be entered in the correct order? For this purpose, RMS provides record enumerations.

Record enumerations let you visit all the records in a record store in a custom order. The first step is to define the custom order. You do so by implementing the compare() method of the RecordComparator interface, which defines an order for the records. The compare() method takes two byte arrays as parameters. It returns one of the constants EQUIVALENT, FOLLOWS, or PRECEDES, depending on the relative order of both records. If in the desired search order the record given as the first parameter follows the second, FOLLOWS must be returned. The other cases are analogous.

For the Journey class, you can implement a RecordComparator that sorts all entries by date as follows:

public class JourneyDateComparator implements RecordComparator {
    public int compare (byte[] rec1, byte[] rec2) {
        Journey journey1 = new Journey (rec1);
        Journey journey2 = new Journey (rec2);
        if (journey1.date > journey2.date) return FOLLOWS;
        if (journey1.date == journey2.date) return EQUIVALENT;
        else return PRECEDES;
    }
}

Here, direct access to the portion of the byte array where the date is encoded may result in improved performance. However, the readability of the example would also suffer.

By giving the RecordComparator to the method enumerateRecords() in the class RecordStore, you can obtain a RecordEnumeration. The RecordEnumeration provides methods to move forward and backwards in the RecordStore with respect to the order defined by the Comparator implementation.

The enumerateRecords() method takes three parameters: a RecordFilter, the RecordComparator, and a boolean value determining if the RecordEnumeration should be kept updated, reflecting changes of the record store performed during traversal. There may be a significant tradeoff in speed when setting the “keep updated” parameter, but the parameter can be useful when the record store is changed during traversal. The RecordFilter parameter allows enumeration of a subset of the records. (It's explained in the next section.) Both the RecordFilter and RecordComparator parameters can be set to null, resulting in an unfiltered, unordered enumeration.

The RecordEnumeration returned from enumerateRecords() can be traversed using the hasNextElement() and nextRecord() methods. When the record enumeration is no longer needed, the application should call destroy() in order to notify the system that system resources allocated for the record enumeration can be released.

The following code snippet shows how your JourneyDateComparator and the RecordEnumeration can be used to traverse a travel record store, ordered by journey date:

RecordStore travelList = RecordStore.open ("travelList", true);
RecordEnumeration enumeration = travelList.enumerateRecords
                   (null, new JourneyDateComparator (), false);

while (enumeration.hasNext ()) {
    Journey journey = new Journey (enumeration.next ())
    // place real operations here
}
enumeration.destroy()
travelList.closeRecordStore ();

You can also add methods for comparing the destination (or distance), allowing you to iterate the records ordered correspondingly. Table 5.4 shows a general overview of the methods of the RecordEnumeration class.

Table 5.4. Methods of RecordEnumeration
Name Purpose
void destroy() Releases system resources associated with this enumeration.
boolean hasNextElement() Indicates whether records are left in the enumeration.
boolean hasPreviousElement() Analogous to hasNextElement(), but in the inverse direction.
boolean isKeptUpdated() Indicates whether the enumeration is kept updated.
void keepUpdated (boolean keepUpd) Sets or resets the automatic update mode.
byte[] nextRecord() Returns the next record.
int nextRecordId() Returns the ID of the next record.
int numRecords() Returns the number of records in this enumeration. Differs from RecordStore.getNumRecords() for filtered or outdated enumerations only.
byte[] previousRecord() Returns the previous record.
int previousRecordId() Returns the ID of the previous record.
void rebuild() Rebuilds the enumeration to reflect all changes. Performed automatically in the updated mode.
void reset() Resets the enumeration to the first record.

Filtered Record Enumerations

You have already seen that the enumerateRecords() method has a filter parameter, but we have not explained how to use it. The corresponding RecordFilter interface works similarly to the RecordComparator interface. It provides a single method, matches(), which takes a record byte array as input and returns a boolean value, determining whether the given record passes the filter.

For example, if you need an enumeration of the journeys where the distance was greater than x kilometers, you can implement it as follows:

Class MinDistanceFilter {
    int min;
    DistanceFilter (int min) {
        this.min = min;
    }
    boolean matches (byte[] record) {
        return new Journey (record).getDistance () >= min;
    }
}

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset