43

Recordmanagment2

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: Recordmanagment2
Page 2: Recordmanagment2

Record Management Store

Page 3: Recordmanagment2

By using the RMS…let’s see how.

Page 4: Recordmanagment2

Persistent Storage Basics

• Simple record-oriented database (RMS) stored in Flash mem

• Device-independent API• Records are arrays of bytes that live in record

stores• Record stores are shared within MIDlet suite– MIDP 2.0 allows for optional sharing of record

stores between MIDlet suites • Support for enumeration, sorting, and filtering• Atomic update for single records

Page 5: Recordmanagment2

RMS Classes and Interfaces

• Defined in javax.microedition.rms package• RecordStore– Collection of records

• RecordEnumerator– RecordStore enumerator

• Interfaces– RecordComparator– RecordFilter– RecordListener

Page 6: Recordmanagment2

Using Records

• Nothing fancy here– Array of bytes

• Integer values used a unique ID• Records can be written using java.io API’s in

CLDC support:– DataInputStream DataOutputStream– ByteArrayInputStream ByteArrayOutputStream

int id byte[] data

int id byte[] data

int id byte[] data

J2MERecordStore

OldRecordStore

Page 7: Recordmanagment2

RecordStore Operations

• Standard operations you would expect:– openRecordStore(name,create)– removeRecordStore(name)

• Get list of all known record stores in a MIDlet suite– listRecordStores()

• Get the size of the RS– int getSize() - # of bytes used by the RS– Int getSizeAvailable() – get amount of space

available for both record data and overhead

Page 8: Recordmanagment2

Creating a RecordStore

• Centered around record stores– Small database that contains data called records

• javax.microedition.rms.RecordStore• Record stores are identified by namepublic static final String RS_NAME = "Tasks";try { m_RS = RecordStore.openRecordStore(RS_NAME,

bCreateIfNecessary); } catch (RecordStoreException ex) { this.m_bRecordStoreError = true; this.m_sRecordStoreError = ex.toString(); }

Page 9: Recordmanagment2

Closing/Deleting RecordStore

• Need to make sure that you release the resource

protected void destroyApp(boolean parm1) throws javax.microedition.midlet.

MIDletStateChangeException {try { m_RS.closeRecordStore(); RecordStore.deleteRecordStore(RS_NAME); } catch (RecordStoreException ex) { ex.printStackTrace(); System.out.println(ex.getMessage()); } }

Page 10: Recordmanagment2

RMSMidlet• Sample MIDlet so that you can become familiar with RMS

and take a little tour.– com.sb.samples.midlet.rms package

• Our objective is to introduce RMS basics including:

1. RecordStore creation/closing2. Record adding3. Record lookup filtering via RecordFilter4. RecordStore deletion (no deletions take place

though very easy to add)5. Encapsulating RecordStore I/O operations in

static Utility Class methods for consistency and program simplification

Page 11: Recordmanagment2

RMSMidlet Description

• Very simple• Creates 5 TaskRow objects.• Only object 3 has been designated as 'already

uploaded to server'.• Shows a single form with only those TaskRows

that have not been uploaded to the server (there are 4 of them in this case).

• On the form is the Record ID of the Task• User can press 'View' button to see Task

information

Page 12: Recordmanagment2

TaskRow Class

• com.sb.samples.midlet.rms.TaskRow class that acts as:– Container object for Task values– Decouples Task data from RecordStore

representation– Static utility tool for consistent, maintainable

TaskRow-to-RecordStore I/O

Page 13: Recordmanagment2

Adding Records

• TaskRow offers a number of ways to add, read, and update a record

public static int addRecord(RecordStore rs, TaskRow taskRow) throws Exception {

byte[] bData = TaskRow.toByteArray(taskRow); int iRecordID = rs.addRecord(bData, 0,

bData.length); return iRecordID; } public static void updateRecord(RecordStore rs,

TaskRow taskRow) throws Exception { byte[] bData = TaskRow.toByteArray(taskRow); rs.setRecord(taskRow.iID, bData, 0,

bData.length); }

Page 14: Recordmanagment2

Read Record public static TaskRow readRecord(RecordStore rs, int iRecordID) throws Exception {

byte[] bData = rs.getRecord(iRecordID); TaskRow tr = readRecord(bData); tr.iID = iRecordID; return tr; } // Maintain a single, consistent InputStream-based read mechanism // for use by readRecord and any other usage public static TaskRow readRecord(DataInputStream dis) throws Exception {

TaskRow tr = new TaskRow();

// the order of these reads must match // the reads in TaskRow.toByteArray() with respect to: // 1) the ordering of the values // 2) the data type of each value tr.iRadioID = dis.readInt(); tr.bUploaded = dis.readBoolean(); tr.sTask = dis.readUTF(); tr.sLongitude = dis.readUTF(); tr.sLatitude = dis.readUTF(); tr.sStatus = dis.readUTF(); return tr; }

Page 15: Recordmanagment2

Read Record – Byte Array // Offer a Byte Array-based reader for parts of the program that // do not have a reference to RecordStore // (e.g. by RecordFilter or RecordComparator that receive only

