Persistent Storage: The LogStorage Class

Beneath the DayLog class for storing the log of a single day, we need another class to store all the DayLogs persistently. The LogStorage class uses a record store for that purpose.

In the constructor, the record store with the name "BloodSugarLog" is opened and assigned to the days object variable:

import javax.microedition.rms.*;
import java.util.*;
import java.io.*;
import java.util.*;


public class LogStorage {

    RecordStore days;
    public LogStorage () throws RecordStoreException {
        days = RecordStore.openRecordStore ("BloodSugarLog", true);
    }
}

The most important functionality of the persistent storage is to provide efficient access to the day log of a specific date. If the logs are stored and put in order by time in the record store, we do not need to iterate all records in order to find a specific date. Instead, we can take advantage of the ordering and perform a so-called binary search. We just pick the middle element and compare it to our target date. Now we know in which half we need to continue the search. Thus, we reduce the questionable records by half with each iteration.

For our binary search, we implement a helper method that just reads the date of a record without building the complete DayLog data structure:

int getDate (int index) throws RecordStoreException {
    byte[] buf = days.getRecord (index);
    return ((((int) buf [0]) & 0x0ff) << 24)
        | ((((int) buf [1]) & 0x0ff) << 16)
        | ((((int) buf [2]) & 0x0ff) << 8)
        | ((((int) buf [3]) & 0x0ff));
}

The getIndex() method performs the binary search, returning the index of the day log of the given date. If a day log for the given date does not exist, the negative index where the day log for the given date should be inserted is returned:

public int getIndex (int date) throws RecordStoreException {

    int i = 1;
    int j = days.getNumRecords ();
    int k;
    int dateK;

    while (i <= j) {
        k = (i + j) / 2;
        dateK = getDate (k);
        if (date == dateK) return k;
        else if (date > dateK) i = k+1;
        else j = k-1;
    }

    return -i;
}

The method for reading a DayLog of a given date is quite simple. First, the index for the given date is calculated by calling getIndex(). Then, whether the index is negative or not, a new DayLog is created or loaded from the record store:

public DayLog getDayLog (int date)
        throws RecordStoreException, IOException  {
    int index = getIndex (date);

    return (index == -1)
        ? new DayLog (date)
            : new DayLog (days.getRecord (index));
}

Storing a DayLog is a bit more complicated. If an entry for the given date does not yet exist, all following records need to be shifted in order to obtain space for the new record:

    public void storeDayLog (DayLog dayLog)
            throws RecordStoreException, IOException {
        if (!dayLog.isDirty ()) return;

        int index = getIndex (dayLog.getDate ());

        byte [] target = dayLog.getByteArray ();

        if (index < 0) {
            index = -index;

            int num = days.getNumRecords ();

            if (index > num) {
                days.addRecord (target, 0, target.length);
                return;
            }

            byte [] buf = days.getRecord (num);
            days.addRecord (buf, 0, buf.length);

            for (int i = num; i > index; i++) {
                buf = days.getRecord (i-1);
                days.setRecord (i, buf, 0, buf.length);
            }
        }

        days.setRecord (index, target, 0, target.length);
    }
}

We also need a method for closing the record store. However, this is quite straightforward:

public void close () throws RecordStoreException {
   days.closeRecordStore ();
}

Finally, we add a static method for converting Java Date objects to our internal format. For this purpose, we create a calendar, set it to the given date, and then read the year, month, and day of month fields:

public static int dateToInt (Date date) {
    Calendar c = Calendar.getInstance ();
    c.setTime (date);
    return (c.get (Calendar.YEAR) << 16)
        | ((c.get (Calendar.MONTH)-Calendar.JANUARY+1) << 8)
        | (c.get (Calendar.DAY_OF_MONTH));
}

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

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