The SIP Servlet Tutorial

Chapter 1 Overview of Session Initiation Protocol (SIP) Application Development

This chapter describes the SIP protocol and the background needed for developing SIP applications using the Java programming language.

About the SIP Protocol

The session initiation protocol (SIP) is a simple network signalling protocol for creating and terminating sessions with one or more participant. The SIP protocol is designed to be independent of the underlying transport protocol, so SIP applications can run on TCP, UDP, or other lower-layer networking protocols.

Figure 1–1 The SIP Protocol

Diagram showing the SIP protocol and its relationship
in a networking stack.

Typically, the SIP protocol is used for internet telephony and multimedia distribution between two or more endpoints. For example, one person can initiate a telephone call to another person using SIP, or someone may create a conference call with many participants.

The SIP protocol was designed to be very simple, with a limited set of commands. It is also text-based, so human can read the SIP messages passed between endpoints in a SIP session.

SIP Requests

The SIP protocol defines some common request types:

Table 1–1 Common SIP Requests

SIP Request 

Description 

INVITE

initiate a session between two participants 

ACK

the client acknowledges receiving the final message from an INVITE request

BYE

terminates a connection 

CANCEL

cancels any pending actions, but does not terminate any accepted connections 

OPTIONS

queries the server for a list of capabilities 

REGISTER

registers the address in the To header with the server

SIP requests are codes used to indicate the various stages in a connection between SIP-enabled entities.

See SIP Requests for a list of all SIP requests.

SIP Responses

The SIP Protocol uses response codes similar to the HTTP protocol.

Some common response codes are as follows:

See SIP Responses for more information on SIP responses.

What Are SIP Servlets?

A SIP servlet is a Java programming language server-side component that performs SIP signalling. SIP servlets are managed by a SIP servlet container, which typically are part of a SIP-enabled application server. SIP servlets interact with clients by responding to incoming SIP requests and returning corresponding SIP responses.

SIP servlets are built off the generic servlet API provided by the Java Servlet Specification.

Differences Between HTTP Servlets and SIP Servlets

SIP servlets differ from typical HTTP servlets used in web applications in the following ways:

SIP Servlets and Java EE Components

This section describes how SIP servlets can integrate with other Java EE components in a converged application. A converged application has one or more SIP servlets and one or more Java EE components, such as HTTP servlets, JavaServer Faces applications, enterprise beans, or web services.

Converged applications allow you to integrate SIP functionality into Java EE applications and frameworks. For example, a web application that acts as a front-end to an employee contact information database could be enhanced by allowing users to make a Voice Over Internet Protocol (VOIP) call to the employee for whom the user is searching. Or, an application could route incoming calls to employees based on their schedule in a calendar server.

SIP Servlet Methods

A SIP servlet is a Java programming language class that extends the javax.servlet.sip.SipServlet class, optionally overriding SipServlet's methods. These methods correspond to the SIP protocol's requests, and are named doRequest where Request is a SIP request name. For example, the doRegister method will respond to incoming SIP REGISTER requests. See SIP Requests for a list of all request methods.

SipServlet also defines several response methods: doProvisionalResponse for SIP 100 series responses; doSuccessResponse for SIP 200 series responses; doRedirectResponse for SIP 300 series responses; and doErrorResponse for SIP 400, 500, and 600 series responses. See SIP Responses for more information about SIP responses.

All the response methods in SipServlet are empty, and a typical SIP servlet will override these methods. All the other request methods defined in SipServlet will reject any incoming corresponding SIP requests with a SIP 500 error (server error) response if the request method is not overridden.

SIP Annotations

SIP Servlet 1.1 defines four annotations that may be used in SIP applications. Using these annotations simplifies SIP application development by making the sip.xml deployment descriptor optional. See The sip.xml Deployment Descriptor.

Table 1–2 SIP Annotations

Annotation 

Description 

@SipServlet

Marks the class as a SIP servlet. 

@SipListener

Marks the class as an implementation class of one of the SIP listeners. 

@SipApplication

An application-level class to define a collection of SIP servlets. 

@SipApplicationKey

Associates an incoming request and SIP session with a particular SipApplicationSession.

Using the @SipServlet Annotation

The javax.servlet.sip.annotation.SipServlet class-level annotation is used to mark the class as a SIP servlet.


Example 1–1 Example of the @SipServlet Annotation

@SipServlet
public class MyServlet extends SipServlet {
	...
}

@SipServlet has the following elements:

Table 1–3 @SipServlet Elements

Element 

Description 

applicationName

Explicitly associates the SIP servlet with a particular SIP application. This element is optional. 

