Adding Voice to Java EE With SIP Servlets

by Prasad Subramanian

Session Initiation Protocol (SIP) is a signaling protocol that is used to set up, modify, and terminate a session between two endpoints. SIP can be used to set up a two-party call, a multi-party call, or even a multicast session for Internet calls, multimedia calls, and multimedia distribution. JSR 116: SIP Servlet API is a server-side interface describing a container of SIP components or services. SIP servlets, servlets that run in a SIP container, are similar to HTTP Servlets, but also support the SIP protocol. Together, SIP and SIP servlets, are behind many popular telecommunications-based applications that provide services such as Voice-over-IP (VoIP), instant messaging, presence and buddy list management, as well as web conferencing.

SIP and SIP servlets are also important in the enterprise. Combined with Java EE technology, SIP servlets can be used to add rich media interactions to enterprise applications. JSR 289: SIP Servlet v1.1 updates the SIP Servlet API and defines a standard application programming model to mix SIP servlets and Java EE components. SIP servlets are going to play an even bigger part in building the next generation of telecommunications services.

This Tech Tip covers some of the basic concepts underlying SIP and SIP servlets. It also presents a sample application that uses SIP servlets and HTTP servlets to provide VoIP phone service.

What is SIP?

An easy way to describe SIP is to examine a usage scenario. Let's say a user identified as A wants to set up a call with a user identified as B. In a telecommunications setting, user A and B would communicate through what are called user agents. One example of a user agent is a soft phone -- a software program for making telephone calls over the Internet. Another example is a VoIP Phone -- a phone that uses VoIP. Here are the steps that need to happen to set up the call:

  1. A invites B to start a conversation. As part of the invitation, A indicates what media it is capable of supporting.
  2. B receives the invitation, sends an immediate response to A, and then evaluates the invitation.
  3. When B is ready to accept the invitation, it sends an acknowledgment to A. As part of the acknowledgement, B indicates what media it supports.
  4. A examines the acknowledgment it receives from B and determines if the media supported by B and A are the same. If A and B support the same media, a call is set up between A and B. The media specified in the invitation facilitates the call.

Figure 1 illustrates the steps in setting up a call.

Steps in Setting Up a Call
Figure 1. Steps in Setting Up a Call

SIP provides a standardized way of carrying out these steps. It does this by defining specific request methods, responses, response codes, and headers for signaling and call control. The protocol has been standardized by the Internet Engineering Task Force (IETF) under RFC3261 and is now accepted as the standard signaling protocol for the 3rd Generation Partnership Project (3GPP) and as a permanent element in the IP Multimedia Subsystem (IMS) architecture.

How is SIP related to HTTP?

People often ask if SIP uses HTTP as the underlying protocol. The answer is no. SIP is a protocol that operates at the same layer as HTTP, that is, the application layer, and uses TCP, UDP, or SCTP as the underlying protocol. However, SIP does have a lot of similarities with HTTP. For example, like HTTP, SIP is text based and user readable. Also like HTTP, SIP uses a request-response mechanism with specific methods, response codes, and headers. A notable difference between HTTP and SIP is that the request-response mechanism is asynchronous in SIP -- a request does not need to be followed by a corresponding response. In fact, a SIP request could result in one or more requests being generated.

SIP is a peer-to-peer protocol. This means that a user agent can act as a server as well as a client. This is another difference between SIP and HTTP. In HTTP, a client is always a client and a server is always a server.

SIP supports the following request methods and response codes:

Request methods:

  • REGISTER. Used by a client to register an address with a SIP server. .
  • INVITE. Indicates that the user or service is being invited to participate in a session. The body of this message includes a description of the session to which the user or service is being invited.
  • ACK. Confirms that the client has received a final response to an INVITE request. This method is only used with INVITE requests.
  • CANCEL. Used to cancel a pending request.
  • BYE. Sent by a user agent client to indicate to the server that it wishes to terminate the call.
  • OPTIONS. Used to query a server about its capabilities.

