An Introduction to the JAIN SIP API
by Emmanuel Proulx
10/17/2007
Abstract
This article shows how to develop client-side applications using the Session Initiation Protocol (SIP) on Java SE. It presents the JAIN SIP API, a powerful "SIP stack." A simple IM application is shown and then dissected to explore this technology.
About JAIN SIP API
The Java APIs for Integrated Networks (JAIN) is a JCP work group managing telecommunication standards. Session Initiation Protocol (SIP) is a standard communication protocol, discussed in a previous article. Put Java and SIP together and you get the JAIN SIP API, a standard and powerful API for telecommunications. This idea started in 1999 with JSR 32. The reference implementation is open source, very stable, and very widely used. If you're writing a SIP application with Java, using this SIP stack makes perfect sense.
This API is typically used for client-side application development. Other container-based technologies, like SIP Servlet API (see BEA WebLogic SIP Server for example), are better suited for server-side development. A previous article focuses on the SIP Servlet API. Now we're going to turn to the client API stack.
Prerequisites
This article requires a good understanding of Java. Also, I suggest you familiarize yourself with SIP, as using the JAIN SIP API requires a good understanding of this protocol. SIP signaling, especially messages and headers, is particularly important. See the References section at the end of the article for links to relevant information.
Libraries
To get the JAIN SIP API libraries, go to the jain-sip project home page. Click the link to go to the download page. You'll need to get these files:
JainSipApi1.2.jar
: SIP interfaces and main classesJainSipRi1.2.jar
: SIP reference implementationlog4j-1.2.8.jar
(Available inside the filejain-sip-1.2.jar
under the folderjain-sip/lib
): Logging serviceconcurrent.jar
(Available inside the filejain-sip-1.2.jar
under the folderjain-sip/lib
): Concurrency utilities
Other files are not needed in this example. Include these libraries in your project.
I suggest you have a look at the first section of the
Appendix for a list of the various classes and interfaces provided in the JAIN SIP API. These classes and interfaces are standard and provided to you free of charge, and soon you will see how to use them as part of our
SipLayer
example class.
The TextClient Sample Application
As an example of a JAIN SIP API program, let's dissect an application that you may be familiar with if you read the article on the topic of SIP Servlets I wrote previously. The TextClient is an instant messaging application that can send and receive text messages over the SIP protocol. One instance of this application can send messages to another instance, but in theory, this client can be used to send messages to other kinds of SIP instant messaging clients, and even SIP server applications. Figure 1 shows a screen capture.
Figure 1. The TextClient returns
To run this application, first you need to download the provided source code. Second, you have to build it using the provided Ant script. This will produce a JAR file. Finally, you run the application, using this command:
java -jar textclient.jar <username> <port>
You can run multiple instances of this client (make sure they use different ports) and send each other messages. The rest of the article explores the code of this sample application.
TextClient Code Overview
A couple of classes and an interface make up the whole TextClient code. This table introduces them:
Class / Interface | Description |
---|---|
TextClient
|
Main class, Swing window that contains the widgets of the application. See Figure 1. |
SipLayer
|
Class that takes care of all the SIP communication. It is instantiated by the
TextClient class, and calls it back through the
MessageProcessor interface.
|
MessageProcessor
|
Callback interface (observer pattern), which serves to decouple the
SipLayer from its container.
|
In the upcoming sections, I'll introduce the
MessageProcessor
and then spend most of the time looking at
SipLayer
. I won't talk about the
TextClient
class at all because it simply contains user interface Swing code and is not relevant to the topic of this article. For more information, please refer to the source code provided with this article.
Message Processor
Before I jump into the
SipLayer
class, I'll briefly cover the
MessageProcessor
interface. To decouple the SIP layer from the GUI layer, you use a callback interface that allows sending information from the former without having to know the signature of the latter. The interface is shown below:
public interface MessageProcessor
{
public void processMessage(String sender, String message);
public void processError(String errorMessage);
public void processInfo(String infoMessage);
}
The
SipLayer
constructor will take an implementation of this interface (that is, the
TextClient
object) as a parameter and will hold on to it. Later you'll be able to use this object to send information back to the GUI.
SIP Stack Preparation
Let's start writing the
SipLayer
class.
TextClient
must be able to receive asynchronous messages coming from other SIP end points. The observer pattern is used for this: The class implements the
SipListener
interface to process incoming messages:
public class SipLayer
implements SipListener {
The methods of this interface are:
void processRequest(RequestEvent evt);
void processResponse(ResponseEvent evt);
void processTimeout(TimeoutEvent evt);
void processIOException(IOExceptionEvent evt);
void processTransactionTerminated(TransactionTerminatedEvent evt);
void processDialogTerminated(DialogTerminatedEvent evt);
In this example, the most important methods evidently are
processRequest()
and
processResponse()
for processing incoming messages. I'll look at those a bit later.
Next are two fields to store objects needed later. These are not directly related to the SIP API, but you'll need them for the example. The first is a
MessageProcessor
object as discussed before. You also need to keep the username handy. These two fields have getters and setters which, for brevity, I'm not showing in this article.
private MessageProcessor messageProcessor;
private String username;
Next is the constructor. A typical way to start a JAIN SIP API application—and TextClient follows this pattern—is to set up a bunch of objects that will be useful later on. I'm talking about a number of factories, and a single SIP stack instance, initialized.
private SipStack sipStack;
private SipFactory sipFactory;
private AddressFactory addressFactory;
private HeaderFactory headerFactory;
private MessageFactory messageFactory;
private SipProvider sipProvider;
public SipLayer(String username, String ip, int port) throws
PeerUnavailableException, TransportNotSupportedException,
InvalidArgumentException, ObjectInUseException,
TooManyListenersException {
setUsername(username);
sipFactory = SipFactory.getInstance();
sipFactory.setPathName("gov.nist");
Properties properties = new Properties();
properties.setProperty("javax.sip.STACK_NAME",
"TextClient");
properties.setProperty("javax.sip.IP_ADDRESS",
ip);
sipStack = sipFactory.createSipStack(properties);
headerFactory = sipFactory.createHeaderFactory();
addressFactory = sipFactory.createAddressFactory();
messageFactory = sipFactory.createMessageFactory();
...
The SIP factory is used to instantiate a
SipStack
implementation, but since there could be more than one implementation, you must name the one you want via the
setPathName()
method. The name "
gov.nist
" denotes the SIP stack you've got.
The
SipStack
object takes in a number of properties. At a minimum, you must set the stack name. All other properties are optional. Here I'm setting an IP address to use by the stack, for cases where a single computer has more than one IP address. Note that there are standard properties, which all SIP API implementations must support, and non-standard ones that are dependent on the implementation. See the References section for links to these properties.
The next step is to create a pair of
ListeningPoint
and
SipProvider
objects. These objects provide the communication functionality of sending and receiving messages. There's one set of these for TCP and one set for UDP. This is also where you select the
SipLayer
(this) as a listener of incoming SIP messages:
...
ListeningPoint tcp = sipStack.createListeningPoint(port, "tcp");
ListeningPoint udp = sipStack.createListeningPoint(port, "udp");
sipProvider = sipStack.createSipProvider(tcp);
sipProvider.addSipListener(this);
sipProvider = sipStack.createSipProvider(udp);
sipProvider.addSipListener(this);
}
And this is how the constructor ends. You've just used the JAIN SIP API to create a
SipStack
instance, a bunch of factories, two
ListeningPoint
s, and a
SipProvider
. These objects will be needed in the upcoming methods to send and receive messages.