description

An optional description of this SIP servlet. 

loadOnStartup

An int value representing the order this SIP servlet should be loaded on application deployment. The default value is -1, meaning the SIP servlet will not load until the container receives a request that the servlet handles. The lower the non-negative integer value in loadOnStartup, the earlier the SIP servlet will be initialized.

name

An optional name for this SIP servlet. 

Using the @SipListener Annotation

The javax.servlet.sip.annotation.SipListener class-level annotation is used to mark the class as an implementation class of one of the SIP event listener interfaces. See SIP Listeners for information on SIP listeners.

Table 1–4 @SipListener Elements

Element 

Description 

applicationName

Explicitly associates the SIP listener with a particular SIP application. This element is optional. 

name

An optional name for this SIP listener. 

Using the @SipApplication Annotation

The javax.servlet.sip.annotation.SipApplication application-level annotation is used to define a collection of SIP servlets and SIP listeners with a common configuration. @SipApplication is annotated at the package level, and all SIP servlets or listeners within the package are part of the defined SIP application unless the SIP servlet or listener explicitly sets the applicationName element in the @SipServlet or @SipListener annotation, respectively.

@SipApplication should be annotated either in a package-info.java file in a package hierarchy, or before the package definition in a particular source file.


Example 1–2 Example of @SipApplication Annotation in a package-info.java File

@SipApplication(name="MySipApplication")
package com.example.sip;

Table 1–5 @SipApplication Elements

Element 

Description 

name

The name of the logical collection of SIP servlets and listeners. This element is required. 

description

Optional description of the SIP application. 

displayName

Optional name for displaying in container administration tools. Defaults to the value of the name element.

distributable

Optional boolean indicating whether the application may be distributed by the container in a clustered environment. The default value is false.

largeIcon

An optional String indicating the location, relative to the root path of the archive, of a large icon for representing this application in container administration tools.

mainServlet

The optional name of the main SIP servlet for this application. 

proxyTimeout

An optional int value indicating the number of whole seconds before a timeout for all proxy operations in this SIP application.

sessionTimeout

An optional int value indicating the number of whole minutes before an application session timeout for all application sessions in this SIP application.

smallIcon

An optional String indicating the location, relative to the root path of the archive, of a small icon for representing this application in container administration tools.

Using the @SipApplicationKey Annotation

The javax.servlet.sip.annotation.SipApplicatonKey method-level annotation associates an incoming request with a particular SIpApplicationSession instance.

The method annotated by @SipApplicationKey must:

The returned String is the key used to associate the request with a SipApplicationSession instance.


Example 1–3 Example of @SipApplicationKey

