Building converged Web services with WebSphere Application Server

Convergence of telecommunications with the World Wide Web is a major driving force behind the development of many new and interesting applications. The lines between these two traditionally isolated worlds is blurring due to IETF-developed protocols like SIP and new programming models like JSR 289, which enable applications to simultaneously control the signaling between these two worlds. Through a sample application, this article illustrates how to develop a converged Web service using IBM® WebSphere® Application Server. This content is part of the IBM WebSphere Developer Technical Journal.

Brian Pulito (brian_pulito@us.ibm.com), WebSphere Architect - SIP, IBM

Author photoBrian Pulito began his career at IBM working in the Lotus organization on the Sametime product, specifically in the area of real-time collaboration. In an effort to move Sametime towards the use of standard protocols, he began working with the SIP protocol, which eventually found its way into WebSphere in the form of the JSR 289 SIP Servlet Container. Brian has lead in the development of both the JSR 289 container/proxy as well as the Communications Enable Application Feature Pack, which brings a simplified programming model to developers wishing to integrate communications into their web applications. Brian can be reached at brian_pulito@us.ibm.com.



Dustin Amrhein, Technical Evangelist, IBM

Author photoDustin Amrhein joined IBM as a member of the development team for the WebSphere Application Server. While in that position, Dustin worked primarily on web services infrastructure and web services programming models. In addition, Dustin worked on the development of a RESTful services framework for Java runtimes. In his current role Dustin is a WebSphere Client Technical Professional.



18 May 2011

Also available in Chinese Spanish

Introduction

Convergence of SIP and HTTP is encouraging the development of all kinds of new capabilities, including Web and mobile applications that contain rich communication features like click-to-call, presence monitoring, and third party call control. It is also having an impact and many different industries, enabling the development of all kinds of new features and services (Figure 1).

Figure 1. New communication features of converged applications
Figure 1. New communication features of converged applications

The latest SIP servlet specification, known as JSR 289, has taken great strides to standardize the programming model needed for the development of truly converged SIP/HTTP Web applications. IBM WebSphere Application Server initially released the JSR 289 compliant SIP container in the form of the Feature Pack for Communications Enabled Applications (CEA).

In addition to the development of converged applications, the JSR 289 programming model enables the development of converged Web services. A WSDL-based interface provides access to the converged Web service via SOAP over HTTP, and SIP is utilized on the back end.

This article provides the details on how to build a converged Web service. Specifically, the converged Web service sample outlined in this article provides an interface for subscribing on a presence entity and receiving notifications when attributes associated with the presence entity change. On the back end, the sample application converts the Web service request into an SIP subscription sent to a SIP presence server.

The converged Web service outlined in this article demonstrates many capabilities of the converged WebSphere Application Server container, including:

  • Converting a Web service request into an SIP subscription.
  • Establishing SIP application session affinity through a Web service.
  • Developing a bi-directional Web service needed to receive asynchronous notifications.
  • Programming a session-based Web service to support failover and redundancy.

The sample application

The sample application discussed in this article provides a Web service interface for presence subscriptions converged with an SIP user agent that forwards subscriptions and handles notifications to and from an SIP presence server. Figure 2 helps to illustrate this.

Figure 2. Converged application environment
Figure 2. Converged application environment

The sequence diagram in Figure 3 illustrates the complete messages flow implemented in the sample application.

Figure 3. The application message flow
Figure 3. The application message flow

(Be aware that this is just one possible way to implement the converged presence monitor. You could decide to eliminate the need for the sendNotification and simply have the presence monitor send the WS-notify messages whenever a NOTIFICATION message comes into the presence server.)


Building the Web service

This section describes how to build the Web services you need in your converged application. For this application, you will build two Web service endpoints and two Web service clients. You will use the JAX-WS (Java™ API for XML Web Services) programming model for your Web service endpoints and clients.

Building the converged service endpoint

