| Sign In/My Account | View Cart |
Building Wireless Web Clients, Part 2
Pages: 1, 2, 3
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)recordId.public void setRecord(int recordId, byte[] data, int offset, int length)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)recordId.public int getRecord(int recordId, byte[] buffer, int offset)public void deleteRecord(int recordId)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?