Response codes:

  • 1xx: Provisional. An ACK that indicates the action was successfully received, understood, and accepted.
  • 3xx: Redirection. Further action is required to process this request.
  • 4xx: Client Error. The request contains incorrect syntax and cannot be fulfilled at this server.
  • 5xx: Server Error. The server failed to fulfill an apparently valid request.
  • 6xx: Global Failure. The request cannot be fulfilled at any server.

Session Description Protocol

Session Description Protocol (SDP) is a format for describing the media format and type to be used in a multimedia session. SIP uses SDP as a payload in its messages to facilitate the exchange of capabilities between various user agents. For example, the content of an SDP might specify the codecs supported by the user agent and the protocol to be used such as Real-time Transport Protocol (RTP).

SIP Message

Figure 2 shows the composition of a SIP message . There are three major parts:

  • Request Line. Specifies the request method, address, and SIP version.
  • Headers. Specify data about the session or call to be set up or terminated.
  • Message Body. Provides the payload, that is the SDP, describing the media for the session.
Composition of a SIP Message
Figure 2. Composition of a SIP Message

The SIP Servlet Model

The SIP servlet programming model is based on the servlet programming model. It brings programming in SIP closer to Java EE. Servlets are server-side objects that process incoming requests and send an appropriate response to the client. They are typically deployed in a servlet container and have a well-defined life cycle. The servlet container is responsible for managing the life cycle of the servlets within the container and managing resources related to technologies such as JNDI and JDBC that the servlet uses. The servlet container also manages network connections for servlets.

As mentioned earlier, SIP servlets are similar to HTTP Servlets, except that they process SIP requests. They do this by defining specific methods to process each of the SIP request methods. For example, HTTP servlets define the doPost() method, which overrides the service() method, to handle POST requests. By comparison, SIP servlets define a doInvite() method, which also overrides the service() method, to handle INVITE requests.

JSR116 defined SIP Servlet API 1.0. It specified:

  • An API for the SIP servlet programming model.
  • The responsibilities of the SIP servlet container.
  • How SIP servlets interface with HTTP servlets and Java EE components.

The initial SIP Servlet API specification is being revised by JSR 289: SIP Servlet v1.1.

SIP Servlet API -- Key Concepts

The key concepts that underlie SIP servlets are similar to those that underlie HTTP servlets. The following sections briefly describe some of those concepts.

SipServletRequest and SipServletResponse

The request-response methodology in SIP is similar to that for HTTP servlets. A request is defined in a SipServletRequest object and a response in a SipServletResponse object. However, only one ServletRequest or ServletResponse object is non-null. That's because a SIP request does not result in a symmetric response. There is also a common super interface, called SipServletMessage, for both SipServletRequest and SipServletResponse objects. The SipServletMessage interface defines the methods that are common to SipServletRequest and SipServletResponse objects.

Figure 3 illustrates the hierarchy of the SipServletRequest and SipServletResponse objects.

Composition of a SIP Message
Figure 3. Hierarchy of SipServletRequest and SipServletResponse Objects

Servlet Context

The servlet context as defined in the servlet specification also applies to SIP servlets. The servlet specification defines specific context attributes that are used to store and retrieve information specific to SIP servlets and interfaces from the context. The servlet context can be shared with HTTP servlets within the same application. This is explained in the section Converged Applications.

Deployment Descriptor

An XML-based deployment descriptor is used to describe the SIP servlets, the rules for invoking them, as well as the resources and environment property used in the application. This descriptor is in a sip.xml file and is similar to the file used in HTTP servlets. The sip.xml file is defined by an XML schema.

SIP Application Packaging

SIP applications have the same packaging structure as web applications. They are packaged in the JAR format with a file extension of .sar (Sip archive) or .war (web archive).

Converged Context and Converged Application

An application may use both SIP and HTTP servlets to create a service. To allow for HTTP and SIP servlets being in the same application package, the SIP servlet specification defines a ConvergedContext object. This object holds the servlet context shared by both HTTP and SIP servlets and provides the same view of the application to SIP and HTTP servlets in terms of servlet context attributes, resources, and JNDI namespaces.