To conserve space, only relevant code sections will be shown in the listings displayed throughout this article. However, the complete code for the sample application is included with this article for download.

  1. The first Web service endpoint will be a part of the converged service and will interact with the SIP service infrastructure. It will provide methods that expose message interactions with the SIP infrastructure including subscribe, unsubscribe, and sendNotifications. You will take the bottom up approach for building this JAX-WS Web service endpoint, which means you will start by simply coding your Web service implementation class. Listing 1 shows the class definition and relevant method definitions for the PresenceMonitor Web service implementation class.

    Listing 1. Web service implementation
    public class PresenceMonitor {	
    
    	public String subscribe(String presentity, String presenceServerAddress, 
    		String callbackEndpoint) {
    		...
    	}
    	
    	public String unsubscribe() {
    		...
    	}
    	
    	public String sendNotifications() {
    		...
    	}
  2. Next, you need to annotate the class in order to denote it as a JAX-WS Web service implementation. Listing 2 shows the annotations necessary for the PresenceMonitor class.
    Listing 2. Annotated web service implementation
    @WebService(name="PresenceMonitor", portName="PresenceMonitorPort")
    public class PresenceMonitor {
    
    	@Resource 
    	private WebServiceContext wscontext;
    
    	@WebMethod(operationName="subscribe", action="doSubscribe")
    	public String subscribe(String presentity, String presenceServerAddress, 
    		String callbackEndpoint) {
    		...
    	}
    	
    	@WebMethod(operationName="unsubscribe", action="doUnsubscribe")
    	public String unsubscribe() {
    		...
    	}
    	
    	@WebMethod(operationName="sendNotifications", action="sendNotifications")
    	public String sendNotifications() {
    		...
    	}

    You start by indicating that the class is a Web service implementation with the use of the @WebService annotation. On the @WebService annotation, you provide a name and a port name that you want to assign to the Web service. Next, you annotate each method we want to expose on the Web service with the @WebMethod annotation. On each @WebMethod annotation, you provide an operationName as well as an action name. You do not have to define any of the attributes on either the @WebService or @WebMethod annotations, as there are default values. You finish annotating your class by placing the @Resource annotation on a private instance variable of the javax.xml.ws.WebServiceContext type. This will result in the automatic injection of a WebServiceContext instance upon the instantiation of the PresenceMonitor class. You will see later that this enables you to retrieve HTTP and SIP session information within our PresenceMonitor implementation.

  3. With the annotations in place, you can use utilities in WebSphere Application Server to generate the required JAXB (Java Architecture for XML Binding) artifacts. The runtime uses these classes to unmarshal and marshal requests to and responses from your PresenceMonitor Web service.

    In order to generate these artifacts, you will use the wsgen tool that resides in the WAS_HOME/bin directory of your WebSphere Application Server installation. Listing 3 demonstrates running the wsgen utility on the PresenceMonitor implementation.

    Listing 3. Using the wsgen utility
    C:\was70dev\bin>wsgen.bat -cp c:\cea\sip\PresenceMonitorServerWAR\build\classes
    com.ibm.sample.presence.ws.PresenceMonitor -d .\wsserver -wsdl -keep

    First, you provide a classpath to the wsgen command using the –cp argument. The classpath must include any classes necessary to compile the com.ibm.sample.presence.ws.PresenceMonitor implementation class that you specify in the command. The –d argument provides the directory to which to write resource (WSDL and schema) and Java source files respectively. Finally, the –wsdl argument tells the wsgen utility to generate a WSDL (Web Services Description Language) file, and the –keep argument directs the utility to preserve all Java source files generated because of the command. Both –wsdl and –keep are optional, but they are utilized here to illustrate the outputs of the wsgen utility. Figure 4 shows a listing of the files generated and saved in the wsserver directory specified in the command.

    Figure 4. Files generated running wsgen on PresenceMonitor
    Figure 4. Files generated running wsgen on PresenceMonitor
  4. The Java classes are included in the com.ibm.sample.presence.ws.jaxws package along with the PresenceMonitor class in a WAR (Web Archive) file within the application. You call the WAR with the PresenceMonitor implementation the server WAR. Additionally, although WebSphere Application Server does not require it for JAX-WS Web services, you package the WSDL and XSD files within the WAR as well. Since you include the WSDL file in the WAR, you also update the @WebService annotation on the PresenceMonitor class to include a wsdlLocation attribute, as shown in Listing 4.

    Listing 4. Updated @WebService annotation on the PresenceMonitor class
    @WebService(name="PresenceMonitor", portName="PresenceMonitorPort", 
    wsdlLocation=”WEB-INF/wsdl/PresenceMonitorService.wsdl”)
    public class PresenceMonitor {

    The wsdlLocation attribute provides a relative location to the WSDL file from the root of the WAR. Per the value shown in Listing 4, you will place the WSDL file generated from running the wsgen utility in the WEB-INF/wsdl directory of the WAR file.

You are done with the PresenceMonitor implementation for now. You now need to build the Web service client that will enable you to call the methods of the PresenceMonitor implementation.

Building the web service client

In order to build the Web service client for the PresenceMonitor implementation, you will use another utility included in your WebSphere Application Server installation called wsimport. The wsimport utility uses a WSDL file to generate Web service client artifacts. You use the PresenceMonitorService.wsdl file generated previously by the wsgen utility. Listing 5 shows the command for running the wsimport utility.

Listing 5. Running the wsimport utility
C:\was70dev\bin>wsimport.bat wsserver\PresenceMonitorService.wsdl -d wsclient –p 
com.ibm.sample.presence.jaxws.client –keep
  1. Run the wsimport utility and pass in the previously generated WSDL. The –p argument provides a package name to use for all generated Java classes. Again, the –d argument specifies where to put the generated artifacts, and the –keep directs wsimport to save all generated source files. Figure 5 shows a listing of the wsclient directory.

    Figure 5. Files generated running wsimport on PresenceMonitorService.wsdl
    Figure 5. Files generated running wsimport on PresenceMonitorService.wsdl
  2. You put these classes, along with your client application code, into a separate WAR file, which will be referred to as the client WAR. Your client application code will utilize these classes in order to issue remote calls to the Web service methods exposed by the PresenceMonitor implementation class. In particular, your client application code will use the client service and port classes --com.ibm.sample.presence.jaxws.client.PresenceMonitorService and com.ibm.sample.presence.jaxws.client.PresenceMonitor, respectively -- in order to send Web service requests and receive Web service responses. You will see the client application code that initiates these requests a little later.

With the converged Web service implementation and corresponding Web service client built, you only have one more Web service implementation to construct.

Building the listener endpoint

In the PresenceMonitor Web service endpoint implementation, there is a sendNotifications method. That method contains logic to send SIP event notifications to a listening Web service endpoint. In that respect, the PresenceMonitor implementation you previously built is not only an endpoint, but it also a Web service client. Now, you need to build the Web service endpoint that will act as the notification listener.

  1. Name the listener Web service class PresenceListener. Listing 6 shows the class and its relevant Web service annotations.
    Listing 6. PresenceListener web service implementation
    @WebService(name="PresenceListener", 
    		serviceName="PresenceListenerService", 
    		portName="PresenceListenerPort", 
    	   targetNamespace="http://listener.ws.presence.sample.ibm.com/”)
    public class PresenceListener {
    	
    	@Resource
    	private WebServiceContext wsContext;
    	
    	@WebMethod
    	public void notify(Event event) {
    		…
    	}

    The PresenceListener implementation exposes a single method called notify which accepts an instance of the Event Java bean. This is the method used by the PresenceMonitor to send notification of an SIP event. We will revisit the logic within the notify method. As you did with the PresenceMonitor implementation, you run the wsgen utility on the PresenceListener class in order to generate the necessary JAXB artifacts. Figure 6 shows the resulting files from running the wsgen utility on the PresenceListener endpoint.

    Figure 6. Files generated running wsgen on PresenceListener
    Figure 6. Files generated running wsgen on PresenceListener

    Place the PresenceListener implementation class and the classes shown in Listing 6 into the client WAR.

  2. To complete building your Web services assets for your application, you need to generate a Web service client for the PresenceListener endpoint implementation. As you did earlier, simply run the wsimport utility on the WSDL file generated by the previous wsgen command. That means you run the wsimport utility on the PresenceListenerService.wsdl file. Figure 7 shows the result of the wsimport command.

    Figure 7. Files generated running wsimport on PresenceListenerService.wsdl
    Figure 7. Files generated running wsimport on PresenceListenerService.wsdl
  3. Place the files shown in Figure 7 into the server WAR so that the PresenceMonitor can act as a Web service client to your PresenceListener implementation.

You now have the necessary Web service endpoint and client assets. It is time to put the rest of the application together. We will look at the required SIP functionality as well as the logic required by your client.


The converged presence monitor server

After you create the Web service, you move to building out the remaining classes that make up the presence monitor. The class diagram in Figure 8 shows all the major classes that make up the presence monitor.

First, the Web service class that receives all the inbound requests is the PresenceMonitor, as described above. You can see here that the PresenceMonitor uses a class called the PresenceSession. The PresenceSession is the convergence point between Web service activity and SIP activity. There is a one-to-one mapping of PresenceSession objects to SIP Application Session (SAS) objects. In fact, the PresenceSession object is stored as an attribute in the SAS. This diagram also shows the PresenceSipServlet which handles all inbound SIP requests, and also uses the PresenseSession object.

Figure 8. Sample application class diagram
Figure 8. Sample application class diagram

PresenceMonitor

As described above, the PresenceMonitor is the main server class that handles the Web service requests. An important aspect of the PresenceMonitor is how it establishes a client session and how that session gets associated with an SIP application session. The code in Listing 7 (with logging removed) shows how an SIP application session is derived from the Web service subscribe.

Listing 7. Establishing a client session in the PresenceMonitor class
WebMethod(operationName="subscribe", action="doSubscribe")
public String subscribe(String presentity, 
String presenceServerAddress, 
String callbackEndpoint) {

	String msg = "";
	try {
		HttpServletRequest httpRequest = (HttpServletRequest)wscontext.
			getMessageContext().get(MessageContext.SERVLET_REQUEST);
	
		PresenceSession presenceSession;
			
		presenceSession = findExpectedPresenceSession(httpRequest);
			
		if (presenceSession != null)
		{
			msg = "Subscription already sent for this session";
		}
		else 
		{				
			HttpSession httpSession = httpRequest.getSession();
	    		SipApplicationSession appSession = ((javax.servlet.sip.
				ConvergedHttpSession)httpSession).getApplicationSession();
				
//	create the web service session to handle this traffic and save it as an 
//	attribute of the app session
			presenceSession = new PresenceSession(appSession, 
				callbackEndpoint);
appSession.setAttribute(PresenceSession.ATTRIBUTE_PRESENCE_SESSION, 
	presenceSession);
…

Whenever code pulls an SIP application session from an HttpServletRequest, as is shown above, the Web container automatically inserts a converged cookie into the HTTP response used to send the SOAP response. The Web services client can then use this cookie to maintain session affinity. The procedures for doing this are in the presence monitor client section.

PresenceSession

The PresenceSession is the class that converts SIP presence notifications into outbound Web service notifications. When the sample application receives a new subscribe, the PresenceMonitor creates a new PresenceSession instance and stores it as an SIP application session attribute. The PresenceSession maintains a queue of SIP notifications that it passes back to the client through Web services.

The PresenceSession uses two important methods for providing the interaction between Web services and SIP. The Web service sendNotifications method calls the getNotifyEvent on the PresenceSession associated with the Web service session. The getNotifyEvent method then checks the queue for any new SIP notifications. If one exists, the PresenceSession calls the notify method of the associated PresenceListener to deliver the notification. If the queue is empty, a Boolean is set to true indicating that the next time a notification is received it should be immediately sent back to the associated PresenceListener through the notify method.

Whenever a new SIP notify is received by the PresenceSipServlet, the servlet pulls the associated PresenceSession from the SIP application session and calls its putNotifyEvent method. This either triggers the notification to be added to the queue or causes the PresenseSession to send the notify onto the client through the Web service interface.

PresenceSession

The PresenceSipServlet is mainly used to handle notifies received from the presence server. It also handles the responses from the SUBSCRIBES that are sent out. The sample application utilizes SIP annotations instead of an sip.xml deployment descriptor.

Listing 8 shows how to access the PresenceSession associated with the notification sent from the presence server:

Listing 8. Accessing the PresenceSession associated with a notification
@protected void doNotify(SipServletRequest req) throws ServletException,
		IOException {

	//	First, we access the PresenceSession object associated with this 
	//	notification. The PresenceSession is where notification event are 
	//	queued and picked up through the Web Service interface.
	SipApplicationSession appSession = req.getApplicationSession();
	PresenceSession presenceSession = (PresenceSession)appSession.getAttribute
		(PresenceSession.ATTRIBUTE_PRESENCE_SESSION);
	…

The presence monitor client

The presence monitor client tests the presence monitor server application. It converts HTTP requests into outbound Web services requests. It also handles inbound Web service notification requests sent from the presence monitor server.

The presence monitor client is quite simple. The class diagram in Figure 9 below shows its main classes, other than the Web services classes.

Figure 9. Presence monitor client class diagram
Figure 9. Presence monitor client class diagram

The TestServlet handles the inbound HTTP request and uses instances of the ClientController to make its Web service requests. A client ID is passed in the HTTP request to map to existing sessions and there is a one-to-one mapping of client IDs to ClientControllers. The PresenceListener is a Web services server and it receives notifies from the presence monitor server, which it stores in a queue.

This code from the ClientController in Listing 9 shows the establishment of the Web service port during the initial subscribe. This port is mapped to the client ID that is passed in the query string of the HTTP subscribe request. (See the Test environment section.) The important point to take away here is the method used to establish session affinity. Putting the SESSION_MAINTAIN_PROPERTY on the request context associated with the port insures that any cookies returned in the HTTP SOAP response are used in subsequent HTTP SOAP request initiated from this port. This insures proper affinity to the SIP application session at the presence monitor server.

Listing 9. Ensuring affinity in the subscribe method
public String subscribe(String presentity, 
String presenceServerAddress, 
				String callbackEndpoint) {
	String msg = "";
	try {
		if(port == null) {
			String wsdlURLStr = webServiceURL + "?wsdl";
			System.out.println("wsdlURLStr is " + wsdlURLStr);
			if(!wsdlURLStr.startsWith("http://")) {
				wsdlURLStr = "http://" + wsdlURLStr;
			}
			URL wsdlURL = new URL(wsdlURLStr);
			PresenceMonitorService svc = new 
PresenceMonitorService(wsdlURL);
			port = svc.getPresenceMonitorPort();
			BindingProvider bp = (BindingProvider) port;

bp.getRequestContext().put(
BindingProvider.SESSION_MAINTAIN_PROPERTY, Boolean.TRUE);
		}			
		msg = port.subscribe(	presentity,
				presenceServerAddress, callbackEndpoint);
	}
	catch(Exception e) {
		throw new RuntimeException(e);
	}
	if (logger.isLoggable(Level.FINEST)) {
		 logger.exiting(className, "subscribe", port);
	}
	return msg;
}

Test environment

The test environment requires a single application server running WebSphere Application Server V7 with the CEA feature pack or WebSphere Application Server V8.0 beta 2 or higher. It also requires a single instance of sipp, which is an open source tool used to simulate an SIP user agent. In this case, a sipp script is used to simulate an SIP presence server. Lastly, you will need a browser to trigger the test and validate the results.

Install these applications on either the same or two different application servers:

  • PresenceMonitorClientWAR.war: This application includes a test servlet that converts HTTP requests into Web service requests to the PresenceMonitorServer. In other words, this is the Web services client described in the sequence diagram above.
  • PresenseMonitorServerWAR.war: This is the core code described above that exposes a Web service interface on one side and an SIP interface on the other.

Start the applications and the sipp client after installing. A batch file used to start the sipp client is included.

The following steps describe how to execute the test code once installed and running. (This example assumes that both applications are running on the same application server instance.)

  1. This URL tells the presence monitor client (PMC) via an HTTP request to open a subscription via a Web service interface to the presence monitor server (PMS), which, in turn, creates a subscription to the presence server via SIP:

    http://<appserverhost:port>/PMC/testservlet?action=subscribe&id=1&presenceServerAddress=<sipphost:port>&presentity=Brian&wsURL=http:// <appserverhost:port>/PMS/PresenceMonitorService

    The appserverhost:port is going to be the WC_defaulthost chain configured for the application server.

    The parameters in the query string tell the client application what to do. Here are details on each parameter:

    • Action: The action to be taken by the client servlet. Choices include subscribe, sendNotifications, getNotifications, and unsubscribe.
    • Id: The ID of the client session. It would be easy to convert the client code to use a cookie to access an HTTP session.
    • presenceServerAddress: Passed across the Web services interface to the presence monitor server, this specifies where to send the SIP subscription. In a real world application, the presence monitor server would have a configuration item for this.
    • Presentity: The presentity string being subscribed on. The sipp script representing the presence server does not care what goes here.
    • wsURL: The URL used by the client to connect through Web services to the presence monitor server.
  2. Next, this URL tells the PMC to request any available notifications from the PMS by sending a Web services request to it. The PMS already has a subscription open to the presence server via SIP from step 1. http://<appserverhost:port>/PMC/testservlet?action=sendNotifications&id=1&presenceServerAddress=<sipphost:port>&presentity=Brian&wsURL=http://<appserverhost:port>/PMS/PresenceMonitorService
  3. This next URL retrieves any notifications received by the PMC from the PMS and displays them in HTML format: http://<appserverhost:port>/PMC/testservlet?action=getNotifications&id=1&presenceServerAddress=<sipphost:port>&presentity=Brian&wsURL=http://<appserverhost:port>/PMS/PresenceMonitorService
  4. This last URL tells the PMC via an HTTP request to unsubscribe to the PMS, which, in turn, sends a subscription with a 0 TTL to the presence server via SIP: http://<appserverhost:port>/PMC/testservlet?action=unsubscribe&id=1&presenceServerAddress=<sipphost:port>&presentity=Brian&wsURL=http://<appserverhost:port>/PMS/PresenceMonitorService

Be aware that the sample code delivered with this article is not for production use. The goal here is to provide only what was needed to explain the concepts described in this article. Therefore, important aspects of the code, such as session invalidation and support for failover, are not included.


Conclusion

This article described how you can build a converged Web service using WebSphere Applicaton Server. The example shown here included an interface for subscribing on a presence entity and receiving notifications when attributes associated with the presence entity change. On the back end, the sample application converted the Web service request into an SIP subscription sent to a SIP presence server. This example demonstrated many capabilities of the converged WebSphere Application Server container, and should be a good starting point for you to build your own converged applications.


Download

DescriptionNameSize
Sample application1105_pulito_sampleapp.zip106KB

Resources

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into WebSphere on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=WebSphere, Web development, SOA and web services
ArticleID=659571
ArticleTitle=Building converged Web services with WebSphere Application Server
publish-date=05182011