Asynchronous Communications with Java ME and SIP: Part I

By Bruce Hopkins

This tech tip teaches developers how to use the JSR 180 APIs to communicate asynchronously using the SIP protocol.

Your mobile application needs to receive information from a server or from another mobile user via a server. Everything works fine when the communication between the mobile device and the server are synchronous. All you need to do is open a connection to send a request, and the server uses that same connection to return a response to you.

The HTTP protocol is great for synchronous transactions, which happens billions of times a day when people access websites and web services all over the world. However, things get tricky when a web server needs to contact your web browser when the connection no longer exists. Since this is tax season for those of us in North America, consider the following concept. If you used a web application to submit your taxes, how did you get the response to inform you that your tax filing was accepted or rejected? You either got your response over an asynchronous protocol (like SMTP, also known as email) or a polling mechanism had to be employed over a synchronous protocol (like HTTP) to check the status of the tax application.

This is the classic problem: If your mobile application needs to receive a notification of some event, you either need to poll using a synchronous protocol or use an asynchronous protocol. If you have used Java ME for any significant amount of time, then you are already aware that every Java ME device has supported the HTTP protocol since MIDP 1.0. So, the purpose of this tech tip is to get developers up to use the JSR 180 APIs to communicate asynchronously using the SIP protocol. Fortunately, JSR 180 is a part of the MSA standard, so more and more mobile devices are supporting this API.

In the following sample code, I show two MIDlets that will use the SIP protocol and the JSR 180 API to communicate asynchronously (and without needing a SIP server/proxy between them). However, before getting started, I need to list all the materials that required for you to run this example:

Yup, you don’t even need two computers to run the sender and the receiver applications. Both examples can be run from the same computer at the same time.

SipReceiver.java MIDlet

I’m going to assume that you’ve already had some experience creating a MIDlet before, so I’m not going to much detail on the MIDlet lifecycle or the constructor. There are several tutorials available where you can get up to speed on Java ME basics if you need to: Learning Path: MIDlet Life Cycle, Wireless Development Tutorial, Part I, or Introduction to Mobility Java Technology. However, let’s take a look the first lines of code:

import javax.microedition.sip.\*;

public class SipReceiver extends MIDlet implements CommandListener{

	public Display display;
	public long startTime;
	public Form form;
	public TextField portTextField;
	public ImageItem userImageItem;
	public Image userImage;
	public Command startCommand;
	public Command exitCommand ;
	public SipConnectionNotifier scn = null;
	public SipServerConnection ssc = null;

The SipServerConnection class is the class that binds to a port and listens for a incoming request. For all this to work, the SipServerConnection works hand-in-hand with a SipConnectionNotifier. The SipConnectionNotifier is an interface that you need to implement so that you can be notified when a SIP request has been received by your MIDlet. As you can see from the class declaration, I didn’t implement the SipConnectionNotifier interface, because I prefer to have an inner class to handle all my I/O. The following code snippet shows the details of my inner class, DataTransfer.

   class DataTransfer extends Thread implements SipServerConnectionListener {

      public void run(){

         try {
            if(scn != null)
               scn.close();
            scn = (SipConnectionNotifier) Connector.open("sip:" + portTextField.getString());
            scn.setListener(this);
            form.append("Listening to port: " + scn.getLocalPort());
         } catch(Exception ex) {
            ex.printStackTrace();
         }
      }

      public void notifyRequest(SipConnectionNotifier scn) {
         try {
            ssc = scn.acceptAndOpen();
            if(ssc.getMethod().equals("MESSAGE")) {
               String contentType = ssc.getHeader("Content-Type");
               String contentLength = ssc.getHeader("Content-Length");
               int length = Integer.parseInt(contentLength);
               if((contentType != null) && contentType.equals("text/plain")) {
                  InputStream is = ssc.openContentInputStream();
                  int i=0;
                  byte testBuffer[] = new byte[length];
                  i = is.read(testBuffer);

                  String message = new String(testBuffer, 0, i);

                  form.append(new StringItem("Subject:", ssc.getHeader("Subject")));
                  form.append(new StringItem("Message:", message));
               }
               ssc.initResponse(200);
               ssc.send();
                }
       
         } catch(IOException ex) {
            form.append("Exception: "+ex.getMessage());
         }
      }
   }

You should notice two obvious things:

