Palm ImageViewer

Because the HTTP stream method uses the least memory and is the fastest end-to-end, we will use this method for the Palm version of ImageViewer.

The ImageViewer constructor sets up the application display. We will use a ChoiceGroup for selecting the image to display, another ChoiceGroup for selecting locally or remotely stored images, an ImageItem to display the image, a Command for saving remote images to local storage, and a Command for exiting the application.

Here is the constructor code:

public ImageViewer() {
   // populate the list with local names
   String[] names = getNames(true);
   if (names == null)
     nameChoice = new ChoiceGroup("Names", ChoiceGroup.EXCLUSIVE, NAMES, null);
   else
     nameChoice = new ChoiceGroup("Names", ChoiceGroup.EXCLUSIVE, names, null);
   // add the items to the form
   mainForm.append(nameChoice);
   mainForm.append(locationChoice);
   mainForm.append(imageItem);
   mainForm.addCommand(saveCommand);
   mainForm.addCommand(exitCommand);
   mainForm.setCommandListener(this);
   mainForm.setItemStateListener(this);
}

Note that the ImageViewer class implements two interfaces: the CommandListener interface and the ItemStateListener interface.

public class ImageViewer extends MIDlet  implements CommandListener, ItemStateListener

This is because we need to listen for Command selections, and state changes and name selections in the ChoiceGroups.

The screen looks like Figure 8.16 on starting the application.

Figure 8.16. The Palm OS version of ImageViewer

graphics/08fig16.jpg

Selecting the Location ChoiceGroup causes the itemStateChanged method to be called. Making a choice of location results in the Names list being populated with image names according to the Location selection. Selecting an image name results in the image being displayed on the screen.

public void itemStateChanged(Item item) {
   Runtime.getRuntime().gc();
   try {
      String location = locationChoice.getString( locationChoice.getSelectedIndex());
      System.out.println("location: " + location);
      imageItem.setLabel("Please wait...");
      if (item == locationChoice) {
         String[] names = getNames(location.equals("Local"));
         System.out.println("there are " + names.length + " names");
         int namesInList = nameChoice.size();
         for (int i=0; i<namesInList; i++)
            nameChoice.delete(0);
         for (int i=0; i<names.length; i++)
            nameChoice.append(names[i], null);
         imageItem.setImage(Image.createImage( Image.createImage(10,10)));
      }
      else if (item == nameChoice) {
         String name = nameChoice.getString(nameChoice.getSelectedIndex());
         imageItem.setImage(Image.createImage( Image.createImage(10,10)));
         Image image = getImage(name, location.equals("Local"));
         imageItem.setImage(image);
      }
      imageItem.setLabel("Image");
   }
   catch (Exception e) {
      System.out.println("Error: " + e.toString());
   }
}

Images are stored on the client in a RecordStore. The image names are retrieved from the RecordStore as follows:

store = RecordStore.openRecordStore(recordStoreName, true);
RecordEnumeration re = store.enumerateRecords(null, null, false);
names = new String[re.numRecords()];
int i=0;
while(re.hasNextElement()) {
   ByteArrayInputStream bis = new ByteArrayInputStream(re.nextRecord());
   dis = new DataInputStream(bis);
   names[i++] = dis.readUTF();
}
store.closeRecordStore();

When a local image name is selected, the image is retrieved from the RecordStore as follows:

[View full width]
RecordStore store = null; try { store = RecordStore.openRecordStore(recordStoreName, true); RecordEnumeration re = store.enumerateRecords(null, null, false); while(re.hasNextElement()) { ByteArrayInputStream bis = new ByteArrayInputStream(re.nextRecord()); dis = new DataInputStream(bis); if (dis.readUTF().equals(name)) { int imageSize = dis.readInt(); imageByteArray = new byte[imageSize]; dis.readFully(imageByteArray); image = Image.createImage(imageByteArray, 0, imageByteArray.length); } } store.closeRecordStore(); } catch (Exception e) { System.out.println("Error:" + e.toString()); } finally { try { if (store != null) store.closeRecordStore(); if (dis != null) dis.close(); } graphics/ccc.gifcatch (Exception e) {} }

