Question

I have a BlackBerry Application that sends messages to a server at fixed intervals. The messages are sent via web service using any of the connection methods available; Wifi, BIS, TCP/IP etc.

Since the messages are being sent continuously, I need a mechanism to queue the messages in case internet is not available and send the messages across when internet becomes available. For that reason, I wish to first save any outgoing message in the Persistent Store and then read the Persistent Store and loop through it to send all pending messages. Any new message should be saved at the last spot in the Persistent Store.

I am calling the two methods below when "Send" is clicked:

    public static void saveMessage(String msg){
        Hashtable hashtable=new Hashtable();
        persistentObject = PersistentStore.getPersistentObject(KEY);
        hashtable.put("MessageToSend", msg);
        persistentObject.commit();
    }

    public static void sendMessage(String msg){
        Hashtable hashtable=new Hashtable();
        persistentObject = PersistentStore.getPersistentObject(KEY);
        Vector msgVector = (Vector)persistentObject.getContents();
        Enumeration eMsgs=msgVector.elements();;
            /*synchronized(poObject )*/{
                persistentObject.setContents(msgVector);
                persistentObject.commit();
            }
            int i=0;
            while(eMsgs.hasMoreElements()){
                hashtable=(Hashtable)eMsgs.nextElement();
                String encryptedMessage=(String)hashtable.get("MessageToSend");
                if(!encryptedMessage.equals("")){
                    //check internet connection
                    String C0NNECTION_EXTENSION = checkInternetConnection();
                    if(C0NNECTION_EXTENSION==null)
                    {
                        Dialog.alert("Check internet connection and try again");
                        return;
                    }
                    else
                    {
                        MyScreen.PostMsgToServer(encryptedMessage);
                        hashtable.remove(encryptedMessage);
                    }
                }
                i++;
            }
    }

This is just an attempt from the tutorials/examples that I came across. Kindly help.

Was it helpful?

Solution

The save method you show is not actually putting the hashtable into the PersistentObject. Try something like this instead:

public static void saveMessage(String msg){
    Hashtable hashtable = new Hashtable();
    persistentObject = PersistentStore.getPersistentObject(KEY);
    hashtable.put("MessageToSend", msg);
    persistentObject.setContents(hashtable);   // <- you were missing this
    persistentObject.commit();
}

That's still probably not a great implementation, because I'm assuming that you might want to call saveMessage() multiple times, and add more than one message to the persistent store (?). Is that right, or can you only ever have one message saved? (if that's true, you can ignore this next suggestion for saveMessage())

public static void saveMessage(String msg){
    persistentObject = PersistentStore.getPersistentObject(KEY);
    Hashtable hashtable = (Hashtable) persistentObject.getContents();
    if (hashtable == null) {
        // lazily initialize the store contents
        hashtable = new Hashtable();
        hashtable.put("MessagesToSend", new Vector());
    }
    Vector queuedMessages = (Vector) hashtable.get("MessagesToSend");
    queuedMessages.addElement(msg);
    // write the store contents to device storage
    persistentObject.setContents(hashtable);
    persistentObject.commit();
}


/** 
 * @param msg TODO: I'm not sure why msg needs to be passed, if 
 *                  saveMessage(msg) was called first? 
 */
public static void sendMessage(String msg){
    // TODO: you could choose to save the message here, so that the caller
    //   need not remember to call both sendMessage() and saveMessage()
    // saveMessage(msg);
    persistentObject = PersistentStore.getPersistentObject(KEY);
    Hashtable hashtable = (Hashtable) persistentObject.getContents();
    if (hashtable != null) {
         // check for saved messages first, and send them
         Vector msgVector = (Vector) hashtable.get("MessagesToSend");
         Enumeration eMsgs = msgVector.elements();
         Vector toDelete = new Vector();
         while (eMsgs.hasMoreElements()) {
              String encryptedMessage = (String)eMsgs.nextElement();

              // if the send was successful, you should delete message from the store
              toDelete.addElement(encryptedMessage);
         }

         eMsgs = toDelete.elements();
         while (eMsgs.hasMoreElements()) {
              // we can delete this sent message now
              msgVector.removeElement((String)eMsgs.nextElement());
         }
         // re-write the persistent store to the device
         persistentObject.setContents(hashtable);
         persistentObject.commit();
    }
}

I'd also generally like to steer you away from making everything static ... that said, that's really a bigger, unrelated issue here, and it does happen that your persistent store object is likely to be a unique, global object in your application (a better implementation, however, would probably avoid all these static declarations).

Update: I'm a little unclear as to how you expect to call these two methods. Based on your description, it seems that you call both saveMessage(msg) and then sendMessage(msg) when Send is clicked by the user. If you save the message first, with my implementation, then there is no need to pass msg in to sendMessage(), since sendMessage() will send out all saved, unsent messages in the queue (vector). So, the API for sendMessage() has an unnecessary parameter. Or, I supposed you could leave sendMessage(String) as the only public method, and have sendMessage(String) first call saveMessage(String).

In any case, that's up to you, and how you want your method calling semantics to work. The basic problem of storing and retrieving persistent objects should be addressed by the code above.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top