When an application includes both SIP and HTTP servlets it is known as a converged application. This is in contrast to a SIP-only application, which is called a SIP application. A converged application is similar in structure to a SIP application except that it has a web.xml file as a deployment descriptor in addition to a sip.xml file. In SIP Servlet API 1.1 (JSR289), the concept of converged applications has been extended to also cover enterprise applications. Enterprise applications can now include a SIP application or a converged application as a module. This type of enterprise application is called a converged enterprise application.

SIP Sessions

The SIP servlet specification defines SipSession objects to represent a session over SIP in the same way as HttpSession objects represent sessions over HTTP. Because a single application such as a converged application may have sessions over HTTP and SIP, the specification also defines SipApplicationSession, which is a session object at the application level. The SipApplicationSession object acts as a parent to HTTP and SIP sessions (that is, protocol sessions) in an application.


Recall that the SIP Servlet API 1.1 aims to align SIP servlets with Java EE 5. As a result, the specification introduces the use of annotations defined by Java EE 5 within SIP servlets and listeners. It also defines custom annotations to represent interfaces defined by the SIP servlet specification. The specification introduces the following annotations:

  • @SipServlet. Used to indicate that a particular class is a SipServlet
  • @SipApplication. Used to define a SIP application. This annotation has a set of attributes, one of them being the "name" attribute, which is used to define the name of the application. The SipApplication annotation can be used to create a logical collection of servlets which form an application, without the use of deployment descriptor.
  • @SipListener. Allows a particular class to be registered as a SipListener for a particular SIP application. The name of the SIP application is defined as an attribute to this annotation.
  • @SipApplicationKey. A method level that helps define a SipApplicationKey for a SIP application. The SipApplicationKey is used to associate request with existing SipApplicationSessions.

Project Sailfin - an Open Source SIP Application Server

A SIP servlet container can be standalone, that is, supporting only SIP servlets, or it can be a converged container supporting both HTTP and SIP servlets. However, for most enterprise uses, a SIP servlet container needs to be a converged container within an application server. Project Sailfin is an effort to produce an open source implementation of a SIP servlet container using the GlassFish application server. The project is being developed under, with Sun and Ericsson as the major contributors. Sailfin, the SIP servlet container implementation in GlassFish being developed in the SailFin project, supports SIP Servlet API 1.0 and aims to support SIP Servlet API 1.1 when the specification is finalized.

The CallSetup Sample Application

The sample application for this tip, named CallSetup, is available as part of the SailFin download. You can download SailFin from the Download SailFin Builds page. Follow the SailFin Project - Instructions to install and configure SailFin. The code for the CallSetup application is in the <sailfin-install-home>/samples/sipservlet/CallSetup directory, where <sailfin-install-home> is the directory where you installed SailFin.

The CallSetup application uses SIP servlets and HTTP servlets to provide VoIP phone service. The application places VoIP calls with the help of a Back-to-Back User Agent (B2BUA) SIP servlet. A B2BUA sets up a call between two user agents by calling each user agent individually and then connecting the two of them.

CallSetup Components

CallSetup includes the following components:

  • A plain old Java object (POJO) that represents the registered user.
  • RegistrarServlet. A SIP servlet that allows users to register. The servlet is also used to persist the user data in the the Java DB database bundled with SailFin.
  • An HTTP Servlet that provides an interface to select the registered users for the call.
  • An HTTP Servlet that sends an INVITE message to the first user (UserB).
  • A SIP Servlet that handles the response from the first user and sets up the call with the second user (User A)
  • web.xml. Deployment descriptor for the HTTP servlets.
  • sip.xml. Deployment descriptor for the SIP servlets.
  • sun-web.xml. A product-specific deployment descriptor.
  • persistence.xml. Defines the persistence unit.

Figure 4 shows the sequence of execution of the application.

CallSetup Sequence of Execution
Figure 4. CallSetup Sequence of Execution

