X

Adding Voice to Java EE With SIP Servlets

Guest Author

by Prasad Subramanian

target="_blank">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. target="_blank">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 height="491" width="560">
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 href="http://www.ietf.org/rfc/rfc3261.txt" target="_blank">RFC3261
and is now accepted as the standard signaling protocol for the
3rd Generation
Partnership Project (3GPP)
and as a permanent element
in the target="_blank">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 height="368" width="430">
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.





alt="Composition of a SIP Message" height="326" width="500">
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.

Annotations

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 java.net, 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
target="_blank">Download SailFin Builds page.
Follow the
target="_blank">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:

  • Registration.java. 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.
  • RegistrationBrowserServlet.java. An HTTP Servlet
    that provides an interface to select the registered
    users for the call.
  • SipCallSetupServlet.java. An HTTP Servlet that sends
    an INVITE message to the first user (UserB).
  • B2BCallServlet.java. 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 height="356" width="557">
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.

RegistrarServlet.java

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.


cellspacing="2"> style="vertical-align: top; background-color: rgb(255, 255, 204);">import
com.ericsson.sip.Registration;


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

public class RegistrarServlet
extends SipServlet{


    style="color: rgb(51, 0, 153);">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

    @Resource style="font-weight: bold;">    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


            style="font-weight: bold;">SipURI to = cleanURI((SipURI)
request.getTo().getURI());
           
ListIterator<Address> li = request.getAddressHeaders("Contact");


           
while (li.hasNext()){

               
Address na = li.next();

               SipURI contact = (SipURI)
na.getURI();


               
logger.log(Level.FINE, "Contact = " + contact);

                 

                style="color: rgb(51, 0, 153); font-style: italic;"> An EntityManager
object is created for storing the user data.

               EntityManager em =
emf.createEntityManager();


               
try {

                       
utx.begin();

                       
Registration registration = new Registration();

                       
registration.setId(to.toString());


                       
registration = em.merge(registration);

                       
em.remove(registration);

                       
utx.commit();

                       
logger.log(Level.FINE, "Registration was successfully created.");

                
} catch (Exception ex) {

                       
try {

                           
utx.rollback();

                       
} catch (Exception e) {


                       
}

               
}

               
em.close();
               
If the registration is successful , a response code of 200 OK is sent


               response.send();

        } catch(Exception e) {

          
style="font-style: italic; color: rgb(51, 0, 153);">If the
registration is not successful , a response code of 500 is sent

            style="font-weight: bold;"> response.setStatus(500);

            style="font-weight: bold;">response.send();

        }

    }

RegistrationBrowserServlet.java

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


