Peer-to-peer (P2P) instant messaging (IM) has became one of the killer applications of our age. Millions of users use instant messaging applications from America Online, Yahoo, and Microsoft every day, and their ISPs use the ownership of those IM networks as the basis for their premier monthly subscription fees. In the corporate world, instant messaging applications have also become increasingly important: As of this writing, IBM and Microsoft have 230,000 and 50,000 corporate IM users, respectively.
Because most people consider their wireless devices to be personal accessories, IM applications are perfectly suited for mobile commerce. In this two-part series, I will introduce you to the tools that enable P2P messaging in the mobile world. In this first installment, we'll discuss Java SMS tools and applications. Material in this article will also appear in my upcoming book, Java Mobile Enterprise Application Development (see Resources for a link).
Mobile phone network infrastructures provide standard ways to pass text messages between phones. The most well-known mobile phone messaging protocols include SMS (Short Message Service) and CBS (Cell Broadcast Short Message Service), both of which work on both GSM and CDMA networks. SMS has become a major source of income for wireless operators; in Europe, SMS services already account for 40% of mobile phone carriers' profits. However, because not all J2ME devices are SMS compatible, the standard J2ME API does not provide a way to access an underlying device's SMS features.
The J2ME Wireless Messaging API (WMA) specifies a standard set of APIs that J2ME applications running on SMS-enabled devices can use to communicate with network peers via the SMS and CBS protocols. The WMA can be implemented on both the CLDC platform (Connected Limited Device Configuration, for mobile phones and low-end PDAs) and the CDC platform (Connected Device Configuration, for high-end PDAs).
One very important feature of the WMA is that it allows J2ME devices to run SMS-based server applications. You would use an SMS server to automatically process and respond to incoming messages in your J2ME application. Unlike traditional HTTP servers, SMS servers do not rely on the IP network. Server addresses are identified by telephone numbers.
The WMA specification has been developed by the Java Community Process (JCP) under JSR 120. It is supported by such major phone vendors as Motorola, Siemens, and Nokia, as well as such major mobile network operators as SprintPCS, Cingular, and France Telecom.
Since SMS is much more popular than CBS, we will focus on SMS messaging here. I will first introduce you to the general concepts of the API and
its usage. Then, I will discuss WMA implementations, in particular the
reference implementation that works on PC-based wireless device emulators. Using the reference
implementation, I will show you how to implement and run a sample peer-to-peer SMS
messaging application called WMATester. (You can download the complete code for this application from the Resources section below.)
Application developers can access WMA features through three top-level
interfaces in the javax.wireless.messaging package:
- The
Messageinterface defines the structure of a message. TheTextMessageandBinaryMessageinterfaces are derived fromMessageand provide more specific message structures. - The
MessageConnectioninterface represents a network connection for messages. It defines basic methods for sending and receiving messages. For example, theMessageConnection.newMessage()method returnsMessageinstances for outgoing messages; theMessageConnection.receive()method captures incoming messages. - The
MessageListenerinterface has only one method:notifyIncomingMessage(). AMessageListenerinstance is registered with a serverMessageConnection. ItsnotifyIncomingMessage()method is called when there is an inbound message. The specification requires that thenotifyIncomingMessage()return quickly. Thus, it is not recommended that you process the inbound message within this method.
Figure 1 contains a UML diagram for these interfaces.
Figure 1. Top-level WMA interfaces in the javax.wireless.messaging package

