Sharing Data Between MIDlet Suites

   
By Richard Marejka, March 3, 2005  

Download the source

Introduction

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.

The Why

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:

  • Don't share the record store.
    • You do lose the storage efficiency and ease of management that would come from consolidating and sharing the data.
  • Encrypt the data and share read-only.
    • The key must be known by all authorized MIDlets, or entered by the user at runtime.
    • The time required to decrypt the data will affect performance, and CPU-intensive decryption will shorten battery life. Given that subscribers are playing 2D and 3D games on their devices, however, there is sufficient computing capacity for a few one-way crypto operations.
    • If the key is compiled into the various MIDlets it can be found.
  • Obscure the record store's name.
    • If the name is compiled into the various MIDlets it can be found.
  • Require authentication.
    • The data can be readable but authentication is required to use it.
  • Store the key on a server and require authentication.
    • The application authenticates itself to the server and receives the key in return.
    • The key is never stored on the client.
The How

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:

  • Vendor name is the value of the MIDlet-Vendor attribute found in the JAD, the manifest, or both.
  • MIDlet suite name is the value of the MIDlet-Name attribuute in the JAD file.
  • Record store name is a case-sensitive string of 1 to 32 Unicode characters, given to the record store when you create it.

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.

An Example

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.

Conclusion

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.

Where to Go from Here
Left Curve
Java SDKs and Tools
Right Curve
Left Curve
Java Resources
Right Curve
JavaOne Banner
Java 8 banner (182)