This chapter describes the SIP protocol and the background needed for developing SIP applications using the Java programming language.
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.
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.
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.
The SIP Protocol uses response codes similar to the HTTP protocol.
Some common response codes are as follows:
100 (Trying)
200 (OK)
404 (Not found)
500 (Server internal failure)
See SIP Responses for more information on SIP responses.
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.
SIP servlets differ from typical HTTP servlets used in web applications in the following ways:
HTTP servlets have a particular context (called the context-root) in which they run, while SIP servlets have no context.
HTTP servlets typically return HTML pages to the requesting client, while SIP servlets typically connect SIP-enabled clients to enable telecommunications between the client and server.
SIP is a peer-to-peer protocol, unlike HTTP, and SIP servlets can originate SIP requests, unlike HTTP servlets which only send responses to the originating client.
SIP servlets often act as proxies to other SIP endpoints, while HTTP servlets are typically the final endpoint for incoming HTTP requests.
SIP servlets can generate multiple responses for a particular request.
SIP servlets can communicate asynchronously, and are not obligated to respond to incoming requests.
SIP servlets often work in concert with other SIP servlets to respond to particular SIP requests, unlike HTTP servlets which typically are solely responsible for responding to HTTP requests.
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.
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 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. |
The javax.servlet.sip.annotation.SipServlet class-level annotation is used to mark the class as a SIP servlet.
@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. |
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. |
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.
@SipApplication(name="MySipApplication") package com.example.sip;
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. |
The javax.servlet.sip.annotation.SipApplicatonKey method-level annotation associates an incoming request with a particular SIpApplicationSession instance.
The method annotated by @SipApplicationKey must:
Be public.
Be static.
Return a String.
Define a single argument of type SipServletRequest.
Not modify the passed-in SipServletRequest object.
The returned String is the key used to associate the request with a SipApplicationSession instance.
@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. |
The javax.servlet.sip.SipFactory interface defines several abstractions useful in SIP applications. SIP applications use the container's SipFactory instance to create :
Requests using the createRequest methods.
Address objects such as URI, SipURI, Address, and Parameterable instances.
Application sessions.
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.
@Resource SipFactor sf;
You may also look up the container's SipFactory instance through the servlet context.
SipFactory sf = (SipFactory) getServletContext().getAttribute("javax.servlet.sip.SipFactory");
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 defines a number of methods for managing application sessions and session data.
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. |
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. |
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. |
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:
@Resource SipSessionsUtil sipSessionsUtil;
You may also manually look up SipSessionsUtil through the servlet context.
SipSessionsUtil sipSessionsUtil = (SipSessionsUtil) getServletContext(). getAttribute("javax.servlet.sip.SipSessionsUtil");
For more information, see the SIP Servlet 1.1 Javadocs
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.
@SipListener public class MyListener implements SipServletListener { ... }
Sip servlet classes may also implement the SIP event listener interfaces.
@SipListener @SipServlet public class MySipServlet extends SipServlet implements SipServletListener { ... }
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. |
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. |
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. |
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. |
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.
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 Application Server 1.5 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.
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.
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.
The B2buaHelper class contains all the necessary methods for creating B2BUA applications. It is retrieved by calling SipServerRequest.getB2buaHelper.
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.
Once you've retrieved B2buaHelper, you can use it to link two SIP sessions by creating requests using the createRequest method.
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.
Once two client's sessions are linked you can then retrieve the sessions using getLinkedSession.
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(); }
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.
A typical SIP application consists of the following programming artifacts:
One or more SIP servlets.
Optional utility and helper classes such as SIP listeners.
Static resources used by the classes.
Metadata and optional configuration files.
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.
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.