Sony Manuel's blog
Linking multiple SIP and Converged Http sessions to a SipApplicationSession (SAS) in SailFin
See Jan Luehe's blog for an introduction to Converged Http Sessions. In this blog I'll discuss how we can link multiple SIP and Converged Http sessions to the same SAS.
Lets take the example of a converged conference application where SAS represents a conference instance. Here we will use the conference name to form the SAS ID (though any String can be used for the same). SIP Session (SS) represents each call in the conference. Converged Http Session (CHS) represents users accessing the conference details through the web.
For SipServlets we should use the @SipApplicationKey annotation to link a new request to a particular SAS.
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.sip.SipServlet;
import javax.servlet.sip.SipServletRequest;
import javax.servlet.sip.SipServletResponse;
import javax.servlet.sip.annotation.SipApplicationKey;
public class ConferenceSipServlet extends SipServlet {
@SipApplicationKey
public static String sessionKey(SipServletRequest request) {
String conferenceName = request.getHeader("Conference-Name");
return conferenceName;
}
@Override
public void doInvite(SipServletRequest request)
throws ServletException, IOException {
SipServletResponse response = request.createResponse(180);
response.send();
response = request.createResponse(200, "OK");
String conferenceName = request.getHeader("Conference-Name");
String sasId = request.getSession().getApplicationSession().getId();
getServletContext().setAttribute(conferenceName, sasId);
String userName = request.getTo().getURI().toString();
request.getSession().setAttribute("UserName", userName);
response.send();
}
@Override
public void doBye(SipServletRequest request) throws IOException {
SipServletResponse response = request.createResponse(200, "OK");
response.send();
request.getSession().invalidate();
}
}
Here the INVITE request has a header 'Conference-Name' which is the conference the user intends to join. The SIP container will link all requests returning the same value for sessionKey() to the same SAS.
The CHS functional specification for SailFin describes different ways of linking CHS and SAS. In this particular example we will use a SAS encoded URL for linking.
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URL;
import java.util.Date;
import java.util.Iterator;
import java.util.logging.Logger;
import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.sip.ConvergedHttpSession;
import javax.servlet.sip.SipApplicationSession;
import javax.servlet.sip.SipSession;
import javax.servlet.sip.SipSessionsUtil;
public class ConferenceHTTPServlet extends HttpServlet {
@Resource
SipSessionsUtil ssu;
static Logger logger = Logger.getLogger("ConferenceHTTPServlet");
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
logger.info("processRequest " + request.getRequestURL());
PrintWriter out = response.getWriter();
try {
String conferenceName = request.getParameter("Conference-Name");
if (conferenceName == null) {
listParticipants(request, out);
} else {
redirectRequest(request, response, conferenceName);
}
} catch (Exception e) {
e.printStackTrace(out);
} finally {
out.close();
}
}
private void redirectRequest(HttpServletRequest request,
HttpServletResponse response, String conferenceName) throws Exception {
ConvergedHttpSession chs = (ConvergedHttpSession) request.getSession(true);
chs.setAttribute("Conference-Name", conferenceName);
String sasId = (String) getServletContext().getAttribute(conferenceName);
logger.info("SAS id = " + sasId);
SipApplicationSession sas = ssu.getApplicationSession(sasId);
String chsEncoded = chs.encodeURL("/ConferenceHttpServlet", "http");
URL url = sas.encodeURL(new URL(chsEncoded));
logger.info("encoded url = " + url);
response.sendRedirect(url.toString());
}
private void listParticipants(HttpServletRequest request, PrintWriter out)
throws Exception {
ConvergedHttpSession chs = (ConvergedHttpSession) request.getSession(false);
SipApplicationSession sas = chs.getApplicationSession();
String conferenceName = (String) chs.getAttribute("Conference-Name");
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet ConferenceHTTPServlet</title>");
out.println("</head>");
out.println("<body>");
out.println("<h3> Welcome to conference " + conferenceName + "</h3>");
Iterator<SipSession> sessions = (Iterator<SipSession>) sas.getSessions("SIP");
out.println("<h4> Participants </h4>");
while (sessions.hasNext()) {
SipSession session = sessions.next();
String name = (String) session.getAttribute("UserName");
out.println(name + " . Call started " + new Date(session.getCreationTime()));
out.println("<br>");
}
out.println("<br>");
out.println("<form action=\"ConferenceHTTPServlet\" method=\"get\">");
out.println("<input type=\"submit\" value=\"Refresh\"/>");
out.println("</form>");
out.println("</body>");
out.println("</html>");
}
// <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
/**
* Handles the HTTP <code>GET</code> method.
* @param request servlet request
* @param response servlet response
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
/**
* Handles the HTTP <code>POST</code> method.
* @param request servlet request
* @param response servlet response
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
/**
* Returns a short description of the servlet.
*/
public String getServletInfo() {
return "Short description";
}
// </editor-fold>
}
On accessing the Servlet at http://localhost:8080/simple-conf/ConferenceHttpServlet?Conference-Name=sailfin, processRequest() is invoked which in turns calls redirectRequest(). Within this function the SAS instance is fetched using the SAS ID stored in ServletContext by invoking SipSessionsUtil.getApplicationSession(sasId). At this point the CHS and SAS are not linked. The SAS encoded URL looks like this.
http://localhost:8080/simple-conf/ConferenceHttpServlet;sipappsessionid=7,7,sailfin/simple-conf
A redirect or subsequent request on this URL will cause the converged container to link the CHS and SAS. After linking we can access the SIP Sessions that are a part of the same SAS. See listParticipants() in the code sample above which lists all the SIP sessions.
Running 2 SIPp UAC instances and accessing the web Servlet gives the following response:
Participants
sip:foo@127.0.0.1:5060 . Call started Fri Apr 18 16:59:34 IST 2008
sip:bar@127.0.0.1:5060 . Call started Fri Apr 18 16:59:39 IST 2008
The above example will work on a single SailFin instance.
In my next blog, I will discuss how to configure the same in a SailFin cluster.
Posted at 01:16AM Apr 19, 2008 by sonymanuel in Sun | Comments[0]