/*
* Copyright (c) 2000-2001 Sun Microsystems, Inc. All Rights Reserved.
*/
import javax.microedition.lcdui.Alert;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.List;
import javax.microedition.lcdui.Screen;
import javax.microedition.midlet.MIDlet;
import javax.microedition.rms.RecordComparator;
import javax.microedition.rms.RecordEnumeration;
import javax.microedition.rms.RecordStore;
import javax.microedition.rms.RecordStoreException;
import javax.microedition.rms.RecordStoreNotOpenException;
/**
* A simple class that shows various functionality of RMS.
* The general flow of this MIDlet is:
*
* In the constructor (See RMSMIDlet),
* create and populate two record stores, one of personal
* contacts, the other with business contacts.
* Display the first screen. This screen shows a list
* of all RMS stores found in the MIDlet suite's name
* space. This screen allows the user to select a
* record store and either display pertinent information
* about the record store such as size, etc., or to view
* the contents of the selected store. When the contents
* of a record store are viewed, they are sorted by last
* name, though this can be changed by instantiate a
* SimpleComparator object with the appropriate
* sort order parameter.
*
* Traversal from screen to screen is handled
* by RMSMIDlet, commandAction.
*
*/
public class RMSMIDlet extends MIDlet implements CommandListener {
private Display myDisplay; // handle to the display
private Alert alert; // used to display errors
// Our commands to display on every screen.
private Command CMD_EXIT;
private Command CMD_DETAILS;
private Command CMD_OK;
// Our screens
private List mainScr;
private List detailScr;
private List dataScr;
// An array of all RMS stores found in this
// MIDlets name space.
private String[] recordStoreNames;
/**
* Seed data for creating personal contacts RMS store
*/
private final String personalContacts[] = {
"John", "Zach", "2225556669",
"Mark", "Lynn", "5125551212",
"Joy", "Beth", "2705551234",
"Abby", "Lynn", "4085558566",
};
/**
* Seed data for creating business contacts RMS store
*/
private final String businessContacts[] = {
"Ted", "Alan", "4125552235",
"Sterling", "Wincle", "9995559111",
"Deborah", "Elaine", "4445552323",
"Suzanne", "Melissa"," 5125556064",
"Frank", "Kenneth", "7775551212",
"Dwight", "Poe", "1115557234",
"Laura", "Beth", "2055558888",
"Lisa", "Dawn", "2705551267",
"Betty", "June", "5555551556",
"Yvonne", "Poe", "6665558888",
"Lizzy", "Loo", "5025557971",
"John", "Gerald", "3335551256",
};
/**
* Display a warning on the screen and revert
* to the main screen.
*
* s A warning string to display
*/
private void doAlert(String s) {
alert.setString(s);
myDisplay.setCurrent(alert, mainScr);
}
/**
* Notify the system we are exiting.
*/
private void doExit() {
destroyApp(false);
notifyDestroyed();
}
/**
* In our simple MIDlet, all screens have the same commands,
* with the possible exception of the detailScr.
*
* Also set up the command listener to call commandAction.
* See RMSMIDlet#commandAction
*/
private void addCommonCommands(Screen s,
boolean doDetails) {
s.addCommand(CMD_OK);
s.addCommand(CMD_EXIT);
if (doDetails) {
s.addCommand(CMD_DETAILS);
}
s.setCommandListener(this);
}
/**
* The public constructor. In our constructor, we get
* a handle to our display and create two record stores.
* In the event of an error, we display an alert.
*/
public RMSMIDlet() {
CMD_EXIT = new Command("Exit", Command.EXIT, 3);
CMD_DETAILS = new Command("Details", Command.SCREEN, 2);
CMD_OK = new Command("OK", Command.OK, 1);
myDisplay = Display.getDisplay(this);
alert = new Alert("Warning");
alert.setTimeout(2000);
CreateAddressBook.createRecordStore("Personal",
personalContacts);
CreateAddressBook.createRecordStore("Business",
businessContacts);
// Now, get a list of RMS stores and add their
// names to the mainScr.
recordStoreNames = RecordStore.listRecordStores();
mainScr = new List("Select RMS Store", List.IMPLICIT,
recordStoreNames, null);
addCommonCommands(mainScr, true);
}
/**
* Called by the system to start our MIDlet.
*/
protected void startApp() {
myDisplay.setCurrent(mainScr);
}
/**
* Called by the system to pause our MIDlet.
* No actions required by our MIDLet.
*/
protected void pauseApp() {}
/**
* Called by the system to end our MIDlet.
* No actions required by our MIDLet.
*/
protected void destroyApp(boolean unconditional) {}
/**
* Generate a screen with a sorted list of the contents
* of the selected RMS store identified by index
* If any errors encountered, display an alert and
* redisplay the mainScr.
*
* index an index into recordStoreNames
*/
public void genDataScr(int index) {
SimpleComparator rc;
RecordEnumeration re;
RecordStore rs;
dataScr = null;
byte record[];
try {
rs = RecordStore.openRecordStore(
recordStoreNames[index], false);
} catch (RecordStoreException e) {
doAlert("Could not open " + recordStoreNames[index]);
return;
}
// Create an enumeration that sorts by last name
rc = new SimpleComparator(
SimpleComparator.SORT_BY_LAST_NAME);
try {
re = rs.enumerateRecords(null, rc, false);
} catch (RecordStoreNotOpenException e) {
doAlert("Could not create enumeration: " + e);
return;
}
// Create a screen and append the contents of the
// selected RMS store.
dataScr = new List(recordStoreNames[index] + " Data",
List.IMPLICIT);
addCommonCommands(dataScr, false);
try {
while (re.hasNextElement()) {
byte[] b = re.nextRecord();
dataScr.append(SimpleRecord.getFirstName(b) +
" " + SimpleRecord.getLastName(b),
null);
}
} catch (Exception e) {
doAlert("Could not build list: " + e);
dataScr = null;
} finally {
try {
rs.closeRecordStore();
} catch (RecordStoreException e) {}
}
}
/**
* Generate a screen that shows some of the details
* of the selected RMS store.
*
* RMS store information displayed:
* - name
* - number of records
* - size, in bytes
* - available size, in bytes
* - version number
*
* index an index into recordStoreNames
*/
public void genDetailScr(int index) {
RecordStore rs;
detailScr = null;
try {
rs = RecordStore.openRecordStore(
recordStoreNames[index],
false);
} catch (Exception e) {
doAlert("Could not open " + recordStoreNames[index]);
return;
}
detailScr = new List(recordStoreNames[index] + " Details",
List.IMPLICIT);
addCommonCommands(detailScr, false);
try {
detailScr.append("Name: " + rs.getName(), null);
detailScr.append("# recs: " +
rs.getNumRecords(), null);
detailScr.append("Size: " + rs.getSize(), null);
detailScr.append("Avail: " +
rs.getSizeAvailable(),null);
detailScr.append("Version: " +
rs.getVersion(), null);
} catch (Exception e) {
detailScr = null;
doAlert("Failed to retrieve data");
return;
} finally {
try {
rs.closeRecordStore();
} catch (RecordStoreException e) {}
}
}
/***
* Respond to command selections.
* Commands are:
* EXIT: if selected, then exit
(see RMSMIDlet, doExit)
* OK: if selected, interpreted in the context of
* the current screen.
*
* This method implements a state machine that drives
* the MIDlet from one state (screen) to the next.
*/
public void commandAction(Command c,
Displayable d) {
// Every screen has an EXIT command.
// Handle this consistently for all screens.
if (c == CMD_EXIT) {
doExit();
return;
}
// switch based on screen.
if (d == mainScr) {
// main screen: two commands to handle. If
// OK was selected, then generate the dataScr
// and make it active. If DETAILS was selected,
// generate the detailScr and make it active.
if ((c == List.SELECT_COMMAND) || (c == CMD_OK)) {
genDataScr(mainScr.getSelectedIndex());
myDisplay.setCurrent(dataScr);
} else if (c == CMD_DETAILS) {
genDetailScr(mainScr.getSelectedIndex());
myDisplay.setCurrent(detailScr);
}
} else if (d == detailScr) {
// If OK selected, go back to mainScr
if (c == CMD_OK) {
myDisplay.setCurrent(mainScr);
}
} else if (d == dataScr) {
// If OK selected, go back to mainScr
if (c == CMD_OK) {
myDisplay.setCurrent(mainScr);
}
}
}
}
/*
* Copyright (c) 2000-2001 Sun Microsystems, Inc. All Rights Reserved.
*/
/**
* Static helper class that creates a record
* store from data in an array.
*/
class CreateAddressBook {
// Don't allow this class to be instantiated
private CreateAddressBook() {}
/**
* Helper method that creates a record
* store from data in an array.
* Returns:
* true if RMS store was created
* false otherwise
* name the name of the record store to create
* seedData an array w/ data to seed record store
*/
static boolean createRecordStore(String name,
String[] seedData) {
RecordStore recordStore;
boolean ret = false;
// Delete any previous record store with same name.
// Silently ignore failure.
try {
RecordStore.deleteRecordStore(name);
} catch (Exception rse) {}
// Create new RMS store. If we fail, return false.
try {
recordStore = RecordStore.openRecordStore(name, true);
} catch (RecordStoreException rse) {
return ret;
}
ret = true; // assume success
// Now, populate the record store with the seed data
for (int i = 0; i < seedData.length; i += 3) {
byte[] record = SimpleRecord.createRecord(seedData[i],
seedData[i+1],
seedData[i+2]);
try {
recordStore.addRecord(record, 0, record.length);
} catch (RecordStoreException rse) {
ret = false;
break;
}
}
// Get here when adds are complete, or an error occured.
// In any case, close the record store. We shouldn't
// have a failure, so silently ignore any exceptions.
try {
recordStore.closeRecordStore();
} catch (RecordStoreException rsne) {}
return ret;
}
}
/*
* Copyright (c) 2000-2001 Sun Microsystems, Inc. All Rights Reserved.
*/
/**
* This class implements the RecordComparator interface.
* It works on the records created by SimpleRecord.
* It sorts on either first name or last name.
*/
class SimpleComparator implements RecordComparator {
/**
* Sorting values (sort by first or last name)
*/
public final static int SORT_BY_FIRST_NAME = 1;
public final static int SORT_BY_LAST_NAME = 2;
/**
* Sort order. Set by constructor.
*/
private int sortOrder = -1;
/**
* Public constructor: sets the sort order to be
* used for this instantiation.
*
* Sanitize s: if it is not one of the
* valid sort codes, set it to SORT_BY_LAST_NAME
* silently.
* s the desired sort order
*/
SimpleComparator(int s) {
switch (s) {
case SORT_BY_FIRST_NAME:
case SORT_BY_LAST_NAME:
this.sortOrder = s;
break;
default:
this.sortOrder = SORT_BY_LAST_NAME;
break;
}
}
/**
* This is the compare method. It takes two
* records, and depending on the sort order
* extracts and lexicographically compares the
* subfields as two Strings.
*
* r1 First record to compare
* r2 Second record to compare
* return one of the following:
*
* RecordComparator.PRECEDES
* if r1 is lexicographically less than r2
* RecordComparator.FOLLOWS
* if r1 is lexicographically greater than r2
* RecordComparator.EQUIVALENT
* if r1 and r2 are lexicographically equivalent
*/
public int compare(byte[] r1,
byte[] r2) {
String n1 = null;
String n2 = null;
// Based on sortOrder, extract the correct fields
// from the record and convert them to lower case
// so that we can perform a case-insensitive compare.
if (sortOrder == SORT_BY_FIRST_NAME) {
n1 = SimpleRecord.getFirstName(r1).toLowerCase();
n2 = SimpleRecord.getFirstName(r2).toLowerCase();
} else if (sortOrder == SORT_BY_LAST_NAME) {
n1 = SimpleRecord.getLastName(r1).toLowerCase();
n2 = SimpleRecord.getLastName(r2).toLowerCase();
}
int n = n1.compareTo(n2);
if (n < 0) {
return RecordComparator.PRECEDES;
}
if (n > 0) {
return RecordComparator.FOLLOWS;
}
return RecordComparator.EQUIVALENT;
}
}
/*
* Copyright (c) 2000-2001 Sun Microsystems, Inc. All Rights Reserved.
*/
/**
* This class provides static methods that allow us
* to hide the format of a record.
* N.B. no synchronized access is provided
*/
final class SimpleRecord {
private final static int FIRST_NAME_INDEX = 0;
private final static int LAST_NAME_INDEX = 20;
private final static int FIELD_LEN = 20;
private final static int PHONE_INDEX = 40;
private final static int MAX_REC_LEN = 60;
private static StringBuffer recBuf =
new StringBuffer(MAX_REC_LEN);
// Don't let anyone instantiate this class
private SimpleRecord() {}
// Clear internal buffer
private static void clearBuf() {
for (int i = 0; i < MAX_REC_LEN; i++) {
recBuf.insert(i, ' ');
}
recBuf.setLength(MAX_REC_LEN);
}
/**
* Takes component parts and return a record suitable
* for our address book.
*
* return byte[] the newly created record
* first record field: first name
* last record field: last name
* num record field: phone number
*/
public static byte[] createRecord(String first,
String last,
String num) {
clearBuf();
recBuf.insert(FIRST_NAME_INDEX, first);
recBuf.insert(LAST_NAME_INDEX, last);
recBuf.insert(PHONE_INDEX, num);
recBuf.setLength(MAX_REC_LEN);
return recBuf.toString().getBytes();
}
/**
* Extracts the first name field from a record.
* return String contains the first name field
* b the record to parse
*/
public static String getFirstName(byte[] b) {
return new String(b, FIRST_NAME_INDEX, FIELD_LEN).trim();
}
/**
* Extracts the last name field from a record.
* return String contains the last name field
* b the record to parse
*/
public static String getLastName(byte[] b) {
return new String(b, LAST_NAME_INDEX, FIELD_LEN).trim();
}
/**
* Extracts the phone number field from a record.
* return String contains the phone number field
* b the record to parse
*/
public static String getPhoneNum(byte[] b) {
return new String(b, PHONE_INDEX, FIELD_LEN).trim();
}
}
|