To retrieve the image names from the server, the following code should look familiar from the previous examples:

[View full width]
String url = "http://192.168.0.1:8080/javaonpdas/servlet/ graphics/ccc.gifImageServiceStreamProxy?service-end-point=http://localhost:8080/axis/servlet/ graphics/ccc.gifAxisServlet&action=getNames"; connection = (HttpConnection)Connector.open(url); connection.setRequestMethod(HttpConnection.GET); dis = connection.openDataInputStream(); int numberOfNames = dis.readInt(); names = new String[numberOfNames]; for (int i=0; i<numberOfNames; i++) { names[i] = dis.readUTF(); }

Retrieving the image from the server is the same technique we used in the HTTPStreamClient:

[View full width]
HttpConnection connection = null; String url = "http://192.168.0.1:8080/javaonpdas/servlet/ graphics/ccc.gifImageServiceStreamProxy?service-end-point=http://localhost:8080/axis/servlet/ graphics/ccc.gifAxisServlet&action=getImage&name="+name; try { connection = (HttpConnection)Connector.open(url); connection.setRequestMethod(HttpConnection.GET); int contentLength = (int)connection.getLength(); if (contentLength>0) { dis = connection.openDataInputStream(); imageByteArray = new byte[contentLength]; int ch = 0; for (int i=0; i<contentLength; i++) { if ((ch = dis.read()) != -1) { imageByteArray[i] = (byte)ch; } else { System.out.println("Error: encountered EOF"); } } image = Image.createImage(imageByteArray, 0, imageByteArray.length); } } catch (Throwable t) { System.out.println("Error:" + t.toString()); t.printStackTrace(); } finally { try { if (dis != null) dis.close(); if (connection != null) connection.close(); } catch (Exception e) {} }

Saving an image is only possible if it is remote. In this case, we take the image array already retrieved to display the image and store it in the record store. If the image name already exists in the record store, the stored image is replaced.

First, we open the record store and create a byte array that stores the record store element:

store = RecordStore.openRecordStore(recordStoreName, true);
System.out.println("size in bytes (before): "+store.getSize());
// create the new record byte array
ByteArrayOutputStream bos = new ByteArrayOutputStream();
dos = new DataOutputStream(bos);
String name = nameChoice.getString(nameChoice.getSelectedIndex());
dos.writeUTF(name);
dos.writeInt(imageByteArray.length);
dos.write(imageByteArray, 0, imageByteArray.length);
byte[] ba = bos.toByteArray();

Then we look for the name in the record store, and update the stored image if the name is already there.

RecordEnumeration re = store.enumerateRecords(null, null, false);
System.out.println("looking for " + name + " in " + re.numRecords() + " records");
boolean found = false;
int recordID = 1;
while(re.hasNextElement()) {
   ByteArrayInputStream bis = new ByteArrayInputStream(re.nextRecord());
   System.out.println("looking at record "+recordID);
   dis = new DataInputStream(bis);
   if (dis.readUTF().equals(name)) {
      System.out.println(name + " found match - updating");
      store.setRecord(recordID, ba, 0, ba.length);
      found = true;
      break;
   }
   else
      System.out.println("no match");
      recordID++;
}

If the image name is not found, the image is added and the record store is closed:

if (!found) {
   System.out.print(name + " not found - adding " + ba.length);
   int addedID = store.addRecord(ba, 0, ba.length);
   System.out.println(" ID = " + addedID);
}
System.out.println("size in bytes (after): "+store.getSize());
store.closeRecordStore();

The full source code for the Palm version of ImageViewer is located in C:\JavaOnPDAs\Palm\src\com\javaonpdas\webservices\clients\custom\ ImageViewer.java.