|
| By Richard Marejka, March 3, 2005 |
|
| |
| |
The original MIDP specification defined a persistent, record-based storage facility called the Record Management Store (RMS). A MIDlet suite can use RMS to create one or more
record stores, each identified by a unique name. You'll find the necessary classes and interfaces in the
javax.microedition.rms package. The
RecordStore class provides open, close, read, write, and update operations, and methods to delete both individual records and whole stores. The package includes interfaces for enumeration, sorting, and filtering of RMS content.
In MIDP 1.0 each store is private to the MIDlet suite that creates it. The MIDP 2.0 specification adds a very useful new capability to the RMS package: It enables one MIDlet suite to share a record store with other MIDlet suites.
| |
Duplicating data in multiple record stores raises serious synchronization issues. If an item is created, updated, or deleted in one store, the same transaction must be executed in all similar stores on the same device. Because a MIDP 2.0-based application suite can give other MIDlet suites access to any of its record stores, you can consolidate data at a single location. By eliminating data duplication, not only do you avoid synchronization problems, but you simplify management, and use more efficiently the limited storage common in MIDP-enabled devices.
To make a record store visible to other MIDlet suites, the suite that owns it must share it explictly, specifying either read-only or read-write access. The MIDP standard does not define other access privileges or restrictions. If a record store is exported, it is exported to all MIDlet suites, and all of them have the same access mode. Note that a store created using the MIDP 1.0 RMS package is not shared, which is not surprising: the MIDP 2.0 RMS package is backward-compatible with the MIDP 1.0 version.
Unrestricted sharing of a record store raises trust issues. The store is accessible to any MIDlet that can generate its name. Furthermore, if it's shared writable, any MIDlet can change or delete its data. If you don't want shared data to be quite so freely accessible, here are some possible tactics to consider:
| |
Sharing an RMS record store requires two or more parties: an owner and one or more consumers. The owner is responsible for creating and naming the store and establishing its authorization mode – sharable or not – and its access mode – writable or not. Consumers gain access to the record store using its name. As you'd expect, they can't access a store that isn't sharable, or modify one that's not writable.
A shared RMS is identified by the tuple (Vendor name, MIDlet suite name, Record store name) where:
MIDlet-Vendor attribute found in the JAD, the manifest, or both.
MIDlet-Name attribuute in the JAD file.
To support sharing, the MIDP 2.0 standard adds two fields and three methods to the
javax.microedition.rms package.
The first new method opens an existing record store, or creates a new one and sets its authorization and
writable characteristics. The first new method, used only by the owning MIDlet suite, opens an existing record store, or creates a new one and sets its authorization and
writable characteristics.
static RecordStore
openRecordStore( String recordStoreName, boolean create,
int authmode, boolean writable );
The parameters are:
recordStoreName sets the name of the record store.
create, if
true, creates the store if it doesn't already exist.
authmode specifies the authorization mode:
RecordStore.AUTHMODE_PRIVATE to block sharing or
RecordStore.AUTHMODE_ANY to permit it.This parameter is ignored if the store already exists.
writeable, if
true, specifies that other MIDlet suites may write to the record store. This parameter too is ignored if the store already exists.
Given the last three parameters and the possibility that the store already exists, there are 16 possible combinations of starting conditions. Eight of the cases reduce to a common outcome: If the record store already exists the method simply ignores the
authmode and
writable parameters – this method does not change the access characteristics of an existing store. Four of the combinations result in an exception:
RecordStoreNotFound is thrown if the record store doesn't already exist and
create is
false. In the remaining four combinations, the record store doesn't exist and
create is
true, and
openRecordStore() creates the store with the specified
authmode and
writable attributes. Note that if you specify
AUTHMODE_PRIVATE the effect of
writable is undetectable.
The method a consumer uses to open a shared record store is:
static RecordStore
openRecordStore( String recordStoreName, String vendorName,
String suiteName );
where:
recordStoreName is the name of the shared record store to open.
vendorName is the value of
MIDlet-Vendor attribute in the
owning MIDlet suite.
suiteName is the name of the owning MIDlet suite.
The method opens the specified record store successfully only if it exists and the owner has set its
authmode to
AUTHMODE_ANY. Note that you can't detect the value of the store's
writable attribute directly. The only way to discover whether write access is enabled is to try a write operation and be prepared to catch an execption if write access is not allowed. If the write succeeds, be sure to delete the record to prevent the store growing without bound. Be aware that record deletion too can throw a
RecordStoreException, which must be handled appropriately.
Note that
MIDlet-Version, available from the JAD or the manifest, is not part of the parameter list. The implication is that the owning MIDlet suite cannot change the record format of a shared record store without affecting the store's consumers.
The last new method is:
void
setMode( int authmode, boolean writable );
where:
authmode specifies the new authorization mode of the record store,
AUTHMODE_PRIVATE or
AUTHMODE_ANY.
writable specifies the store's new writable mode.
Only the owning MIDlet suite may change the
authmode and
writable characteristics. There is no method to query the current settings of these attributes.
| |
The
sample application consists of two MIDlet suites that share a collection of URLs, which might be used to identify different access points to a corporate network. The interesting bits of the
URL class look like this:
import java.io.*;
public class URL {
private String protocol;
private String path;
public URL( byte[] data ) throws ... {
fromByteArray( data );
}
public URL( String p, String f ) {
protocol = p;
path = f;
}
public String getProtocol() {
return protocol;
}
public String getPath() {
return path;
}
public byte[] toByteArray() throws ... {
byte[] data;
...
return data;
}
private void fromByteArray( byte[] array ) throws ... {
...
}
}
The collection of URLs is managed by the
URLdb class, which uses RMS to store the collection.
URLdb has two constructors: one for the owner to use, one for the consumer.
import java.io.*;
import javax.microedition.rms.*;
public class URLdb {
RecordStore rs;
public URLdb( String name ) throws ... { // Owner
rs = RecordStore.openRecordStore( name, true,
RecordStore.AUTHMODE_ANY, false );
}
public URLdb( String recordStoreName, String vendorName,
String suiteName ) throws ... { // Consumer
rs = RecordStore.openRecordStore( recordStoreName,
vendorName, suiteName );
}
public void close() throws ... {
rs.closeRecordStore();
}
public int add( String protocol, String path ) throws ... {
URL url = new URL( protocol, path );
byte[] data;
data = url.toByteArray();
return rs.addRecord( data, 0, data.length );
}
public URL getURL( int recordID ) throws ... {
byte[] data = rs.getRecord( recordID );
return new URL( data );
}
public void delete( int recordId ) throws ... {
rs.deleteRecord( recordId );
}
public int RecordCount() {
return rs.recordCount();
}
public RecordEnumeration enumerate()
throws RecordStoreNotOpenException {
return rs.enumerateRecords( null, null, true );
}
}
The owning MIDlet, called
SharedRMS, provides create, read, update, and delete operations on the URL collection. It uses the owner form of the
URLdb constructor, and creates and populates the URL collection as needed.
The consumer MIDlet, called
UseRMS, uses the consumer form of the
URLdb constructor.
UseRMS has only about two thirds as many lines as
SharedRMS because it supports only the read operation on the URL collection.
| |
The MIDP RMS package provides persistent, record-based storage for MIDlets. The MIDP 2.0 specification adds a highly useful capability: One MIDlet suite can share a record store with others, granting them read-only or read-write access, depending on application requirements. By centralizing common data at a single location, a shared record store can simplify management, reduce on-device storage requirements, and avoid the synchronization problems that can arise when data is duplicated in multiple record stores.
| |
javax.microedition.rms package
