Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.



Published on

Published in: Technology
  • Be the first to comment

  • Be the first to like this


  1. 1. Record Management Store
  2. 2. By using the RMS…let’s see how.
  3. 3. 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
  4. 4. RMS Classes and Interfaces • Defined in javax.microedition.rms package • RecordStore – Collection of records • RecordEnumerator – RecordStore enumerator • Interfaces – RecordComparator – RecordFilter – RecordListener
  5. 5. J2ME Using Recordsint id RecordStore byte[] data int id byte[] data int id byte[] data Old RecordStore • Nothing fancy here – Array of bytes • Integer values used a unique ID • Records can be written using API’s in CLDC support: – DataInputStream DataOutputStream – ByteArrayInputStream ByteArrayOutputStream
  6. 6. 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
  7. 7. Creating a RecordStore • Centered around record stores – Small database that contains data called records • javax.microedition.rms.RecordStore • Record stores are identified by name public static final String RS_NAME = "Tasks"; try { m_RS = RecordStore.openRecordStore(RS_NAME, bCreateIfNece ssary); } catch (RecordStoreException ex) { this.m_bRecordStoreError = true;
  8. 8. 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()); }
  9. 9. RMSMidlet • Sample MIDlet so that you can become familiar with RMS and take a little tour. – package • 1. 2. 3. 4. Our objective is to introduce RMS basics including: RecordStore creation/closing Record adding Record lookup filtering via RecordFilter RecordStore deletion (no deletions take place though very easy to add) 5. Encapsulating RecordStore I/O operations in static Utility Class methods for consistency
  10. 10. 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
  11. 11. TaskRow Class • 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
  12. 12. 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); }
  13. 13. 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; }
  14. 14. 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){ } } } }
  15. 15. 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.
  16. 16. 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; }
  17. 17. RecordFilterTaskNotUpload ed 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; }
  18. 18. RMS Tour • That concludes our RMS tour. • Unlike most tours, our RMS tour doesn’t end at a gift shop…
  19. 19. Enterprise J2ME (The whirlwind tour…)
  20. 20. 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
  21. 21. Wireless Enterprise Web Tier Mobile Services Tomcat HTTP XMLRPC Servlet Business Tier Backend Systems
  22. 22. kXML-RPC Usage
  23. 23. 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
  24. 24. MIDP XML Parsers • A few parsers are available for MIDP • kXML – – Pull parser – SAX and DOM support – Written for J2ME/CLDC/MIDP • NanoXml – – DOM – Ported
  25. 25. 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
  26. 26. 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…
  27. 27. Making an XML-RPC Call • Using XML-RPC is as simple as doing the following: String connect = “”; String ticker = "Submitting to Server"; updateUI(); XmlRpcClient xmlrpc = new XmlRpcClient(connect); try { String result = (String) xmlrpc.execute(SB.submitTaskInfo, paramsArray);
  28. 28. 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>
  29. 29. 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 
  30. 30. Couple more advanced topics… Timers & System Properties
  31. 31. 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.
  32. 32. Timer MIDlet • Found in package • Objectives: 1. Introduce Timer and TimerTask 2. Extend RMS basics to include an ‘Updating Task Records’
  33. 33. 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
  34. 34. 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
  35. 35. TimerMidlet public 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(){
  36. 36. TimerMidlet public 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); }
  37. 37. TimerMidlet catch (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) { } } };
  38. 38. Start the Timer m_TimerUpload = new Timer(); m_TimerUpload.schedule(this.m_TimerTaskUpl oadATaskRow, 5000, 10000); }
  39. 39. 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;
  40. 40. System Properties
  41. 41. 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)
  42. 42. Bootcamp Wrap-up J2ME is an exciting development opportunity • • Fairly easy to transition to if you are at Javaeese. • 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 applications If your company is interested in the full 2-day intensive J2ME developer bootcamp or requires contracting services for mobile projects, contact me directly at