cellspacing="2"> style="vertical-align: top; background-color: rgb(255, 255, 204);">@PersistenceContext(name
= "persistence/LogicalName", unitName =
"EricssonSipPU")
public class
RegistrationBrowserServlet extends HttpServlet {
style="font-weight: bold;">@PersistenceUnit(unitName =
"EricssonSipPU") private EntityManagerFactory emf;
style="font-weight: bold;">

   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 {

      
response.setContentType("text/html;charset=UTF-8");

       PrintWriter out =
response.getWriter();
      

        This gets the list of
registrations


      
Collection registrations = getRegistrations();


       Iterator iter =
registrations.iterator();


      
out.println("<html><body>");
      
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("</FORM>");

       out.println("SipFactoryInstance =
"+sf.toString());

      
out.println("</body></html>");

       out.close();

   }

SipCallSetupServlet.java

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


cellspacing="2"> style="vertical-align: top; background-color: rgb(255, 255, 204);">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


        style="font-weight: bold;">String[] contacts =
request.getParameterValues("CONTACT");



        if ( contacts.length < 2
)  {

           
return;

        }


        callA = contacts[0];

        callB = contacts[1];

       
Using the SipFactory object to create a SipApplicationSession


        style="font-weight: bold;">SipApplicationSession as =
sf.createApplicationSession();


       
style="font-style: italic; color: rgb(51, 0, 153);">Using the
SipFactory object to create a "To" and "From" Address objects

        style="font-weight: bold;"> Address to = sf.createAddress(callB); style="font-weight: bold;">       
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.
        style="font-weight: bold;">SipServletRequest sipReq =
sf.createRequest(as, "INVITE", from, to);


         
logger.log(Level.FINE, "SipCallSetupServlet sipRequest = " +
sipReq.toString());

       

        
style="font-style: italic; color: rgb(51, 0, 153);">Set an attribute
in SipServletRequest to indicate that this is an initial INVITE

        style="font-weight: bold;">sipReq.setAttribute("CALL","INITIAL");


         // set servlet to
invoke by response
        
Getting a SipSession from the Request created


         style="font-weight: bold;">SipSession s = sipReq.getSession();
         
This is the key part. We set name of the servlet that would handler the
response for the
style="color: rgb(51, 0, 153); font-style: italic;">          
Request being sent. Here b2b is the name of the SIP Servlet that would
handle the response

           to this
request.
style="font-weight: bold;">        
s.setHandler("b2b");


         // lets send invite to
B ...

         
style="color: rgb(51, 0, 153); font-style: italic;">Sending the request
         style="font-weight: bold;">sipReq.send();


    }

B2BCallServlet.java

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.


cellspacing="2"> style="vertical-align: top; background-color: rgb(255, 255, 204);"> style="color: rgb(0, 0, 0);">public
class B2BCallServlet extends SipServlet
{


   
SipFactory                             
sf              
= null;

   
ServletContext                         
ctx             
= null;


   
public
void init(ServletConfig config) throws ServletException {

        super.init(config);

        ctx =
config.getServletContext();
           
Get the SipFactory from the ServletContext


            style="font-weight: bold;">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");

       
style="font-style: italic; color: rgb(51, 0, 153);">
       
if( alreadySent == null && resp.getContentLength() > 0
&& resp.getContentType().equalsIgnoreCase("application/sdp")) {

           
String responseFrom = (String) origReq.getAttribute("CALL");

            
style="font-style: italic; color: rgb(51, 0, 153);">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
            style="font-weight: bold;"> if("INITIAL".equals(responseFrom)) {

               
//Take the SDP and send to A
style="font-style: italic; color: rgb(51, 0, 153);">              
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());


               
newReq.setContent(resp.getContent(),resp.getContentType());

               
SipSession ssA = newReq.getSession(true);

               
SipSession ssB = resp.getSession(true);

               
Set the SipSession object as a session attribute to each call leg


          style="font-weight: bold;">      
ssA.setAttribute("OTHER_SESSION",ssB); style="font-weight: bold;">               
ssB.setAttribute("OTHER_SESSION",ssA);


               
//Test

               
style="font-style: italic; color: rgb(0, 0, 153);">Set the b2b servlet
as the handler for the response for the new request being sent.

               
ssA.setHandler("b2b");

               
ssB.setHandler("b2b");

               
origReq.setAttribute("SENT_INVITE","SENT_INVITE");
style="font-style: italic; color: rgb(0, 0, 153);">               
send the request to the other user

               newReq.send(); //Send to A

            }
else {

               
style="font-style: italic; color: rgb(0, 0, 153);">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");

               
ssB.setAttribute("SDP",resp.getContent());

            }

        } else {

           
return;

        }

        // Count so that both sides
sent 200.

        style="font-style: italic;">If
response has a 200OK as the status code
style="color: rgb(0, 0, 0);"> style="font-style: italic; color: rgb(0, 0, 153);">
style="font-weight: bold;">       
if( resp.getStatus() == 200 ) {

           
style="color: rgb(0, 0, 0);"> style="color: rgb(0, 0, 153);">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

               
sas.setAttribute("GOT_FIRST_200",resp);

            }

            else
{ //This is the second 200 sen both ACK

               
style="font-style: italic;">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.
style="font-weight: bold;">               
sendAck(resp);
               
sendAck(first);


            }

        }

    }

    

    