@SipApplication
package com.example.sip;
...
public class MySipApplication {
	@SipApplicationKey
	public static String sessionKey (SipServletRequest req) {
		return hash(req.getRequestURI() + getDomain(req.getFrom());
	}
}
	

Only one @SipApplicationKey method should be defined for a particular SIP application.

Table 1–6 @SipApplicationKey Elements

Element 

Description 

applicationName

Explicitly associates the SIP application key with a particular SIP application. This element is optional. 

Using SipFactory to Create SIP Servlet Instances

The javax.servlet.sip.SipFactory interface defines several abstractions useful in SIP applications. SIP applications use the container's SipFactory instance to create :

For a full description of SipFactory's methods, see the SIP Servlet 1.1 Javadocs.

Use the javax.annotations.Resource annotation to inject an instance of SipFactory in a class.


Example 1–4 Injecting an Instance of SipFactory into a Class

@Resource
SipFactor sf;

You may also look up the container's SipFactory instance through the servlet context.


Example 1–5 Looking Up SipFactory

SipFactory sf = 
		(SipFactory) getServletContext().getAttribute("javax.servlet.sip.SipFactory");

SIP Sessions

SIP servlets, like HTTP servlets, are stateless, meaning that they do not store data across requests. SIP sessions allow SIP servlets to associate SIP messages with data stored by the SIP container. This allows an application to provide functionality across a number of discreet requests, and associating that series of requests with a single client.

The javax.servlet.sip.SipSession interface is SIP the equivalent of javax.servlet.http.HttpSession interface. Instances of SipSession store SIP session data and associate SIP user-agents so that they may communicate in a multiple-request dialog.

Many SIP applications, however, use multiple protocols (for example, a converged web and SIP application uses both HTTP and SIP sessions), provide functionality across dialogs (for example, a teleconferencing application involving multiple user-agents), or are used in concert with other applications for a single VOIP call. The type of data stored in an instance of SipSession does not cover these complicated use-cases. The javax.servlet.sip.SipApplicationSession interface defines methods for storing protocol information for both SIP and other protocols (for example, HTTP), and storing session data for the entire application. SipApplicationSession instances represent application instances, and the all the data and protocol information needed to provide the functionality in an application.

SipApplicationSession Methods

SipApplicationSession defines a number of methods for managing application sessions and session data.

SipApplicationSession Data Methods

Storing and retrieving session data is accomplished by using the following methods:

Table 1–7 SipApplicationSession Data Methods

Method 

Description 

getAttributes(String id)

Returns the object bound to the specified ID. Returns null if no such object ID exists. 

getAttributeNames()

Returns an Iterator over the String IDs of the objects bound to this application session.

setAttribute(String name, java.lang.Object attribute)

Binds an object to the session using the specified String as the object's ID for later retrieval. 

removeAttribute(String name)

Removes an object from the session by specifying the bound object's ID. 

SipApplicationSession Protocol Methods

Instances of SipApplicationSession typically have multiple protocol sessions contained within the application session. Such protocol sessions are called child sessions. The following table lists the methods defined in SipApplicationSession for managing child sessions:

Table 1–8 Child Session Methods in SipApplicationSession

Method 

Description 

getSessions()

Retrieves an Iterator over all valid child protocol sessions.

getSessions(String protocol)

Retrieves an Iterator over all valid child sessions for a particular protocol. For example, passing SIP to getSessions will return all SIP protocol sessions.

getSipSession(String id)

Retrieves a particular session by its ID. 

getSession(String id, String protocol)

Retrieves a particular session associated with the specified protocol by its ID. 

SipApplicationSession Lifecycle Methods

The following table lists the methods defined in SipApplicationSession for managing the SIP application session lifecycle:

Table 1–9 SipApplicationSession Lifecycle Methods

Method 

Description 

getCreationTime()

Returns the time that the SipApplicationSession instance was created as a long value representing the number of milliseconds since midnight January 1, 1970 GMT.

getExpirationTime()

Returns the time that the SipApplicationSession will expire as a long value representing the number of milliseconds since midnight January 1, 1970 GMT.

getInvalidateWhenReady()

Returns a boolean value specifying whether the container will notify the application when the SipApplicationSession instance is ready to be invalidated.

getLastAccessedTime()

Returns the time that the SipApplicationSession instance was last accessed as a long value representing the number of milliseconds since midnight January 1, 1970 GMT.

setInvalidateWhenReady(boolean invalidateWhenReady)

Tells the container to notify the application when the SipApplicationSession instance is ready to be invalidated.

invalidate()

Explicitly invalidates the SIP application session and unbinds any objects bound to the session. 

isReadyToInvalidate()

Returns a boolean value specifying whether the SipApplicationSession instance is ready to be invalidated.

isValid()

Returns a boolean value specifying whether the SipApplicationSession instance is valid.

setExpires(int deltaMinutes)

Extends the time of expiry for the SipApplicationSession instance by the number of minutes specified by deltaMinutes. If deltaMinutes is 0 or a negative number, the session will never expire. Returns an int value of the number of minutes by which the session was extended. If it returns 0, the session was not extended.

Using SipSessionsUtil to Manage SIP Sessions

The SipSessionsUtil interface defines utility methods for managing SIP sessions in a converged application. Use the javax.annotations.Resource annotation to inject the container's SipSessionsUtil implementation class in your SIP servlets:


Example 1–6 Example of Injecting SipSessionsUtil into a Class

@Resource
SipSessionsUtil sipSessionsUtil;

You may also manually look up SipSessionsUtil through the servlet context.


Example 1–7 Example of Looking Up SipSessionsUtil

SipSessionsUtil sipSessionsUtil = 
	(SipSessionsUtil) getServletContext().
		getAttribute("javax.servlet.sip.SipSessionsUtil");

For more information, see the SIP Servlet 1.1 Javadocs

SIP Listeners

SIP application listeners are Java servlet application listeners that listen for SIP-specific events. SIP applications implement the SIP event listener interfaces by marking the implementation class with a javax.servlet.sip.annotation.SipListener annotation.


Example 1–8 Example of @SipListener

@SipListener
public class MyListener implements SipServletListener {
	...
}

Sip servlet classes may also implement the SIP event listener interfaces.


Example 1–9 Example of SIP Listener in SIP Servlet Class

@SipListener
@SipServlet
public class MySipServlet extends SipServlet implements SipServletListener {
	...
}

SIP Servlet Listeners

The following SIP servlet listeners, in package javax.servlet.sip, are available to SIP servlet developers:

Table 1–10 SIP Servlet Listeners

Listener 

Description 

SipServletListener

Implementations of SipServletListener receive notifications on initialization of SipServlet instances. See the SIP Servlet 1.1 Javadocs for more information.

SIP Application Session Listeners

The following SIP application listeners, in package javax.servlet.sip, are available to SIP servlet developers:

Table 1–11 SIP Application Listeners

Listener 

Description 

SipApplicationSessionListener

Implementations of SipApplicationSessionListener receive notifications when SipApplicationSession instances have been created, destroyed, timed out, or are ready to be invalidated. See the SIP Servlet 1.1 Javadocs for more information.

SipApplicationSessionAttributeListener

Implementations of SipApplicationSessionAttributeListener receive notifications when attributes are added, removed, or modified in SipApplicationSession instances. See the SIP Servlet 1.1 Javadocs for more information.

SipApplicationSessionBindingListener

Session attributes that implement SipApplicationSessionBindingListener receive notifications when they are bound or unbound to SipApplicationSession instances. See the SIP Servlet 1.1 Javadocs for more information.

SipApplicationSessionActivationListener

Implementations of SipApplicationSessionActivationListener receive notifications when SipApplicationSession instances are activated or passivated. See the SIP Servlet 1.1 Javadocs for more information.

SIP Session Listeners

The following SIP session listeners, in package javax.servlet.sip, are available to SIP servlet developers:

Table 1–12 SIP Session Listeners

Listener 

Description 

SipSessionListener

Implementations of SipSessionListener receive notifications when SipSession instances are created, destroyed, or ready to be invalidated. See the SIP Servlet 1.1 Javadocs for more information.

SipSessionActivationListener

Implementations of SipSessionActivationListener receive notifications when SipSession instances are activated or passivated. See the SIP Servlet 1.1 Javadocs for more information.

SipSessionAttributeListener

Implementations of SipSessionAttributeListener receive notifications when attributes are added, removed, or modified in SipSession instances. See the SIP Servlet 1.1 Javadocs for more information.

SipSessionBindingListener

Attributes that implement SipSessionBindingListener receive notifications when they are bound or unbound from SipSession instances. See the SIP Servlet 1.1 Javadocs for more information.

SIP Error Listeners

The following SIP error listeners, in package javax.servlet.sip, are available to SIP servlet developers:

Table 1–13 SIP Error Listeners

Listener 

Description 

SipErrorListener

Implementations of SipErrorListener receive notifications when an expected ACK or PRACK SIP message is not received. See the SIP Servlet 1.1 Javadocs for more information.

SIP Timer Listeners

The following SIP timer listeners, in package javax.servlet.sip, are available to SIP servlet developers:

Table 1–14 SIP Timer Listeners

Listener 

Description 

TimerListener

Implementations of TimerListener receive notifications when ServletTimer instances have fired. See the SIP Servlet 1.1 Javadocs for more information.

For information on SIP timers, see SIP Timers.

SIP Timers

The SIP timer service is provided by the SIP servlet container to allow SIP applications to schedule and manage timers, and receive notifications when timers expire. Timers are events that can be scheduled to run once at a specific time, or to repeat at configurable intervals. Timers may be persistent, in which case the timer will be preserved across Communications Server restarts. Persistent timers will be fired on server startup if the server was shut down when the timer was supposed to fire.

Repeating timers can be either fixed-delay or fixed-rate. Both fixed-delay and fixed-rate timers will fire at approximately regular intervals, but fixed-delay timers will fire regardless of whether previous timer firings were late. Fixed-rate timers are rescheduled based on the absolute time.

Managing SIP Timers

The container provides a javax.servlet.sip.TimerService implementation that allows you to create timers, which are javax.servlet.sip.ServletTimer instances. The TimerService interface defines the following methods for creating timers:

Table 1–15 TimerService Timer Creation Methods

Method 

Description 

createTimer(SipApplicationSession session, long delay, boolean isPersistent, Serializable info)

Creates a single, optionally persistent timer associated with the specified SIP application session. The delay parameter is the time in milliseconds before a timer fires. The info parameter is the application information delivered when the timer expires.

createTimer(SipApplicationSession session, long delay, long period, boolean fixedDelay, boolean isPersistent, Serializable info)

Creates a recurring, optionally persistent timer associated with the specified SIP application session. The delay parameter is the time in milliseconds before the timer first fires. The period parameter is the time in milliseconds after the first timer firing that the timer will fire again. The fixedDelay parameter specifies whether the timer is fixed-delay or fixed-rate. The info parameter is the application information delivered when the timer expires.

The ServletTimer interface defines the following methods for managing a particular timer:

Table 1–16 TimerService Timer Management Methods

Method 

Description 

cancel()

Cancels the timer. 

getApplicationSession()

Returns the SipApplicatonSession instance the timer is associated with.

getId()

Returns the ID of the timer as a String. 

getInfo()

Returns a Serializable object of the information specified when the timer was created.

getTimeRemaining()

Returns a long representing the number of milliseconds until the timer is scheduled to next fire.

scheduledExecutionTime()

Returns a long representing the most recent time the timer was scheduled to fire. If the timer has not yet fired, the return value is undefined.

For more information on the TimerService interface, see the SIP Servlet 1.1 Javadocs.

Back-to-Back User Agent Applications

A back-to-back user agent (B2BUA) is a SIP element that acts as an endpoint for two or more SIP dialogs, forwarding requests and responses between the dialogs. B2BUA applications are extremely common SIP applications, and SIP Servlet 1.1 defines a helper class, javax.servlet.sip.B2buaHelperto simplify the creation of B2BUA applications. B2BUA applications have the potential to break end-to-end communication between endpoints because they sit between two endpoints in a communication chain. Using B2buaHelper minimizes some of the risk of breaking the signaling between two endpoints.

Understanding the B2buaHelper Class

The B2buaHelper class contains all the necessary methods for creating B2BUA applications. It is retrieved by calling SipServerRequest.getB2buaHelper.


Example 1–10 Example of Retrieving B2buaHelper

private void sendInfoToClient(SipServletResponse resp) {
	SipServletRequest req = resp.getRequest();
	B2buaHelper b2buaHelper = req.getB2buaHelper();
	...
}

A typical B2BUA application has two SIP sessions, one for each client. The B2buaHelper class is typically used to create requests that are then forwarded to and from the SIP sessions. retrieve linked sessions.

For a complete list of B2buaHelper's methods, see SIP Servlet 1.1 Javadocs.

Creating Requests with B2buaHelper

Once you've retrieved B2buaHelper, you can use it to link two SIP sessions by creating requests using the createRequest method.


Example 1–11 Creating a Request Using B2buaHelper

SipServletRequest clientRequest = 
		b2buaHelper.createRequest(serverReq, true, headerMap);

The createRequest method takes a SipServletRequest instance of the original request, an optional boolean indicating whether the sessions should be linked, and a java.util.Map<String,java.util.Set> map of headers that will be used instead of the headers in the original request. The From and To headers are the keys in the map. The only headers that can be set using this map are non-system headers and the From, To, and Route headers.

See Example 2–6 for the full method where B2buaHelper is used to create a request that links two sessions.

Retrieving Linked Sessions Using B2buaHelper

Once two client's sessions are linked you can then retrieve the sessions using getLinkedSession.


Example 1–12 Retrieving Linked Sessions Using B2buaHelper

private void sendByeToServer(SipServletRequest clientBye) 
        throws ServletException, IOException {
    B2buaHelper b2buaHelper = clientBye.getB2buaHelper();
    SipSession serverSession = b2buaHelper.getLinkedSession(clientBye.getSession());
    SipServletRequest serverBye = serverSession.createRequest("BYE");
    logger.info("Sending BYE request.\n" + serverBye);
    serverBye.send();
}

SIP Servlets and the SIP Servlet Container

The SIP servlet container manages the lifecycle of SIP servlets, enables network communication for SIP requests and responses by listening on a particular listening point, and provides optional services such as security and interaction with other server-side components.

Structure of a SIP Application

A typical SIP application consists of the following programming artifacts:

The sip.xml Deployment Descriptor

The optional sip.xml deployment descriptor is used by the SIP servlet container to process deployed SIP applications and configure the runtime to properly respond to incoming SIP requests. It is similar in structure to web.xml deployment descriptor used by Java EE web applications. You may bypass the need for a fully defined sip.xml if you use SIP annotations in your application.

Packaging a SIP Application

SIP applications are packaged in either SAR (SIP archive) or WAR (web archive) files. These archives are standard Java archives (JAR). The SAR format is similar to and based on the WAR format, including the use of the presence of the WEB-INF folder that contains class files and deployment descriptors. SIP containers will recognize either the .sar or .war extensions when processing SIP applications.

Converged applications may be packaged in WAR files, or the SAR or WAR file may be itself packaged within an Enterprise archive (EAR), similar to a typical Java EE application. This means a SIP application that has been packaged in a SAR or WAR may be packaged with enterprise bean components, Java Persistence API JARs, and any other Java EE component that is allowed to be packaged in EAR files.