The Java General Connection Framework (GCF) connector class javax.microedition.io.Connector instantiates instances of
MessageConnection. The URL that is passed to the
Connector.open() method determines the connection
that will be opened. The following URL patterns and message connection types
are supported by the WMA:
- The URL
sms://+18005555555specifies a connection to send SMS messages to the phone number 1-800-555-5555. (Note that the WMA has no phone number format requirements; you can use any series of digits that your phone and network will recognize.) - The URL
sms://+18005555555:1234specifies a connection to send SMS messages to port number 1234 at the phone number 1-800-555-5555. - The URL
sms://:1234specifies a server connection to receive messages on port 1234. A server connection can also send messages. - The URL
cbs://:3382specifies a connection that listens for inbound CBS messages on port 3382. Unlike a SMS server connection, this CBS connection cannot send out any message.
Now that we understand the basics of the WMA, let's take a look at some concrete code examples.
Sending messages with the WMA is very simple. You can send a message to an arbitrary
phone number and/or an SMS port through a MessageConnection constructed
for that destination, as shown in Listing 1.
Listing 1. Sending an SMS message
String addr = "sms://+123456789";
// Or: String addr = "sms://+123456789:1234";
MessageConnection conn =
(MessageConnection) Connector.open(addr);
TextMessage msg =
(TextMessage) conn.newMessage(
MessageConnection.TEXT_MESSAGE);
msg.setPayloadText( "Hello World" );
conn.send(msg);
|
We can also send out messages through a server connection, as shown in Listing 2.
Listing 2. Sending an SMS message via a server connection
MessageConnection sconn = (MessageConnection)
Connector.open("sms://:3333");
TextMessage msg =
(TextMessage) sconn.newMessage(
MessageConnection.TEXT_MESSAGE);
msg.setAddress("sms://+123456789:1234");
msg.setPayloadText( "Hello World" );
sconn.send(msg);
|
If you choose to use a server connection to send your message, you gain a number of benefits:
- The connection can be reused again and again.
- The message contains the sender's port number and phone number. Hence, it gives the recipient peer the opportunity to respond.
To receive SMS messages in a Java application, we need to have a server
MessageConnection listening at the message's target
port. The MessageConnection.receive() method blocks
until a message is received or the connection is closed. We can loop the receive() method to automatically handle incoming messages
when they arrive. Listing 3 illustrates a server loop
that listens, receives, and replies to incoming SMS messages.
Listing 3. Receiving an SMS message and replying to it
MessageConnection sconn = (MessageConnection)
Connector.open("sms://:3333");
while (true) {
Message msg = sconn.receive();
if (msg instanceof TextMessage) {
TextMessage tmsg = (TextMessage) msg;
String msgText = tmsg.getPayloadText();
// Construct the return message
TextMessage rmsg =
(TextMessage) sconn.newMessage(
MessageConnection.TEXT_MESSAGE);
rmsg.setAddress ( tmsg.getAddress() );
rmsg.setPayloadText( "Thanks!" );
sconn.send(rmsg);
} else {
// process the non-text message
// maybe a BinaryMessage?
}
}
|
In the real world, such a server loop would run in a separate background thread to avoid
blocking the user interface. To see how that would work, please refer to our sample application,
WMATester.
The WMA reference implementation
An SMS wireless messaging client depends on the underlying device and mobile network infrastructure to send and receive messages. Thus, each implementation of the WMA is device- and network-dependent. Sun has come up with a WMA reference implementation (RI) for PC emulators so that you can develop WMA applications independent of any actual phone or live network. Currently, the WMA RI works with the MIDP (Mobile Information Device Profile) emulator. MIDP is a J2ME platform that targets mobile phone devices. WMA implementations for other J2ME platforms (such as PersonalJava, CDC) will come soon.
The RI provides a transport mechanism that emulates SMS over the host PC's TCP/IP ports. All SMS messages are routed as datagram messages to host ports specified by the RI's runtime properties. The properties can be specified in an internal config file or from the command line. For convenience, we will use the command-line properties in Listing 4 for our examples.
Listing 4. Specifying the reference implementation's runtime properties
emulator -classpath MyApp.jar \
-Xdescriptor:MyApp.jad \
-Dcom.sun.midp.io.enable_extra_protocols=true \
-Dcom.sun.midp.io.j2me.sms.Impl=
com.sun.midp.io.j2me.sms.DatagramImpl \
-Dcom.sun.midp.io.j2me.sms.DatagramHost=localhost \
-Dcom.sun.midp.io.j2me.sms.DatagramPortIn=54321 \
-Dcom.sun.midp.io.j2me.sms.DatagramPortOut=12345 \
-Dcom.sun.midp.io.j2me.sms.permission.receive=true \
-Dcom.sun.midp.io.j2me.sms.permission.send=true \
-Dcom.sun.midp.io.j2me.cbs.permission.receive=true \
-Djavax.microedition.io.Connector.sms=true \
-Djavax.microedition.io.Connector.cbs=true \
-Dcom.sun.midp.io.j2me.sms.CBSPort=24680 \
-Dwireless.messaging.sms.smsc=+17815511212
|
Of course, the command in Listing 4 assumes that the WMA RI classes are already
preverified and packed in MyApp.jar. Let's examine each parameter in the listing in detail:
com.sun.midp.io.enable_extra_protocolsenables the datagram protocol. It is needed for the MIDP 1.0 RI, which by default only allows HTTP GCF connections.com.sun.midp.io.j2me.sms.Impldesignates a class that supplies the low-level network transport for SMS messages in the WMA RI.- The
com.sun.midp.io.j2me.sms.Datagram*parameters specify the host and datagram ports to emulate SMS. In Listing 4, all outgoing SMS messages regardless of destination phone numbers are sent tolocalhost's 12345 datagram port. All messages received from port 54321 will be captured by the WMA RI as incoming SMS messages. - The
com.sun.midp.io.j2me.sms.permission.*andjavax.microedition.io.Connector.*parameters specify the default permission to access SMS and CBS resources. Those properties are used by the MIDP 2.0 security manager. For more information on required permissions, please refer to the WMA Recommended Practices guide (see Resources). com.sun.midp.io.j2me.sms.CBSPortspecifies the SMS port on which to receive CBS messages.wireless.messaging.sms.smscspecifies an SMS service center phone number. In the PC emulator, this property is irrelevant.
The WMA RI sports a multiple-layer architecture, illustrated in Figure 2. It is relatively straightforward to port the RI to use proprietary SMS stacks on real devices. The low-level transport layer is just a thin wrapper of Java native methods over device-native SMS libraries. The implementation classes layer aggregates those native methods into concrete implementation classes for WMA interfaces. For a detailed discussion on the architecture and port guide of the WMA RI, please read its accompanying documentation.
Figure 2. WMA Reference Implementation architecture