  • My inner class extends Thread, because all blocking I/O operations need to operate in a separate thread.
  • My inner class implements SipConnectionNotifier, which was explained earlier. Now that my class implements the SipConnectionNotifier, its notifyRequest() will be called when a new request comes in.

Now that you’ve seen the bulk of the work required to receive a SIP message, let’s take a look at the code required to send a message.

SipSender.java MIDlet

As in the previous example, I’m going to let an inner class do all my heavy lifting, so let's dive right in the inner class code to see what’s going on.

   class DataTransfer extends Thread implements SipClientConnectionListener{

      public void run() {
         SipClientConnection sc = null;
         try {
            sc = (SipClientConnection) Connector.open(addressTextField.getString());
            sc.setListener(this);
            String message = messageTextField.getString();
            sc.initRequest("MESSAGE", null);
            sc.setHeader("From", addressTextField.getString());
            sc.setHeader("Subject", subjectTextField.getString());
            sc.setHeader("Content-Type", "text/plain");
            sc.setHeader("Content-Length", "" + message.length());
            OutputStream os = sc.openContentOutputStream();
            os.write(message.getBytes());
            os.close(); 
       
         } catch(Exception e) {
            e.printStackTrace();
         }
      }

      public void notifyResponse(SipClientConnection scc) {
         try {
            scc.receive(1);
            form.append("notifyResponse: "+scc.getStatusCode()+" "+scc.getReasonPhrase());
            scc.close();
         } catch(Exception e) {
            form.append(e.getMessage());
         }
      }
   }

Once again, there are few things that I want to point out:

  • The inner class extends Thread for performance reasons, and you don’t want the entire application to hang when I/O requests are generated.
  • We need to implement the interface SipClientConnectionListener, which forces us to implement the callback method notifyResponse(). The allows us to check the status code of our message. The SIP status code is very similar to HTTP, so a 200 status means that your request was successfully received and understood.

The following images show the both applications running, using the Sun Wireless Toolkit.

SIP Sender Receiver

Conclusion

As you can see, it doesn’t take a lot of effort to the JSR 180 API to send and receive messages using the SIP protocol. The great thing about SIP is that its response codes are modeled after the HTTP protocol, so most of you should feel very comfortable using the protocol. In Part 2, we’ll take a deeper look into the SIP protocol, and find out the benefits of using a Registrar or a Proxy.


Source Code

Following is the full source code for SipReceiver.java and SipSender.java.

Comments:

Nice and simple article, can't wait till next article. Maybe some more information about sending other data through SIP. Like RTP packages or SDP information?

Posted by JRikhof on April 22, 2008 at 12:53 AM PDT #

Thanks,

As you noticed in this article, I didn't get into the details of all the SIP methods, because learning SIP can be a little daunting. More to come soon!

Bruce

Posted by Bruce Hopkins on April 23, 2008 at 12:02 AM PDT #

Hi,

Nice article.

Have you tested the sip receiver code on a real phone? I have got problem in opening the listening connection by specifying a specific port number and I am not able to listen to incoming SIP message. It works fine when i use an emulator but not on the real phone. Any idea?

Thanks.

Posted by slng on April 24, 2008 at 04:21 PM PDT #

Your device should prompt you before it tries to open a server connection. You probably need to modify your had file to specify that.

Posted by bruce hopkins on April 25, 2008 at 03:32 PM PDT #

Sorry, I meant "jad" file

Posted by bruce on April 25, 2008 at 03:37 PM PDT #

How can I download Java ME to my nokia N95?

Posted by guest on April 29, 2008 at 06:16 AM PDT #

This is my email addres, please help. Thx! apollo5@op.pl

Posted by guest on April 29, 2008 at 06:21 AM PDT #

}
ssc.initResponse(200);
ssc.send();
}
intersting method !
i would prefer a different technique like this:\\

}
ssc.initResponse(250);
ssc.send();
}

Posted by טיסות on May 01, 2008 at 10:21 PM PDT #

Apollo5,

