- 19.1 Why Messaging?
- 19.2 Sending Messages
- 19.3 Sending Binary Messages
- 19.4 Sending Multipart Messages
- 19.5 Receiving Messages
- 19.6 A Simple Messaging Application
- 19.7 Summary
19.6 A Simple Messaging Application
HermesMIDlet (see Figure 19.1) demonstrates how to send and receive SMS messages. It sends and receives on port 50,000. If you download the example from the book's Web site, the MIDlet suite descriptor has a static push registry entry, but HermesMIDlet also attempts to register itself dynamically if the static registration fails for any reason.
Figure 19.1 Running HermesMIDlet
The entire application consists of four classes:
- HermesMIDlet runs the show. It handles commands and knows how to send messages.
- HermesMessageReader receives incoming messages in its own thread. It is a MessageListener.
- HermesForm is the user interface for creating a message.
- HermesMessageForm is the user interface for displaying an incoming message.
The whole source code is lengthy, so only the interesting parts are here.
Sending a message is straightforward. Two methods in HermesMIDlet get the job done, and that includes the sendText() method you've already seen.
public void run() { String cs = "sms://" + mHermesForm.getAddress() + ":50000"; String text = mHermesForm.getMessage(); try { sendText(cs, text); } mDisplay.setCurrent(mHermesForm); catch (IOException ioe) { showErrorAlert(ioe); } catch (InterruptedException ie) { showErrorAlert(ie); } } public void sendText(String cs, String text) throws IOException, InterruptedException { MessageConnection mc = (MessageConnection)Connector.open(cs); TextMessage tm = (TextMessage) mc.newMessage(MessageConnection.TEXT_MESSAGE); tm.setPayloadText(text); mc.send(tm); }
HermesMessageReader handles incoming messages. Its start() method attempts to place an entry in the PushRegistry if that entry is not already present. In addition, it opens the incoming MessageConnection and registers itself as a listener.
HermesMessageReader maintains two lists, implemented as Vectors. The first is a list of MessageConnections with incoming data. Every time the listener callback method notifyIncomingMessage() is called, the connection is added to the list. In addition, the waiting thread in run() is awakened.
The second list contains received messages. When the run() thread wakes up, it retrieves a message from a waiting MessageConnection. The received message is put in the message list. The MIDlet retrieves available messages using the hasMore() and next() methods.
import java.io.*; import java.util.*; import javax.microedition.io.*; import javax.wireless.messaging.*; public class HermesMessageReader implements MessageListener, Runnable { private volatile boolean mTrucking; private Vector mConnections; private Vector mMessages; private HermesMIDlet mMIDlet; private MessageConnection mConnection; public HermesMessageReader(HermesMIDlet midlet) { mConnections = new Vector(); mMessages = new Vector(); mMIDlet = midlet; } public void start() throws IOException { mTrucking = true; Thread t = new Thread(this); t.start(); // Try push registry registration if static registration // did not work. String[] registered = PushRegistry.listConnections(false); if (registered == null || registered.length == 0) { try { PushRegistry.registerConnection( "sms://:50000", "HermesMIDlet", "*"); } catch (IOException ioe) { System.out.println(ioe); } catch (ClassNotFoundException cnfe) { System.out.println(cnfe); } } // Register as a listener for our connection. mConnection = (MessageConnection)Connector.open("sms://:50000"); mConnection.setMessageListener(this); } public synchronized void stop() { mTrucking = false; notify(); try { mConnection.close(); } catch (IOException ioe) { System.out.println(ioe); } } // MessageListener method. public synchronized void notifyIncomingMessage( MessageConnection mc) { mConnections.addElement(mc); notify(); } // Runnable method. public synchronized void run() { while (mTrucking) { try { MessageConnection mc = null; if (mConnections.size() == 0) wait(); if (mTrucking == false) break; mc = (MessageConnection)mConnections.elementAt(0); mConnections.removeElementAt(0); Message m = mc.receive(); mMessages.addElement(m); mMIDlet.notifyAvailableMessage(); } catch (InterruptedException ie) { mTrucking = false; } catch (IOException ioe) { System.out.println("MessageReader.run(): " + ioe.toString()); } } } // Public API. public boolean hasMore() { return mMessages.size() > 0; } public synchronized Message next() { Message m = (Message)mMessages.elementAt(0); mMessages.removeElementAt(0); return m; } }
If you don't have real devices for testing, you can use the Sun Java Wireless Toolkit to simulate a message network. If you launch more than one emulator, you can send messages between emulators. You can also use the WMA Console, available from File > Utilities, to send and receive messages.
With my Motorola V3, I was able to send a message to myself, and the message was sent and received by HermesMIDlet. However, when I tried to exchange messages between the V3 and my Nokia 6030 (on different wireless networks), the messages were successfully sent but ended up in the recipient's default message box rather than being retrieved by HermesMIDlet. The destination port number was lost in transit.