byte arrays)

public static TaskRow readRecord(byte[] bData) throws Exception { ByteArrayInputStream bais = new ByteArrayInputStream(bData); DataInputStream dis = new DataInputStream(bais); try { return readRecord(dis); } finally { if (null != dis){ try { dis.close(); } catch (Exception e){

} } } }

Page 16: Recordmanagment2

Lookup Filtering

• The RMSMidlet keeps track of records that have not been uploaded to a server.

• And then we use a Filter to determine which records need to be uploaded.

Page 17: Recordmanagment2

Filter for Records protected TaskRow[] getUnuploadedTaskRows() throws Exception { // Filter for tasks not yet uploaded to server RecordFilter rf = new RecordFilterTaskNotUploaded(); // If we cared about ordering (e.g. Data created), we'd // create a RecordComparator for that purpose. For now, don't sort. RecordComparator nullRecordComparator = null; boolean bKeepUpdated = false; RecordEnumeration re = m_RS.enumerateRecords(rf,nullRecordComparator,

bKeepUpdated); TaskRow[] aTaskRows = new TaskRow[re.numRecords()]; int i = 0; while (re.hasNextElement()) { int iNextRecord = 0; try { iNextRecord = re.nextRecordId(); TaskRow tr = TaskRow.readRecord(m_RS, iNextRecord); aTaskRows[i] = tr; i++; } catch (Exception ex) { throw ex; } } return aTaskRows; }

Page 18: Recordmanagment2

RecordFilterTaskNotUploaded Class