Our
example application, WMATester, demonstrates how to
use the WMA and how to run the WMA RI on a MIDP emulator. WMATester runs a server thread, SMSServer, which listens on an SMS port specified by the
JAD attribute serverPort. The run1 and run2 tasks in the Ant
build.xml script (part of which is shown in Listing
5) run two peers on the same PC emulator.
Listing 5. Snippet of build.xml
<target name="run1" depends="init" >
<exec executable="${WTK_path}/bin/emulator">
<arg value="-classpath ${bindir}/${projname}.jar" />
<arg value="-Xdescriptor:${bindir}/${projname}01.jad" />
<arg value="-Dcom.sun.midp.io.enable_extra_protocols=true" />
<arg
value="-Dcom.sun.midp.io.j2me.sms.Impl=com.sun.midp.io.j2me.sms.DatagramImpl" />
<arg value="-Dcom.sun.midp.io.j2me.sms.DatagramHost=localhost" />
<arg value="-Dcom.sun.midp.io.j2me.sms.DatagramPortIn=54321" />
<arg value="-Dcom.sun.midp.io.j2me.sms.DatagramPortOut=12345" />
<arg value="-Dcom.sun.midp.io.j2me.sms.permission.receive=true" />
<arg value="-Dcom.sun.midp.io.j2me.sms.permission.send=true" />
<arg value="-Djavax.microedition.io.Connector.sms=true" />
</exec>
</target>
<target name="run2" depends="init" >
<exec executable="${WTK_path}/bin/emulator">
<arg value="-classpath ${bindir}/${projname}.jar" />
<arg value="-Xdescriptor:${bindir}/${projname}02.jad" />
<arg value="-Dcom.sun.midp.io.enable_extra_protocols=true" />
<arg
value="-Dcom.sun.midp.io.j2me.sms.Impl=com.sun.midp.io.j2me.sms.DatagramImpl" />
<arg value="-Dcom.sun.midp.io.j2me.sms.DatagramHost=localhost" />
<arg value="-Dcom.sun.midp.io.j2me.sms.DatagramPortIn=12345" />
<arg value="-Dcom.sun.midp.io.j2me.sms.DatagramPortOut=54321" />
<arg value="-Dcom.sun.midp.io.j2me.sms.permission.receive=true" />
<arg value="-Dcom.sun.midp.io.j2me.sms.permission.send=true" />
<arg value="-Djavax.microedition.io.Connector.sms=true" />
</exec>
</target>
|
The task run1 runs WMATester01.jad (peer 1; see Listing 6). This peer listens on SMS port 3333
(as established by the JAD serverPort attribute). Its underlying PC
emulator receives SMS messages from datagram port 54321 and sends out SMS
messages through datagram port 12345.
Listing 6. WMATester01.jad
Manifest-Version: 1.0 MIDlet-1: WMATester, ,com.enterprisej2me.WMATester.WMATester MIDlet-Name: WMATester MIDlet-Version: 1.0 MIDlet-Data-Size: 256 MIDlet-Description: WMA Tester program MIDlet-Jar-Size: 31684 MIDlet-Jar-URL: WMATester.jar Created-By: 1.3.0 (Sun Microsystems Inc.) MIDlet-Vendor: Sun Microsystems, Inc. MicroEdition-Configuration: CLDC-1.0 MicroEdition-Profile: MIDP-1.0 serverPort: 3333 |
The task run2 runs WMATester02.jad (peer 2; see Listing 7). It listens on SMS port 3334. Its
underlying PC emulator receives SMS messages from datagram port 12345 and sends
out SMS messages through datagram port 54321.
Listing 7. WMATester02.jad
Manifest-Version: 1.0 MIDlet-1: WMATester, ,com.enterprisej2me.WMATester.WMATester MIDlet-Name: WMATester MIDlet-Version: 1.0 MIDlet-Data-Size: 256 MIDlet-Description: WMA Tester program MIDlet-Jar-Size: 31684 MIDlet-Jar-URL: WMATester.jar Created-By: 1.3.0 (Sun Microsystems Inc.) MIDlet-Vendor: Sun Microsystems, Inc. MicroEdition-Configuration: CLDC-1.0 MicroEdition-Profile: MIDP-1.0 serverPort: 3334 |
So, all the messages sent out by peer 1 are captured by peer 2, and vice
versa. Each peer has two send command buttons: SEND1 sends out a message using a new client MessageConnection; SEND2 sends
out a message using a server MessageConnection.
Once a message is received by the SMSServer
thread, the server MessageConnection sends back an
acknowledgment. The SMSServer then displays an Alert box. To see WMATester in action, take a look at Figure 3.
Figure 3. The WMATester application in action