The JVM that interprets Java ME bytecode is already on the Nokia N95 handset, so you don't need to download the Java ME interpreter (if that's what you're asking). Now, there are several ways to download Java ME applications to Nokia Series 60 handsets (and yes the N95 is a Series 60 handset). The easiest way to do so if you have a Bluetooth enabled PC is to transfer the Java ME application (it will be a JAR file) to the phone using Bluetooth file transfer. On Windows, this is a drag-and-drop operation. The phone will accept the file, and prompt you on what to do next.

Posted by Bruce Hopkins on May 04, 2008 at 11:30 PM PDT #

Dear טיסות,

Hmm, that very interesting. What does the response code of "250" mean? Here's a list of valid SIP response codes from Wikipedia:

http://en.wikipedia.org/wiki/SIP_Responses

Thanks,

Bruce

Posted by Bruce Hopkins on May 04, 2008 at 11:37 PM PDT #

I have a few questions, little off topic but while reading a few ideas popped into my head.
With the UDP protocol, alot of people say its faster the TCP, is it just the connection for TCP that makes it slower, and is the difference even noticable?
Also is there a big difference in time while you are actually sending data?

The other question was with TCP connections, is there any benefit from having 2 connections open? one of them for transmitting and the other for receiving.
Sorry a little off topic, think it does come under Asynchronous Communications in ways.

Thanks

Posted by orly on May 05, 2008 at 04:23 AM PDT #

Orly,

Great questions. Let's start with the first one. Regarding the speed of TCP vs. UDP, I have no idea of which transport is faster or slower. I do know that TCP connections are guaranteed in a transaction, so you'll get a success or failure when you're sending data. UDP datagrams are not guaranteed, so your message may never be delivered, or your receiver may receive the same datagram more than once. UDP also as a size limitation, which TCP does not impose.

Second question. When running these applications in the WTK 2.5 emulator, the data transfer was almost instantaneous.

Third question. Separating the code for sending and receiving data makes things easier to follow (in my opinion).

FYI. SIP can be transported over UDP and TCP connections. In my testing, I noticed that the Sun Wireless Toolkit used UDP exclusively.

Thanks,

Bruce

Posted by Bruce Hopkins on May 05, 2008 at 09:56 PM PDT #

Orly,

To expand on Bruce's comment.

UDP is a connectionless IP protocol that transmits units called datagrams. There is no guarantee of datagram delivery. Additionally, the datagram transmission order may not be the same as datagram reception order. TCP is a connection oriented IP protocol and implements the concept of an ordered, byte-stream between end-points called sockets. All of the "machinery" to support data transport, acknowledgements, re-transmission, sending and receiving windows, etc is part of the protocol. Both TCP and UDP are bi-directional and full-duplex, i.e. the same socket can be used for both reading and writing and reading and writing can be taking place concurrently.

By way of example, the early versions of the NFS protocol which was part of the Solaris kernel were written using UDP, implementing it's own "machinery" for reliable data transactions. Eventually the UDP version of NFS was replaced by a TCP implementation 1) to take advantage of the highly refined TCP "machinery", 2) reduce the size of the kernel, 3) eliminate a source of bugs.

As to your question about time efficiency of either protocol - that may not be important, the choice should be based on the application's requirements. If a byte-stream is required the choices are: TCP or UDP + "machinery" with the application providing the "machinery".

Instantiating either type of end-point socket (TCP or UDP) likely takes approximately the same amount of time. From a performance and resources perspective it is better to avoid continual socket creation / destruction sequences in the application. The actual time to transmit data is dependent on a large number of variables ranging from the handset software and hardware to the carrier's network, geographic and atmospheric conditions.

I agree with Bruce about separating sender and receiver implementations but would share the socket to avoid the resource consumption.

As far as JSR 248 MSA goes TCP client sockets are mandatory, TCP server sockets are optional as is UDP (see MSA A.2.1).

Rick

Posted by Rick Marejka on May 27, 2008 at 01:19 AM PDT #

Post a Comment:
  • HTML Syntax: NOT allowed
About

Tips for developers who use Java technologies (Java SE, Java ME, JavaFX) for mobile and embedded devices.

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today