public class RecordFilterTaskNotUploaded implements RecordFilter { // only allow TaskRows that have not been uploaded to // be accepted public boolean matches(byte[] bCandidate) { try { TaskRow tr = TaskRow.readRecord(bCandidate); if (tr.bUploaded == false) { return true; } else { return false; } } catch (Exception e) { return false; }}

Page 19: Recordmanagment2

RMS Tour

• That concludes our RMS tour.• Unlike most tours, our RMS tour doesn’t end

at a gift shop…

Page 20: Recordmanagment2

Enterprise J2ME(The whirlwind tour…)

Page 21: Recordmanagment2

J2ME and J2EE

• MIDP App’s become a client with Middle-tier access

• XML data provided by a Servlet at well-known URL or through Web Services

• Received as streaming data using networking API’s

• Converted to String for parsing (i.e. kXML)• Display using MIDP UI elements

Page 22: Recordmanagment2

Wireless Enterprise

HTTP

Tomcat BackendSystems

Business TierWeb Tier

XMLRPCServlet

Mobile Services

Page 23: Recordmanagment2

kXML-RPC Usage

Page 24: Recordmanagment2

MIDP & XML

• MIDP networking allows access to data formats like WML, XML– We’re just interested in XML

• Upside– Easy to work with– Most are familiar with XML

• Downside– Expensive– Heavy String manipulation– Footprint for the parser

• For some devices, not as big a deal because available resources are greater

Page 25: Recordmanagment2

MIDP XML Parsers

• A few parsers are available for MIDP• kXML– http://www.kxml.org– Pull parser– SAX and DOM support– Written for J2ME/CLDC/MIDP

• NanoXml– http://nanoxml.sourceforge.net/kvm.html– DOM– Ported

• Both support XSLT

Page 26: Recordmanagment2

kXML-RPC

• kXML-RPC is a J2ME implementation of the XML-RPC protocol built on top of the kXML parser.

• Extremely lightweight mechanism for exchanging data and invoking web services in a neutral, standardized XML format.

• Hides the implementation of kXML

Page 27: Recordmanagment2

Dealing with Payloads

• Not really all that much to do here when using kXML-RPC, the payload is handled for you on the client, and the server uses a TaskHandler to get the parameters

• Let’s look at making a call, and then a sample of what a payload might look like if you wanted to sniff the wire…

Page 28: Recordmanagment2

Making an XML-RPC Call

• Using XML-RPC is as simple as doing the following:

String connect = “http://www.switchbacksoftware.com/service.do”;

String ticker = "Submitting to Server"; updateUI(); XmlRpcClient xmlrpc = new XmlRpcClient(connect); try { String result = (String)

xmlrpc.execute(SB.submitTaskInfo, paramsArray);

Page 29: Recordmanagment2

Payload Example<methodCall> <methodName>SB.submitTaskInfo</methodName> <params> <param> <value> <string>Task1</string> </value> </param> <param> <value> <string>W 12.32560</string> </value> </param> <param> <value> <string>N 72.09090</string> </value> </param>

</params></methodCall>

Page 30: Recordmanagment2

J2ME Web Services API (WSA) JSR-172 (CLDC 1.0 & 1.1) - API's standardize remote service invocation and XML parsing - subsets of based on JAX-RPC 1.1 and SAX2

WTK 2.1, includes the libraries you need to develop MIDlets that take advantage of J2ME WS and also includes a JAX-RPC stub generator

Good article http://developers.sun.com/techtopics/mobility/apis/articles/wsa/

Page 31: Recordmanagment2

Couple more advanced topics…

Timers & System Properties

Page 32: Recordmanagment2

Timer and TimerTask

• Introduced in J2SE 1.3 to schedule tasks for execution by a background thread

• MIDP includes the Timer and TimerTask classes

• Only J2SE classes that are not included in the CLDC but are included in MIDP

• Timer API identical to J2SE version except (there’s always an exception…) the constructor that specifies whether the thread is a daemon is missing.– Remember…daemon threads aren’t supported in

MIDP• TimerTask exactly the same in J2SE & MIDP

Page 33: Recordmanagment2

Timer MIDlet

• Found in com.sb.samples.midlet.timer package

• Objectives:1. Introduce Timer and TimerTask2. Extend RMS basics to include an ‘Updating

Task Records’

Page 34: Recordmanagment2

TimerMIDLet Description

• Creates a TimerTask that does the following each time it is invoked:– Scans RecordStore for TaskRows that have 'not yet

been uploaded‘– Picks the first Task in the list and uploads it via

submitTask()– Updates it's status value and flags it as 'uploaded‘– Updates the respective record in the RecordStore– Makes a sound upon upload– Rebuilds the UI to reflect a dwindling list of 'not

uploaded' Tasks

Page 35: Recordmanagment2

Developer Note

• We’re not going to walk through the building of the UI, since we’ve already seen how Commands are added and handled in other examples

Page 36: Recordmanagment2

TimerMidletpublic class TimerMidlet extends RMSMidlet { Command m_CommandRefresh = null; Timer m_TimerUpload = null; TimerTask m_TimerTaskUploadATaskRow = null;

public TimerMidlet() { super();

// need to create a TimerTask that gets the list of not uploaded TaskRows and

// uploads them (or just the first) and // updates the record to bUploade = true; // m_TimerTaskUploadATaskRow = new TimerTask(){

Page 37: Recordmanagment2

TimerMidletpublic void run() { try { // Get the list of un-uploaded Tasks TaskRow[] aTaskRows = getUnuploadedTaskRows();

if (aTaskRows.length > 0){ TaskRow tr = m_aTaskRows[0]; // Submit them to server submitTask(tr); try { // and update the RMS record TaskRow.updateRecord(m_RS, tr); }

Page 38: Recordmanagment2

TimerMidletcatch (Exception ex) { Alert a = new Alert("Task", "Error updating task "

+ tr.sTask + ":" + ex.getMessage(), null, AlertType.ERROR); a.setTimeout(Alert.FOREVER); AlertType.ERROR.playSound(m_Display); m_Display.setCurrent(a, m_Display.getCurrent()); } try { buildUI(); } catch (Exception e) { } m_Display.setCurrent(m_FormTasks); } } catch (Exception e) { } } };

Page 39: Recordmanagment2

Start the Timer

m_TimerUpload = new Timer(); m_TimerUpload.schedule(this.m_TimerTaskUploadATaskRow, 5000, 10000);

}

Page 40: Recordmanagment2

Submitting The Task protected void submitTask(TaskRow tr) {

Vector vParams = new Vector(); vParams.addElement(tr.sTask); vParams.addElement(tr.sLongitude); vParams.addElement(tr.sLatitude); vParams.addElement(new Integer(tr.iRadioID)); // radio Id String sResult = null;

// normally would use a constants file or properties singleton // or MIDlet attributes String sConnect = HomeBase1.HOME_BASE_SERVER + HomeBase1.HOME_BASE_URL_FILE; XmlRpcClient xmlrpc = new XmlRpcClient(sConnect); try { sResult = (String) xmlrpc.execute(HomeBase1.HOME_BASE_SUBMIT_RPC, vParams); // When not using real phone, sleep so tos // simulate delay for testing destroyApp(false) // Thread.sleep(10000); AlertType.INFO.playSound(m_Display); tr.bUploaded = true; } catch (Exception e) { sResult = "Error Submitting:" + e.getMessage(); AlertType.ERROR.playSound(m_Display); } tr.sStatus = sResult; }

Page 41: Recordmanagment2

System Properties

Page 42: Recordmanagment2

Use of System Properties

• CLDC does not include the java.util.Properties class

• Limited set of properties available using System.getProperty( String key)

• microedition.platform - Name of the host platform or device (implementation-dependent)

• microedition.encoding - Default character encoding Default value:“ISO-8859-1”

• microedition.configuration - Name and version of the supported configuration “CLDC-1.1”

• microedition.profiles - Names of the supported profiles (implementation-dependent)

Page 43: Recordmanagment2

Bootcamp Wrap-up• J2ME is an exciting development opportunity• Fairly easy to transition to if you are at Java-

eese.• Need to make some adjustments in your

programming habits (Come to the J2ME Best Practices session to find out more!)

• J2ME/J2EE integration will be powerful for a new breed of applicationsIf your company is interested in the full 2-day intensive J2ME developer bootcamp or requires contracting services for mobile projects, contact

me directly at [email protected]

Thanks!