SIP Servlet Engine© Documentations
 
  Top >   SIP Servlet Programming >   SIP Servlet Programming >   Click2Dial Sample
 
 

Click2Dial Sample

This document describes how a 3PCC servlet is started and events are received. For information about this SPI and utility class, see 3PCC Function and BasicSipAction Class.

Overview of Configuration and Processing

Figure 1 shows an application configuration and process steps.


Figure 1: Click-to-dial System Configuration and Process Steps

  1. User A displays the address book (or the buddy list).
  2. User A checks that User B already starts the SIP phone on the presence display.
  3. User A clicks the link to User B. The Web browser then sends an HTTP request to the HTTP servlet (Struts Action). Struts Action invokes the method on the 3PCC servlet to request start of the 3PCC call flow.
  4. The 3PCC servlet establishes a SIP session between User A and User B.
  5. User A and User B start real time communication with one another.

Figure 2 shows the sequence of the above procedure at SIP and HTTP protocol levels. Note that this call flow is based on a sequence called Type 1.


Figure 2: Sequence of Click-to-dial Procedure

Action Class

This application implements an application-specific Action class (DialAction) that inherits the BasicSipAction class. This Action class is invoked when an HTTP request is received, and used to extract party information from an HTTP form and start a 3PCC servlet. Figure 3 shows communication between DialAction and 3PCC.


Figure 3: Communication between DialAction and 3PCC

List 1 shows the source code of the DialAction class. Main parts of this implementation are described below.

  • The caller (caller) and receiver (callee) in this 3PCC process are specified in the HTTP form. This code extracts this information from the HTTP request.
  • Next, it uses location management function to take contact information about the target user. In this example, only one entry is randomly taken if multiple registrations exist. You should use preference and application-specific selection logic to determine a destination terminal.
  • When required information is collected to start the 3PCC process, it starts the SIP servlet (CallControlServlet). The SIP servlet is started using request redirection (SipRequestDispatcher.invoke). In this example, it is assumed that CallControlServlet is registered with the servlet context under the name "caller". Note that the event listener (ProgressMonitor) is registered to monitor the progress of call control. This listener stores call back information (CallingProgress) from CallControlServlet in the HTTP session. When call control is completed, it deletes the information from the session in five seconds.

List 1: DialAction Class

package com.oki.sip.apps.demo.action;

/**
 * Struts Action to start 3PCC.
 * After the process has started, monitors the progress and stores it in the session information.
 */
