Ask a question
Thursday, 17 September 2009 16:45

Mobile Databases for MIDP Devices

Rate this item
(1 vote)

12.1 PointBase Micro Edition

Among all mobile databases, PointBase Micro (v4.5) has the best CLDC/MIDP support. It actually produces a SQL database on the MIDP platform. Point-Base provides a set of proprietary Lite APIs under the com.pointbase.me package to access its MIDP database. The PointBase Lite API is very similar to JDBC. The only thing a JDBC developer needs to know to get started is the URL to obtain a Connection object (Listing 12.1).

Listing 12.1. Connect to a PointBase Micro MIDP database
public void connect() {

  try {

    Connection c = DriverManager.getConnection(

                "jdbc:pointbase:micro:" +

                m_dbname, "PBPUBLIC", "PBPUBLIC");

    Statement s = c.createStatement();

  } catch (Exception ex) {

    // Handle the error

  }

}

The PointBase Micro Lite database has a footprint of 47 KB. In the Lite API's PreparedStatement and ResultSet classes, the setter and getter methods support only the following types: Int, String, Decimal, Date, and Bytes. The setBytes() and getBytes() methods allow us to manipulate binary database fields (i.e., Blob fields). You can use your camera phone to take pictures and store them in your on-device PointBase MIDP database! For more details, please refer to PointBase Micro documentation and sample applications (see "Resources").

PointBase also provides a utility MIDlet, com.pointbase.me.tools. MicroConsoleMIDP. It allows developers to quickly peek into a database without writing a single line of access and UI code. The console has a simple UI to browse the content and schema of currently available tables. This console MIDlet is especially useful during the testing and debugging stages of application development. We can bundle it into our testing MIDlet Suite to view the database content at real time for diagnostic purposes. Screen shots of the MIDP Micro Console in action are shown in Figure 12.1.

Figure 12.1. The PointBase Micro MIDP Console.

 

12.2 The Oracle J2ME SODA SDK

The Oracle9i Lite database does not run on the MIDP platform. Instead, Oracle provides a Java object database for MIDP devices. The Oracle J2ME SDK (beta) supports the Oracle Simple Object Database Access (SODA) data store. Built on top of the standard RMS, SODA allows us to store, search, and retrieve Java data objects directly. The oracle.wireless.me.soda package contains six classes (see descriptions in Table 12.1).

Table 12.1. Oracle Simple Object Database Access (SODA) API

Listing 12.2. The SODA demo
DBSession sess = new DBSession();



// Create a new DBClass with an INT field

// and a String field.

// The name of this DBClass is "dept". You can

// get it by its name using findClass() method

// in the sess object.

DBClass dept = sess.createClass(

    "dept",

    new DBAttr[] {

      new DBAttr("id", DBAttr.C_INT),

      new DBAttr("name", DBAttr.C_STRING)

    }

);



// Load a comma delimited database file.

// It will create a number of DBObjects

// under the "dept" DBClass.

DBLoader.loadCSV(dept, new InputStreamReader(in), dept.allAttr());



// Now, get all DBObjects (null match condition)

// in dept class in a DBCursor

DBCursor c = dept.createCursor(null, null);



// Iterate and get all field attributes

// in the DBClass.

DBAttr[] a = dept.getAttrs();

for (int i = 0; i < a.length; i++)

  System.out.print(a[i].name+", ");

  System.out.println();

  DBObject o;

  // Iterate through the cursor and get

  // data in each column (field).

  while ((o = c.next()) != null) {

    for (int i = 0; i < a.length; i++)

      System.out.print(o.getString(i)+",");

      System.out.println();

    }

    c.close();

}



// Remember to release resources.

sess.close();

12.3 The IBM DB2e FastRecordStore

IBM DB2e (v8.1) provides a FastRecordStore class over the MIDP standard RMS record store. FastRecordStore packs several database rows into one RMS record and supports indexes for fast lookup. This results in much improved performance over the linear RMS record store.

To create a database table in a FastRecordStore, we have to first create the table in a DB2e backend database. Then, we synchronize the table to the MIDP device using IBM DB2e Sync. After the synchronization, a FastRecordStore with the same name as the backend table is created. We can now read or update data in the FastRecordStore via the TableMetaData class. All the changes we make on the MIDP client will be sent back to the backend table upon the next synchronization operation. For more information about database synchronization and the IBM Sync,

Note

We cannot start with record stores on the MIDP client first, as they will be deleted on the first synchronization.


In the FastRecordStore, each table row is packed into a byte array. Developers are required to manipulate those raw arrays manually. All rows start with a dirty byte and are followed by data in each column according to the following rules.

  • If the column is not nullable, the data for the column is present.

  • If the column is nullable there is a 1-byte boolean null indicator. If the indicator is true, no data follows. Otherwise, the column data follows.

To illustrate the above points, the SQL INSERT statement in Listing 12.3 can be interpreted as the Java code in Listing 12.4.

Listing 12.3. SQL script for a sample table
create table MyTable (a int, b int not null, c varchar(20),

                      id bigint not null primary key);

insert into MyTable values (null, 10, 'Have fun', 99);

Listing 12.4. Java code for the INSERT statement in Listing 12.3
DataOutputStream dout = new DataOutputStream(byteArrayOutStrm);

// The dirty byte

dout.writeByte(0);



// 'a' is null, no data follows

dout.writeBoolean(true);



// 'b', not nullable

// So there is no null indicator

dout.writeInt(10);



// 'c' is nullable, but not null

dout.writeBoolean(false);

dout.writeUTF("Have fun");



// 'id' not nullable

dout.writeLong(99);

The following code (Listing 12.5) demonstrates how to iterate through rows, delete a row, and read out data in a FastRecordStore.

Listing 12.5. Browse the FastRecordStore
  TableMetaData rs = ((MIDPISync)isync).getTableMetaDataByName(sName);

  int numCols = rs.getNumCols();

  FastRecordStore rms = FastRecordStore.openRecordStore(sName, false);

  Index index = new Index(rms, rs);

  FastRecordEnumeration enum = rms.enumerateRecords(null, null, false);



  // Iterate through rows

  while (enum.hasNextElement()) {

    int id = enum.nextRecordId();

    int recSize = rms.getRecordSize(id);

    byte data = new byte[recSize];

    recSize = rms.getRecord(id, data, 0);



    // Example: delete a row

    if (id == rowToDelete) {

      data[0] = ISync.ROW_DELETED;

      index.updateRecord(id, data, recSize);

      continue;

    }



    // Read out each field for each row

    ByteArrayInputStream bin = new ByteArrayInputStream(data);

    DataInputStream din = new DataInputStream(bin);

    din.readByte(); // dirty byte



    for (int c = 0; c < numCols; c++) {

    int type = rs.getType(c);

    boolean isNullable = rs.isNullable(c);

    boolean ind = false;

    if (isNullable) ind = din.readBoolean();

    if (ind) continue;

    switch (type) {

      case VARCHAR:

        strval = din.readUTF();

break;

      case INTEGER:

        intval = din.readInt();

break;

      // more ...

    }

  }

}



 
Last modified on Wednesday, 23 September 2009 20:48
Vicky

Vicky

E-mail: This e-mail address is being protected from spambots. You need JavaScript enabled to view it