The complete source code of WMATester is included in Listing 8.
Listing 8. WMATester.java
package com.enterprisej2me.WMATester;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.rms.*;
import javax.microedition.io.*;
import javax.wireless.messaging.*;
public class WMATester extends MIDlet
implements CommandListener {
private Display display;
private TextField textMesg;
private TextField dest;
private Command doneCommand;
private Command send1Command;
private Command send2Command;
private String serverPort;
private boolean done;
private MessageConnection sconn;
public WMATester () throws Exception {
display = Display.getDisplay(this);
doneCommand = new Command("DONE",
Command.SCREEN, 1);
send1Command = new Command("SEND1",
Command.SCREEN, 1);
send2Command = new Command("SEND2",
Command.SCREEN, 1);
serverPort = getAppProperty("serverPort");
}
public void startApp() {
try {
displayBlankForm ();
sconn = (MessageConnection)
Connector.open("sms://:" + serverPort);
done = false;
new Thread(new SMSServer()).start();
} catch (Exception e) {
System.out.print("Error in start");
e.printStackTrace();
}
}
public void pauseApp() {
done = true;
try {
sconn.close();
} catch (Exception e) {
System.out.print("Error in pause");
e.printStackTrace();
}
}
public void destroyApp(boolean unconditional) {
done = true;
try {
sconn.close();
} catch (Exception e) {
System.out.print("Error in pause");
e.printStackTrace();
}
}
// There are some potentially blocking I/O
// operations in this callback function.
// In real world applications, you probably
// want to move them to a separate thread.
public void commandAction(Command command,
Displayable screen) {
if (command == doneCommand) {
destroyApp(false);
notifyDestroyed();
} else if (command == send1Command) {
try {
String addr = "sms://+" + dest.getString();
MessageConnection conn =
(MessageConnection) Connector.open(addr);
TextMessage msg =
(TextMessage) conn.newMessage(
MessageConnection.TEXT_MESSAGE);
msg.setPayloadText( textMesg.getString() );
conn.send(msg);
conn.close();
displayBlankForm ();
} catch (Exception e) {
System.out.println("Error in sending");
e.printStackTrace ();
}
} else if (command == send2Command) {
try {
String addr = "sms://+" + dest.getString();
TextMessage msg =
(TextMessage) sconn.newMessage(
MessageConnection.TEXT_MESSAGE);
msg.setAddress ( addr );
msg.setPayloadText( textMesg.getString() );
sconn.send(msg);
displayBlankForm ();
} catch (Exception e) {
System.out.println("Error in sending");
e.printStackTrace ();
}
}
}
private void displayBlankForm () throws Exception {
Form form = new Form ("WMATester");
textMesg = new TextField("Message", "",
100, TextField.ANY);
dest = new TextField("Phone No.", "",
20, TextField.ANY);
form.append( dest );
form.append( textMesg );
form.addCommand(doneCommand);
form.addCommand(send1Command);
form.addCommand(send2Command);
form.setCommandListener(
(CommandListener) this);
display.setCurrent(form);
}
class SMSServer implements Runnable {
public void run () {
try {
while (!done) {
Message msg = sconn.receive();
if (msg instanceof TextMessage) {
TextMessage tmsg = (TextMessage) msg;
String msgText = tmsg.getPayloadText();
// Construct the return message
TextMessage rmsg =
(TextMessage) sconn.newMessage(
MessageConnection.TEXT_MESSAGE);
rmsg.setAddress ( tmsg.getAddress() );
rmsg.setPayloadText( "Message " +
msgText +
" is received" );
sconn.send(rmsg);
Alert alert = new Alert ("Received", msgText,
null, AlertType.ERROR);
alert.setTimeout(Alert.FOREVER);
display.setCurrent( alert );
} else {
throw new Exception("Received is not a text mesg");
}
}
} catch (Exception e) {
System.out.println("Error in server receiving");
e.printStackTrace ();
}
}
}
}
|
SMS beyond the Wireless Messaging API
The WMA enables mobile Java peers to communicate with each other via SMS. SMS is also often used to deliver enterprise information from back-end servers to mobile users. For example, a stock monitoring server could send price alerts to mobile subscribers. To handle SMS on server computers, we could develop a J2SE/J2EE WMA implementation that uses a modem or TCP/IP connection to interact with a wireless carrier's SMS Center (SMSC). In fact, JSR 197, "Generic Connection Framework Optional Package for J2SE," is working on a GCF implementation for J2SE, and hence will allow the WMA to be ported to Java platforms beyond J2ME.
But such an enterprise server-compatible WMA implementation is not available today. In the following sections, I will briefly introduce you to two Java SMS tools that are already available for enterprise markets.
Object XP's jSMS package provides an easy-to-use Java SMS
API. It runs on a J2SE computer (that is, a standard PC). In order for the PC to send and
receive any SMS message, it has to be connected to a general mobile phone network using
one of the two following techniques:
- The PC can connect to a GSM phone via a serial port.
jSMSpasses outgoing SMS messages to the phone, and the phone sends them out. When a new SMS message comes in, the phone sends a signal through the serial port and a monitoringjSMSserver thread receives the message. This mode allows you to quickly incorporate SMS functionality into back-end applications. - If you have an account with an SMSC, the
jSMSapplication running on your PC can connect to that SMSC via a modem, an ISDN line, or a TCP/IP connection. This mode is designed to handle large numbers of messages.
Using the jSMS API is very simple, as illustrated in Listing 9.
Listing 9. The jSMS API in action
SmsService service = new GsmSmsService();
service.init();
// Create a new SMS Message
SmsMessage msg = new SmsMessage(service);
// Set recipient and message
msg.setRecipient("18885555555");
msg.setMessage("Stock ABC drops below XYZ");
msg.requestStatusReport(true);
// Send the SMS
service.sendMessage(msg);
|
For more information on jSMS, see the Resources section below.
Simplewire is a leading wireless messaging solution provider. The Simplewire Wireless Messaging Protocol Server relays messages between your server application and wireless networks. Those servers provide such enterprise features as logging, monitoring, and caching. They are also highly extensible.
You can purchase and run your own messaging protocol servers. But most users can simply use the servers from Simplewire's Wireless Messaging Network, which have access to carriers of over 300 networks in 118 countries. The Wireless Messaging Network charges a usage fee that varies based on SMS message volumes.
Simplewire's client SDK contains the necessary library and interfaces to interact with its messaging protocol servers. The SDK is available on multiple programming platforms, including Java. Sending SMS messages through the Java API is very simple, as shown in Listing 10.
Listing 10. Sending SMS messages via Simplewire
SMS sms = new SMS();
// Pin is phone number
sms.setMsgPin("+18885555555");
sms.setMsgFrom("StockServ");
sms.setMsgCallback("+18886666666");
sms.setMsgText("Stock ABC drops below XYZ");
// Send Message
sms.msgSend();
|
For complete API documentation and more code examples, please refer to Simplewire's Web site (see Resources).
In this article, you have learned about Java tools for SMS messaging. The WMA is particularly important, because with it you can now seamlessly integrate SMS into your J2ME client applications. This opens a whole new world of opportunities for J2ME game, enterprise, and consumer commerce developers.
In the next installment of this series, I will discuss more powerful, but less ubiquitous, mobile P2P frameworks, such as JXTA ME and Jabber, which support general P2P features beyond simple text messaging. These non-SMS solutions are of particular interest to enterprise mobile users who use WLAN or Wi-Fi networks.
I would like to thank Gary Adams for his review of and valuable suggestions on the organization of the article.
| Name | Size | Download method |
|---|---|---|
| wi-p2pmsg/WMATester.zip | 152 KB | HTTP |
Information about download methods
-
Download this article's sample application, WMATester.
- JSR 120 is the Java community project that is developing Wireless Messaging API specifications.
-
Download the latest WMA specification, reference implementation, documentation, and recommended practices from Sun's WMA site.
-
John Muchow's developerWorks tutorial, "The MIDlets advantage" (March 2002) introduces you to MIDP programming.
Michael J. Yuan is a PhD candidate at the University of Texas at Austin. He is the author of an upcoming Prentice Hall book, Java Mobile Enterprise Application Development. You can contact him at juntao@mail.utexas.edu.