public class DialAction extends BasicUserAction
    implements SipConstants, CallControlConstants, RecorderConstants
{
    public static final String SATTR_CALLING_PROGRESS = "3pcc.progress";
    public static final String SATTR_CALLING_DUMMY = "3pcc.dummy";

    public ActionForward execute(ActionMapping mapping,
                                 ActionForm form,
                                 HttpServletRequest request,
                                 HttpServletResponse response) 
        throws Exception
    {
        HttpSession session = request.getSession();
        ServletContext context = session.getServletContext();

        // Obtains caller and callee information from Form.
        String formCallerURI = (String) PropertyUtils.getSimpleProperty(form, "caller"));
        String formCallerDisp = (String) PropertyUtils.getSimpleProperty(form, "dispCaller");
        SipURI callerURI = (SipURI) createURI(context, formCallerURI);
        CallingEntity caller = new CallingEntity(callerURI, formCallerDisp);

        String formCalleeURI = (String) PropertyUtils.getSimpleProperty(form, "callee"));
        String formCalleeDisp = (String) PropertyUtils.getSimpleProperty(form, "dispCallee");
        SipURI calleeURI = (SipURI) createURI(context, formCalleeURI);
        CallingEntity callee = new CallingEntity(calleeURI, formCalleeDisp);

        // Sets Contact for each.
        LocationEditor locationMgr = getLocationEditor();

        List clist = locationMgr.getContactList(callee.getSipURI(), null);
        caller.setContact((Address) clist.get(0));

        clist = locationMgr.getContactList(callee.getSipURI(), null);
        callee.setContact((Address) clist.get(0));

        // Starts CallControlServlet via SipRequestDispatcher.
        ServletContext context = session.getServletContext();
        SipRequestDispatcher dispatcher = SipRequestDispatcher.getInstance(this, context, "caller");
        SipRequestParams params = new SipRequestParams();
        params.setParam(RATTR_3PCC_FLOW, new Integer(1));
        params.setParam(RATTR_3PCC_TIMEOUT, new Integer(120));
        params.setParam(RATTR_3PCC_CALLER, caller);
        params.setParam(RATTR_3PCC_CALLEE, callee);
        params.setParam(RATTR_3PCC_MONITOR, new ProgressMonitor(session));
        
        CallingProgressHandler handler =
            (CallingProgressHandler) dispatcher.invoke("makeCall", params);

        // Stores handler in session for processing cancel.
        session.setAttribute("call.handler", handler);

        // Finishes the process.
        return mapping.findForward("success");
    }

    /**
     * Listener that receives status change event of 3PCC.
     */
    private class ProgressMonitor implements CallingProgressListener {

        private HttpSession session;

        private ProgressMonitor(HttpSession session) {
            this.session = session;
        }

        public void statusChanged(CallingProgress progress) {
            // Stores it in the HTTP session to send the progress to JSP.
            session.setAttribute(SATTR_CALLING_PROGRESS, progress);

            if(progress.isDone() || progress.isInitiated()) {
                // Operates session attribute in another thread to avoid blockage of call process.
                new Thread() {
                    public void run() {
                        try {
                            // Blocks the process to display the last dialog for five second.
                            sleep(5000);
                        } catch(Exception e) {
                        }
                        // Removes attribute information from the HTTP session to notify the process completion.
                        clearSession(session);
                    }
                }.start();
            }
        }
    }
}

By using an event from CallControlServlet, you can create a dialog (progressMonitor.jsp) that displays the progress of call control. This dialog is started in another window immediately after 3PCC is started. It then accesses the Web server at regular intervals to update the progress. When the progress information disappears from the HTTP session, it automatically closes the window to finish the process.

Web browsers can not receive events directly like SIP. Therefore, the dialog must access the server as described above and check status changes.

List 2: progressMonitor.jsp File

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<%@ page contentType="text/html; charset=euc-jp" >
<%@ page errorPage="showError.jsp?action=close" %>

<%@ page import="com.oki.sip.equips.signal.CallingProgress" %>
<%@ page import="com.oki.sip.apps.demo.action.DialAction" %>

<%
    CallingProgress progress =
        (CallingProgress) session.getAttribute("3pcc.progress");
    if(progress == null) {
        Thread.yield();
        Thread.sleep(1000);
        progress = (CallingProgress) session.getAttribute("3pcc.progress");
        if(progress == null) {
%>
    <html>
      <body>
        <script>window.close();</script>
      </body>
    </html>
<%
            return;
        }
    }
%>

<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=euc-jp">
    <meta http-equiv="Expires" content="0">
    <meta http-equiv="max-age" content="0">
    <title><%= progress.getCalleeURI() %> Calling to... </title>
    <script language="JavaScript" type="text/javascript">
    </script>
  </head>

  <body>

    <center>
      <table border="0" width="80%">
        <tr>
          <td>
            <%= progress.getMessage() %>
          </td>
        </tr>
        <tr>
          <td>
<%  if(progress.getStatusCode() > 0) { %>
            (<%= progress.getStatusCode() %>
             <%= progress.getReasonPhrase() %>)
<%  } else { %>
            
<%  }  %>
          </td>
        </tr>
        <tr>
          <td align="left">
            <img src="dot-progress.gif" height="16"
                 width="<%= progress.getPercent() %>%">
          </td>
        </tr>
        <tr>
          <td>
<% if(! progress.isInitiated()) { %>
            <form action="<%= request.getContextPath() %>/cancelDial.do"
                  onsubmit="javascript:cancelDial()">
            <input type="submit" value="Cancel">
            </form>
<% } %>
          </td>
        </tr>
      </table>
    </center>

  </body>
</html>

Last Modified:Wed Jan 12 19:42:20 JST 2005