Let's look at some of the code in the components that comprise CallSetup. Not all of the components for the application are shown here and not necessarily all the code in each component. You're encouraged to explore the entire code for the application in the SailFin download.

When a user agent sends a REGISTER request, the doRegister() method is invoked and the registration data is stored. A response with a status code is then sent to the user agent.


@PersistenceContext(name = "persistence/LogicalName", unitName = "EricssonSipPU")

public class RegistrarServlet extends SipServlet{

    The PersistenceUnit annotation is used to annotate the EntityManagerFactory with the name of the PU to be used.
    @PersistenceUnit(unitName = "EricssonSipPU")
    private EntityManagerFactory emf;

    The Resource annotation is used to inject the UserTransaction
    private UserTransaction utx;

    protected void doRegister(SipServletRequest request) throws ServletException, IOException {

        SipServletResponse response = request.createResponse(200);
        try {
             The SipServletRequest object is parsed to get to address and request headers. The Contact header is obtained and stored in the database
            SipURI to = cleanURI((SipURI) request.getTo().getURI());
            ListIterator<Address> li = request.getAddressHeaders("Contact");
            while (li.hasNext()){
                Address na =;
                SipURI contact = (SipURI) na.getURI();
                logger.log(Level.FINE, "Contact = " + contact);
                An EntityManager object is created for storing the user data.
                EntityManager em = emf.createEntityManager();
                try {
                        Registration registration = new Registration();

                        registration = em.merge(registration);
                        logger.log(Level.FINE, "Registration was successfully created.");
                 } catch (Exception ex) {
                        try {
                        } catch (Exception e) {

                If the registration is successful , a response code of 200 OK is sent
        } catch(Exception e) {
If the registration is not successful , a response code of 500 is sent

This is an HTTP Servlet that provides an interface to list registered users and to set up calls between the two of them.

@PersistenceContext(name = "persistence/LogicalName", unitName = "EricssonSipPU")
public class RegistrationBrowserServlet extends HttpServlet {
@PersistenceUnit(unitName = "EricssonSipPU") private EntityManagerFactory emf;

   public Collection getRegistrations() {
       EntityManager em = emf.createEntityManager();
       Query q = em.createQuery("select object(o) from Registration as o");
       return q.getResultList();

   protected void processRequest(HttpServletRequest request, HttpServletResponse response)
   throws ServletException, IOException {
       PrintWriter out = response.getWriter();
        This gets the list of registrations

       Collection registrations = getRegistrations();
       Iterator iter = registrations.iterator();

       Call to the HTTP servlet SipCallSetupServlet
       out.println("<FORM ACTION = \\"/CallSetup/SipCallsetupServlet\\" METHOD = POST>");

       out.println("<INPUT TYPE=SUBMIT NAME=Submit VALUE=\\"Submit\\">");
       out.println("SipFactoryInstance = "+sf.toString());

This HTTP Servlet is called from the RegistrationBrowserServlet and acts like a B2BUA by setting up a call between the two users.

public class SipCallSetupServlet extends HttpServlet {

        SipFactory sf = null;
        TimerService ts = null;
        ServletContext ctx = null;

    public void init(ServletConfig config) throws ServletException {
       ctx = config.getServletContext();

        Getting the SIpFactory object from the ServletContext
       sf = (SipFactory) ctx.getAttribute(SipServlet.SIP_FACTORY);

    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {

        String callA = null;
        String callB = null;
         Getting the contacts from request parameters
        String[] contacts = request.getParameterValues("CONTACT");

        if ( contacts.length < 2 )  {

        callA = contacts[0];
        callB = contacts[1];

        Using the SipFactory object to create a SipApplicationSession
        SipApplicationSession as = sf.createApplicationSession();

Using the SipFactory object to create a "To" and "From" Address objects
        Address to = sf.createAddress(callB);
        Address from = sf.createAddress(callA);
         Creating a SipServletRequest using the SipFactory  and the SipApplicationSessionObjects created. Note that
         INVITE is being sent as  if UserA is inviting UserB.
        SipServletRequest sipReq = sf.createRequest(as, "INVITE", from, to);

          logger.log(Level.FINE, "SipCallSetupServlet sipRequest = " + sipReq.toString());
Set an attribute in SipServletRequest to indicate that this is an initial INVITE

         // set servlet to invoke by response
         Getting a SipSession from the Request created
         SipSession s = sipReq.getSession();
          This is the key part. We set name of the servlet that would handler the response for the
           Request being sent. Here b2b is the name of the SIP Servlet that would handle the response
           to this request.

         // lets send invite to B ...
Sending the request


This SIP Servlet receives and handles the response to the INVITE request sent by SipCallSetupServlet. The servlet processes the response headers and body, gets the SDP, and sends another INVITE request to the other user agent, along with the SDP metadata. After it receives the response from other user with a success response code, the servlet sets up the call between the two users.

public class B2BCallServlet extends SipServlet {

    SipFactory                              sf               = null;
    ServletContext                          ctx              = null;

    public void init(ServletConfig config) throws ServletException {
        ctx = config.getServletContext();
            Get the SipFactory from the ServletContext
            sf = (SipFactory) ctx.getAttribute(SipServlet.SIP_FACTORY);
            ts = (TimerService) ctx.getAttribute(SipServlet.TIMER_SERVICE);

    protected void doResponse(SipServletResponse resp) throws ServletException, IOException {
        get the  SipApplicationSession and SipServletRequest from the response
        SipApplicationSession sas = resp.getApplicationSession(true);
        SipServletRequest origReq = resp.getRequest();

        String alreadySent = (String) origReq.getAttribute("SENT_INVITE");

        if( alreadySent == null && resp.getContentLength() > 0 && resp.getContentType().equalsIgnoreCase("application/sdp")) {
            String responseFrom = (String) origReq.getAttribute("CALL");
Check if this an response to INITIAL INVITE sent from the HTTP Servlet, and if there is
            an SDP sent in the response, create an INVITE to the other user
            if("INITIAL".equals(responseFrom)) {
                //Take the SDP and send to A
               Note that To address in the orginal request is the From address here and vice versa. This is what makes this servlet act like
                a B2BUA.
                SipServletRequest newReq = sf.createRequest(sas,"INVITE",origReq.getTo(),origReq.getFrom());
                SipSession ssA = newReq.getSession(true);
                SipSession ssB = resp.getSession(true);

                Set the SipSession object as a session attribute to each call leg
Set the b2b servlet as the handler for the response for the new request being sent.
                send the request to the other user
                newReq.send(); //Send to A
            } else {
If this is a response from User A then get the SDP from User A and set it i
                SipSession ssB = (SipSession) resp.getSession().getAttribute("OTHER_SESSION");
        } else {
        // Count so that both sides sent 200.
        If response has a 200OK as the status code

        if( resp.getStatus() == 200 ) {
Check if this is a response from the UserB ( first user)
            SipServletResponse first = (SipServletResponse) sas.getAttribute("GOT_FIRST_200");
            if( first == null ) { // This is the first 200
            else { //This is the second 200 sen both ACK
This is a second response and now we send an ACK to both
                 User A and UserB. This exchanges the SDP and sets up the call.
This method sends the ACK with the SDP.
    private void sendAck( SipServletResponse resp ) throws IOException {
        SipServletRequest ack = resp.createAck();
        //Check if pending SDP to include in ACK
        Object content = resp.getSession().getAttribute("SDP");
        if( content != null ) {



The sip.xml file defines the SIP servlets and specifies their mapping. The mapping for a SIP servlet uses the equal, and, or, and not operators to define a condition in which the servlet is invoked. In this case, the match is on the request method being either REGISTER, INVITE, OPTIONS, or MESSAGE.

    <display-name>SIP Registrar</display-name>
    <description>SIP Registrar application</description>
        <description>Registrar SIP servlet</description>
                    <var ignore-case="false"></var>
                        <var ignore-case="false">request.method</var>
                        <var ignore-case="false">request.method</var>
                        <var ignore-case="false">request.method</var>
                        <var ignore-case="false">request.method</var>


The persistence.xml file defines the persistence unit, EricssonSipPU, which is used to persist the registration data in the database. The application uses the default JDBC resource available with Sailfin, jdbc/__default.

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="" xmlns:xsi="" xsi:schemaLocation="">
  <persistence-unit name="EricssonSipPU" transaction-type="JTA">
      <property name="toplink.ddl-generation" value="drop-and-create-tables"/>

Running the Sample Application

To run the CallSetup application, follow the instructions on the SailFin Project - Instructions page. If you follow the instructions successfully, you should be able to set up a call between two softphone clients. The phone should ring sequentially at two selected end points.


This tip covered some of the basic concepts underlying SIP and SIP servlets. It also presented a sample application that uses SIP servlets and HTTP servlets to provide VoIP phone service. And it introduced the SailFin project, which is building an open source implementation of a SIP servlet container using the GlassFish application server.

To learn more about SIP, SIP servlets, and the SailFin project, consult the following resources:

Note that there is a NetBeans plugin available for SIP servlets, which allows you to create a SIP application using the NetBeans IDE. The plugin is available as a part of SailFin. You can learn more about the NetBeans plugin in the blog entry NetBeans 6.1 and Project Sailfin.

About the Author

Prasad Subramanian is a staff engineer at Sun Microsystems and is the engineering lead for Project Sailfin.


Try GlassFish

Connect and Participate With GlassFish
Try GlassFish for a chance to win an iPhone. This sweepstakes ends on March 23, 2008. Submit your entry today.


Great article!

Does this work only within an enterprise network? I'd like to have a Sailfin server running at my colo datacenter, and have home users use it to do voice conf / IM. Are there issues getting past home routers when the two users try to connect, or has that been solved somehow in the code?

Posted by bob on March 05, 2008 at 06:15 AM PST #

At this time Sailfin works only within an enterprise network. To make home users connect to Sailfin directly via home routers, we may need a way to work around NAT issues. That is something that we want to solve in the next quarter. Stay tuned !

Try and listen to AND

Thanks for asking !

Posted by Prasad Subramanian on March 11, 2008 at 04:39 PM PDT #

Great work and great introduction,

thanks Prasad. I have been waiting for the package for a long time since the birth of SIP/SDP, for building instant messaging, presence and buddy list management, as well as web conferencing into a J2EE application server and product which is installed and setting up in a personal desktop or laptop, either for personal content publishing and management. As regard to NAT issue, you always need a central server to hook up two users.

thanks Prasad.

Posted by Fan on April 07, 2008 at 08:44 AM PDT #


Which features do you plan to make sailfin working with NAT home routers ?
I plan to make a demo installation of a sailfin server and this would also require access through NAT routers. In my opinion NAT issues can be solved on client side and would not require server side changes.

Posted by Peter Klein on April 15, 2008 at 08:42 PM PDT #

@Fan : Thanks ! Yes, we would need a STUN server to resolve NAT issues. There is a STUN server that is available with jVoiceBridge, from , which could be a potential integration.

@Peter : We would need to potentially change Sailfin to listen to both SIP and STUN requests on the same port. This is still under discussion. Do you have any ideas on this ?


Posted by Prasad Subramanian on April 16, 2008 at 03:20 AM PDT #

We have a custom SIP Stack developed using C. And they expose dll's for the SIP events. We need to develop a browser based IM client for voice chat using the SIP stack.
Is it possible to use SIPServlet?

Thanks in advance

Posted by Java User on September 29, 2008 at 07:57 PM PDT #

Hi Prasad,

Great introduction to Sailfin.

Are there any plans on adding the "voice" part of the signalling into the Sailfin project? Eg. the recent JSR 309 or like?


Posted by Soren on October 24, 2008 at 02:51 AM PDT #

how can i communicate a sip-servlet with a http-servlet?

Posted by diego gallego on September 11, 2009 at 01:18 PM PDT #

Post a Comment:
Comments are closed for this entry.



« April 2014