ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Building Wireless Web Clients, Part 2
Pages: 1, 2, 3

What is Stored in the Bookstore?

In the first part of this article, we used HTTP to get the details for a book and convert them into an instance of the BookInfo class. This class, which we didn't show in the first part of the article, has the following instance variables:



public class BookInfo {

    int    id;          // Used when persisting
    String isbn;        // The book ISBN
    String title;       // The book title
    int    reviews;     // Number of reviews
    int    ranking;     // Current ranking
    int    lastReviews; // Last review count
    int    lastRanking;  // Last ranking

}

The isbn variable is the book ISBN obtained from the user. The values of all of the other variable, with the exception of id (which will be described below), are extracted from the HTML. The reviews and ranking fields hold the current values, while lastReviews and lastRanking are the values that were obtained on the previous query. Each time the book's Web page is fetched from the server, the value of reviews and ranking are copied to lastReviews and lastRanking, respectively, and the values extracted from the Web page are written to reviews and ranking.

The BookInfo class is designed to hold all of the information relating to a book in the BookStore. The intent is that each BookInfo instance will be mapped to a record in the underlying RecordStore. In terms of the RecordStore APIs, a record is simply a contiguous sequence of bytes, the meaning of which is opaque to the platform and to the classes in the javax.microedition.rms package. The RecordStore class provides several methods that operate on records:

public int addRecord(byte[] data, int offset, int length)
Creates a new record initialized with the specified portion of an array of bytes, returning a unique integer identifier known as recordId.

public void setRecord(int recordId, byte[] data, int offset, int length)
Replaces the content of the record identified by recordId with the given portion of an array of bytes. This may cause the record to grow or to become smaller.

public byte[] getRecord(int recordId)
Returns the content of the record with a given recordId.

public int getRecord(int recordId, byte[] buffer, int offset)
Reads the given record into the supplied array, starting at the given offset, and returns the number of bytes that were read.

public void deleteRecord(int recordId)
Deletes the record with the given recordId.

In order to add a record for a new book or replace the data for an existing book, we need to create an array of bytes that represents its BookInfo instance and use either the addRecord() or setRecord() methods to write the bytes to the RecordStore. If you were using J2SE, you might take advantage of object serialization to create a serialized version of each instance of BookInfo for storage, or use the Java Beans persistance mechanism introduced in Java 2 version 1.4 to flatten the object into an XML representation. Unfortunately, neither of these is available to MIDlets. The most convenient way for a MIDlet to convert a class instance into a record is to use a DataOutputStream in conjunction with a ByteArrayOutputStream. Here, for example, is how the BookStore class converts a BookInfo object into a byte array:

    // Writes a record into a byte array.
private byte[] toByteArray(BookInfo bookInfo) throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    DataOutputStream os = new DataOutputStream(baos);

    os.writeUTF(bookInfo.isbn);
    os.writeUTF(bookInfo.title == null ? "" : bookInfo.title);
    os.writeInt(bookInfo.ranking);
    os.writeInt(bookInfo.reviews);
    os.writeInt(bookInfo.lastRanking);
    os.writeInt(bookInfo.lastReviews);

    return baos.toByteArray();
}

The function of the ByteArrayOutputStream is to write everything that it receives into a buffer that can be extracted in the form of a byte array, while the DataOutputStream provides convenience methods that write Java primitives, types, and strings in a platform-independent way to an output stream.

You'll notice that the toByteArray method does not write out the id field from the BookInfo class. This is because each record is implicitly associated with its own recordId and therefore it does not need to be stored in the record content. The recordId is a unique positive integer value assigned when the record is created. Each time a record is written, it is assigned the next recordId, starting from 1. The software guarantees that recordIds are not reused. In particular, if you delete a record, its recordId is not reassigned at any time in the future. The getNextRecordID() method can be used to find out the recordId for the next record to be written to the RecordStore.

Reading the content of a record and converting it to a BookInfo object is a simple matter of reversing the steps shown above, using a ByteArrayInputStream and a DataInputStream to map the byte array returned from the RecordStore method getRecord() to the original Java types:

public BookInfo getBookInfo(int id) throws RecordStoreException,
                                                IOException {
    byte[] bytes = store.getRecord(id);
    DataInputStream is = new DataInputStream(
        new ByteArrayInputStream(bytes));

    String isbn = is.readUTF();
    BookInfo info = new BookInfo(isbn);
    info.id = id;
    info.title = is.readUTF();
    info.ranking = is.readInt();
    info.reviews = is.readInt();
    info.lastRanking = is.readInt();
    info.lastReviews = is.readInt();

    return info;
}

This method assumes that we already have the recordId for the book whose details we require. So how do we get this value?

Pages: 1, 2, 3

Next Pagearrow