style="font-style: italic;">This
method sends the ACK with the SDP.

style="font-weight: bold;">   
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 ) {

           
ack.setContent(content,"application/sdp");

        }

        ack.send();

    }


}

sip.xml

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.


cellspacing="2"> style="vertical-align: top; background-color: rgb(255, 255, 204);"><sip-app>

    <display-name>SIP
Registrar</display-name>

    <description>SIP Registrar
application</description>

    <servlet>

        style="font-weight: bold;"><servlet-name>registrar</servlet-name>

        <description>Registrar
SIP servlet</description>

       
<servlet-class>com.ericsson.sip.RegistrarServlet</servlet-class>

        <init-param>

           
<param-name>Registrar_Domain</param-name>

           
<param-value>ericsson.com</param-value>

        </init-param>

       
<load-on-startup>1</load-on-startup>

    </servlet>

    <servlet>

        style="font-weight: bold;"><servlet-name>b2b</servlet-name>

       
<servlet-class>com.ericsson.sip.B2BCallServlet</servlet-class>

       
<load-on-startup>1</load-on-startup>

    </servlet>

    <servlet-mapping>

        style="font-weight: bold;"><servlet-name>registrar</servlet-name>

        <pattern>

           
<and>

               
<equal>

                   
<var ignore-case="false">request.uri.host</var>

                   
<value>test.com</value>

               
</equal>

               
<or>

                   
<equal>

                       
<var ignore-case="false">request.method</var>

                       
<value>REGISTER</value>

                   
</equal>

                   
<equal>

                       
<var ignore-case="false">request.method</var>

                       
<value>INVITE</value>

                   
</equal>

                   
<equal>

                       
<var ignore-case="false">request.method</var>

                       
<value>OPTIONS</value>

                   
</equal>

                   
<equal>

                       
<var ignore-case="false">request.method</var>

                       
<value>MESSAGE</value>

                   
</equal>

               
</or>

           
</and>

        </pattern>

    </servlet-mapping>

</sip-app>

persistence.xml

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.


cellspacing="2"> style="vertical-align: top; background-color: rgb(255, 255, 204);"><?xml
version="1.0" encoding="UTF-8"?>

<persistence version="1.0"
xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">

  <persistence-unit
name="EricssonSipPU"

transaction-type="JTA">

   
<provider>oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider</provider>

   
<jta-data-source>jdbc/__default</jta-data-source>

    <properties>

      <property
name="toplink.ddl-generation" value="drop-and-create-tables"/>

    </properties>

  </persistence-unit>

</persistence>

Running the Sample Application

To run the CallSetup application, follow the instructions on the
target="_blank">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.

Summary

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
target="_blank">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.

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------



width="100">
width="170">
src=""
alt="Try GlassFish" padding="5" border="0" height="88" width="100">

href="http://java.sun.com/javaee/community/campaigns/iphone-012008/welcome.jsp">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.




Join the discussion

Comments ( 8 )
  • bob Wednesday, March 5, 2008

    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?


  • Prasad Subramanian Tuesday, March 11, 2008

    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 users@sailfin.dev.java.net AND dev@sailfin.dev.java.net

    Thanks for asking !

    --Prasad


  • Fan Monday, April 7, 2008

    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.


  • Peter Klein Wednesday, April 16, 2008

    Hello,

    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.


  • Prasad Subramanian Wednesday, April 16, 2008

    @Fan : Thanks ! Yes, we would need a STUN server to resolve NAT issues. There is a STUN server that is available with jVoiceBridge, from http://jvoicebridge.dev.java.net , 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 ?

    Thanks

    Prasad


  • Java User Tuesday, September 30, 2008

    Hi,

    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

    Java_User


  • Soren Friday, October 24, 2008

    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?

    Thanks,

    Soren


  • diego gallego Friday, September 11, 2009

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


Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.