Converged HTTP/SIP Web Services in Webphere

Digg this!

Work's been keeping me very busy lately. So, I plan on writing about a commonly asked question around the new converged HTTP/SIP capabilities in WebSphere Application server (WAS) V6.1. So first, what is a converged service? A converged service is an application that spans communication over multiple protocols to provide higher level function. In the case of the HTTP & SIP protocols, a converged service joins together session information from both protocols, allowing interactions over one protocol to influence communication over the other (subjects to the constraints of the protocol). WAS provides a Servlet programming model for both HTTP & SIP. Unification of those protocols is achieved though a converged web container solution, whereby sessions for both protocols may live in a single parent "application session" instance under the covers -the application session concept being first introduced as a SIPApplicationSession concept in the JSR116 SIP Servlet programming model.

The basic benefit to converged services? For SIP enabled applications, HTTP provides an ideal control protocol for communication with SIP signaling logic, which may participate in many different sessions, and may be constantly sending and receiving signaling messages asynchronously out the back-end. However, SIP also supports the notion of a basic request and response exchange, so what makes HTTP so ideal? First, you don't have to deal with the unreliability in SIP in a situation where decisive action is needed. But then enter Web Services. Central to Web Services is the notion of a Web Service Definition Language (WSDL) document that describes the structure of the request being issued. While you can always stuff a bunch of XML into an HTTP or SIP request to communicate with the application, WSDL provides the formal structure to allow you to communicate that interface to others. This approach also provides a path to interoperability with other programming stacks.

So back to getting up and running with converged web services. Today's most common paradigm for having Web Services in a J2EE environment is based on JSR109 JAX RPC specification. Some tooling parses the WSDL (WAS provides a tool called WSDL2JAVA) and generates either client-side or server-side stubs for packaging in the application. The service developer then inserts his or her code into the "BindingImpl" piece of the server-side stub. The goal of JSR109 was to isolate the developer from the details of Web Service interactions and provide them with an environment that looks a little more like Java. So, a little extra knowledge is required to enable a JSR109 binding to work with converged HTTP/SIP communications.

The following is a code example that shows you how to get access to SIP facilities and converged information from a JSR109 Web Service stub.

...
import javax.xml.rpc.server.ServiceLifecycle;
import javax.xml.rpc.server.ServletEndpointContext
...

public class MyServiceBindingImpl
  implements MyService, // This is base interface that represents the WSDL interface in Java
             ServiceLifecycle { // This allows you to access container information

  private ServletEndpointContext endptCtx = null;

  private SipFactory sipFactory = null;

  /**
   * This method is called before each invocation by the JAX RPC runtime as part of the
   * ServiceLifecycle interface. The API says to cast the context to a
   * ServletEndpointContext object inside init. This lets you get at web container facilities.
   */
  public void init(Object context) throws ServiceException {
    endptCtx = (ServletEndpointContext)context;
    ServletContext srvCtx = endptCtx.getServletContext();
    sipFactory = (SipFactory)srvCtx.getAttribute(SipServlet.SIP_FACTORY);
  }

  /**
   * Also part of ServiceLifecycle interface.
   */
  public void destroy() {

  }

  /**
   * This gets you access to the shared application session parent object of the
   * HTTP session and corresponding SIP sessions.
   */
  private IBMApplicationSession getIBMApplicationSession() {
    IBMSession session = (IBMSession)endptCtx.getHttpSession();
    IBMApplicationSession appSession = session.getIBMApplicationSession();
    return appSession;
  }

  /**
   * This may seem a little more familiar.
   */
  private SipApplicationSesion getSipApplicationSession() {
    return (SipApplicationSession)getIBMApplicationSession();
  }

  public void myOperation(String someArg) {

    // Access the SIP factory if needed via the private member. This lets you
    // create new SIP messages.

    // Get at the SIP application session to see inter-protocol state information
    SipApplicationSession appSession = getSipApplicationSession();

    // Do good things

  }

}

This code example shows how to do two things from the Web Service side: (1) Get at the SipFactory object which is one entry point into the SIP Servlet API function. (2) Access application level information from within the SipApplicationSession. In addition, the SipApplicationSession lets you find session instances from both HTTP & SIP protocols.

However, a caveat: converged services require that the Web Service client maintain some state information in order to refer to the converged session (this makes sense - you have to find the session somehow). There are two ways of doing this: maintaining the HTTP session information between Web Service calls using cookies or URL rewriting, and encoding Web Service URIs with application session IDs. Maintaining HTTP session information can be accomplished by setting the javax.xml.rpc.Stub.SESSION_MAINTAIN_PROPERTY property on the client-side stub. URI encoding requires that the converged service return a the original endpoint URI of the Web Service with a special identifier encoded as a parameter in the URI. The Web Service client then needs to know to set that URI as the subsequent endpoint for its communications.

Some folks dislike this approach because it breaks the stateless model that is traditionally Web Services and increases complexity at the client. One way to get around this is to introduce a correlator within the Web Service interface. Then a fronting Web Service server stub can receive the request, extract the correlator, and use the correlator to determine the appropriate encoded URI to use to find the appropriate converged session. This last approach comes at the cost of increased latency for each invocation of the service. Such an approach may even require a database lookup to find the appropriate information to dispatch the request to the real handler of the service. Regardless of the approach used, there still has to be some tidbit of information that relates the request to the session.

JSR 289 kind of improves the situation

Many of the aspects of converged HTTP/SIP services within the WebSphere implementation are expanded and standardized within the upcoming JSR 289 release currently in early draft review. The particulars of accessing the converged session and SipFactory from the post will remain valid going forward, especially the need to use the ServiceLifecycle interface. Within WebSphere 6.1 at least, gaining access to the SipFactory through the ServletContext may require the JSR 109 web.xml servlet listing to appear in sip.xml as well. That sip.xml entry is required so that the WebSphere SIP Container knows to insert the SipFactory into the ServletContext at runtime. Also interesting is that retrieving the IBMApplicationSession from the HttpSession causes the HttpSession to have the same duration/expiration/etc semantics as the IBMApplicationSession which isn't always what one would hope...