Changes to the AddressDB Class
Our only previous option was to retrieve addresses from a comma-delimited text file stored on a remote server. This option was adequate for our simple example but is clearly no way to build an industrial-strength application with many different data sources. Storing the information in XML allows any application to retrieve and parse the data in a reliable, structured manner. Consequently, we'll modify the AddressDB class to handle both J2ME RMS storage and XML data retrieval using the kXML parser. The source code for the new AddressDB class is contained in the following listing.
import javax.microedition.rms.*; import javax.microedition.io.*; import java.io.*; import org.kxml.*; import org.kxml.io.*; import org.kxml.parser.*; import org.kxml.kdom.*; public class AddressDB { private static RecordStore rs = null; public AddressDB() { try { rs = RecordStore.openRecordStore("addressbook", true); } catch (RecordStoreException e) { System.out.println(e); e.printStackTrace(); } } public void addAddress(String Name, String Address) { // Store each address within the "addressbook" record store. // For simplicity's sake, separate the Name // and Address fields with a comma. ByteArrayOutputStream os = new ByteArrayOutputStream(); DataOutputStream output = new DataOutputStream(os); try { output.writeUTF(Name + "," + Address); } catch (IOException e) { System.out.println(e); e.printStackTrace(); } // Now that the address is in the stream, // extract it and add it to the store. byte[] b = os.toByteArray(); try { rs.addRecord(b, 0, b.length); } catch (RecordStoreException e) { System.out.println(e); e.printStackTrace(); } } public static String getName(int index) { int counter = 1; int commalocation = 0; String name = null; //Retrieve the UTF string from the data store. // Note that we start // at position 2 because the writeUTF() // method writes two bytes at // the beginning of the stream to indicate // the number of bytes to follow. try { RecordEnumeration enumRec = rs.enumerateRecords(null, null, false); while ((counter <= index) && (enumRec.hasNextElement())) { String strTemp = new String(enumRec.nextRecord()); commalocation = strTemp.indexOf(','); name = strTemp.substring(2, commalocation); counter++; } } catch (Exception e) { System.out.println(e); e.printStackTrace(); } return name; } public static String getAddress(int index) { int counter = 1; int commalocation = 0; String address = null; try { RecordEnumeration enumRec = rs.enumerateRecords(null, null, false); while ((counter <= index) && (enumRec.hasNextElement())) { String strTemp = new String(enumRec.nextRecord()); commalocation = strTemp.indexOf(','); address = strTemp.substring(commalocation + 1); counter++; } } catch (Exception e) { System.out.println(e); e.printStackTrace(); } return address; } public static int recordCount() { int count = 0; try { count = rs.getNumRecords(); } catch (Exception e) { System.out.println(e); e.printStackTrace(); } return count; } public void loadXML() { StreamConnection c = null; InputStream s = null; Attribute att = null; String Name = null; String Address = null; //Delete the AddressDB try { rs.closeRecordStore(); rs.deleteRecordStore("addressbook"); rs = RecordStore.openRecordStore("addressbook", true); } catch (Exception e) { System.out.println(e); e.printStackTrace(); } try { c = (StreamConnection)Connector.open( "http://localhost/AddressBook.xml"); s = c.openInputStream(); XmlParser parser = new XmlParser(new InputStreamReader(s)); Document document = new Document(); document.parse(parser); Element root = document.getRootElement(); int children = root.getChildCount(); for (int i=0; i < children; i++) { if (root.getType(i) == Xml.ELEMENT) { Element el = root.getElement(i); int babies = el.getChildCount(); for (int j=0; j < babies; j++) { if (el.getType(j) == Xml.ELEMENT) { Element elName = (Element)el.getChild(j); if (elName.getName().equals("name")) { att = elName.getAttribute("value"); Name = att.getValue(); } else if (elName.getName().equals("address")) { att = elName.getAttribute("value"); Address = att.getValue(); } } } addAddress(Name, Address); } } } catch (IOException err) { System.out.println(err); err.printStackTrace(); } } }
Actually, although it's a departure from the previous application, nearly all the changes to the new AddressBook application occur within the loadXML() method. This method loads an XML document using the javax.microedition.io.StreamConnection interface. Once the document has been loaded, it can be parsed using the org.kxml.parser.XmlParser class and analyzed using the org.kxml.kdom.Document class. As you can see, the document tree can be traversed within a loop and each element can be analyzed using an if statement. After each element has been loaded, the name/address pair is added to the database using the addAddress() method. From that point on, address information can be retrieved from the database and displayed on the screen using the same functionality introduced in previous examples.