http://www.developer.com/

Back to article

Implementing Contextual Web Services


April 15, 2008

Overview

Web Services are a true interoperable technology that enables disparate systems to talk to each other using a common language. The Web Service consumers communicate to Web Services using SOAP messages transported over standard HTTP protocol. HTTP is a stateless protocol in nature, meaning that subsequent Web Service requests (for example, SOAP over HTTP) from the same user are considered as independent requests. The stateless behavior simplifies the design of HTTP protocol but this forces developers to use alternate methods such as cookies to maintain the user state. As the Web Services technology and the standards around it evolve more and more, the kind of application that the large enterprises implement using Web Services also tends to evolve. In the recent past, the use of Web Services has moved beyond simple laboratory services to highly advanced domain services. It will slowly become mandatory that Web Services understand the context under which the user operates to provide more sophisticated, user-centric personalized services.

A classic example where the context will play a major role is Business Activity Monitoring, one of the critical requirements of the complex business process manager. When the business transaction spans multiple Web Services and multiple machines, the application will require common information something like correlation id (in other words, typically a transaction id) that will be passed to all participating activities so that a real time summary is generated for operational purposes.

This article will discuss more about the need for context in Web Service end points and also give a glimpse on how Web Services can be enabled to gain access to Web Service context using vendor-specific API and standard JAX-RPC API.

The Need for Context Access in Service Endpoints

The Web Services technology already has something called handlers (also known as interceptors) that can gain access to context information. Handlers act as pre and post processors that intercept incoming Web Services requests, extract the context information, and implement the behaviors as per project requirements. For example, they implement non-functional requirements such as security. The handlers are really useful mechanisms because they are loosely coupled, non intrusive, and highly transparent.

However, in some scenarios, apart from handlers, the service end point objects (also known as back end components) also might want to access the context information such as message context, HTTP session objects, and so on. For example, consider this restaurant application that behaves differently for different user types. This restaurant application returns the list of a maximum of the three nearest restaurants in the given vicinity for the classic user type. Meanwhile, for the premium user type, the application returns, hypothetically, the unlimited list of nearest restaurants in the given vicinity. In this case, the end point object must know who the user is and the user type that it belongs to. Otherwise, it will not know whether to serve the limited list of restaurants or unlimited list of restaurants. Figure 1 depicts this scenario.

Figure 1: Contextual Services

One way to implementing this functionality could be that the user id and user type information may be passed as method arguments to Web Services. However, as you might notice, there are some quite obvious disadvantages with this approach:

  • The user will be expected to pass on the values for these arguments from the client side. In most cases, the user may not know what the values are. For example, the client application may not know what the user id is. (In most applications, the user will know only the alphanumeric username and it is the application's responsibility to fetch the corresponding user id and other necessary context information from the user store to respond to the clients as expected).
  • Some fields may be system generated and they are not relevant to users. For example, a transaction id would need to be generated.
  • When the application needs more and more information, the method signature will have to be modified accordingly. This will displease all stakeholders in the Web Services realm.

A Solution Explored

When there are several issues with passing the information as method arguments, there must be a way for the service end points to gain access to context information. JAX-RPC provides a mechanism for Web Service end point objects to access the context and HTTP session information. This feature will be available to developers who use the Servlets-based implementation of JAX-RPC runtime. For example, they can use Apache Axis. Non-Servlets-based runtimes, such as WebLogic 8.1, do not support this feature. As a workaround, WebLogic offers developers its vendor specific Application Programming Interfaces (API) to access the context information. However, from version 9.x onwards, WebLogic has changed its Web Services development model and hence it deprecated the use of all these APIs. The new development model (in 9.x onwards) is based on Servlets; therefore, it supports standard APIs provided by JAX-RPC. In the following sections, you will see how context can be accessed using standard and WebLogic APIs.

Accessing Context Using the WebLogic API

As mentioned earlier, the JAX-RPC runtime provided by WebLogic 8.1 was not based on Servlets; therfore, it implements the feature in slightly a different way. It provides an API called weblogic.webservice.context.WebServiceContext to access the Web Service context. The Web Service developer will have to invoke the static method, currentContext, on weblogic.webservice.context.WebServiceContext to obtain the reference to weblogic.webservice.context.WebServiceContext. For more information on Java documentation, please visit this URL http://edocs.bea.com/wls/docs81/javadocs/ weblogic/webservice/context/WebServiceContext.html.

The following code sample will provide a glimpse on how developers can use this API. This example program assumes (but code details of handlers are not mentioned here) the typical design, the Web Service will have handlers that collect the user credentials, perform security operations if required, fetch the user id from the database corresponding to the given username, and places the user id in the message context so that the user id information can be used in the service end point to decide the fate of the results to the user.

package service;

import javax.xml.rpc.handler.soap.SOAPMessageContext;

import weblogic.webservice.context.WebServiceContext;

public class RestaurantServiceBEA81{

   public String getRestaurants( int latitude, int longitude ) {
      try {
         WebServiceContext wsc =
            WebServiceContext.currentContext();

         SOAPMessageContext mcontext = wsc.getLastMessageContext();

      //Play with message context

         if( mcontext.containsProperty( "userId" ) ) {
         String userId = (String) mcontext.getProperty( "userId" );

         String userType = "Classic";

         //String userType = UserDAO.getUserType( userId );

         if( userType.equals( "Premium" ) ) {
            return "<Restaurants>" +
               "<Restaurant>Italiano</Restaurant>"     +
               "<Restaurant>Pizza Hut</Restaurant>"    +
               "<Restaurant>Mona Lisa</Restaurant>"    +
               "<Restaurant>Chili's</Restaurant>"      +
               "<Restaurant>Sushi Bistro</Restaurant>" +
               "<Restaurant>Naan-N-Curry</Restaurant>" +
               "</Restaurants>";
            }
         }

      }
      catch ( Exception ex ) {
         ex.printStackTrace();
      }


      return "<Restaurants>" +
             "<Restaurant>Italiano</Restaurant>"  +
             "<Restaurant>Pizza Hut</Restaurant>" +
             "<Restaurant>Mona Lisa</Restaurant>" +
             "</Restaurants>";
   }

}

Accessing Context Using Standard JAX-RPC API

The use of WebServiceContext API has been deprecated in WebLogic 9.2 onwards and the support for this API may be withdrawn at any time. From version 9.2 onwards, WebLogic has moved towards a Servlets-based JAX-RPC runtime; therefore, support for standard APIs are available now. Another important note is that the Web Service development model has been drastically changed in 9.2 when compared to its previous versions. It has adopted a Web Services annotations model to develop portable Web Services. For more information, please read JSR 181: Web Services Metadata for the JavaTM Platform and JSR 921: Implementing Enterprise Web Services.

The JAX-RPC specification provides an API, javax.xml.rpc.server.ServiceLifecycle, that defines the lifecycle of an endpoint. If the service end point implements this interface, the container is expected to manage the life cycle of the corresponding service end points. This interface has life cycle methods to initialize and destroy the service end points. Please find the method signature for the life cycle methods below:

/**
 * Used to initialize the service end point
 */
public void init ( Object contextObject ) throws ServiceException {

}

/**
 * JAX-RPC runtime system ends the lifecycle of a service
 * endpoint instance by invoking the destroy method
 */
public void destroy() {

}

In the ServiceLifecyle interface, the init method takes a single parameter of Java data type javax.xml.rpc.server.ServletEndpointContext. After the JAX-RPC runtime instantiates the service end point object, it invokes the init method by passing a javax.xml.rpc.server.ServletEndpointContext object. The ServletEndpointContext object provides the context maintained by the underlying Servlet container.

To illustrate the use of standard APIs, the earlier restaurant example has been recoded as below:

package service;

import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.xml.rpc.ServiceException;
import javax.xml.rpc.handler.MessageContext;
import javax.xml.rpc.server.ServiceLifecycle;
import javax.xml.rpc.server.ServletEndpointContext;

import weblogic.jws.WLHttpTransport;

@WebService( name="Restaurant", serviceName="Restaurant",
   targetNamespace="http://location.com/webservices" )


@SOAPBinding( style = SOAPBinding.Style.DOCUMENT,
   use = SOAPBinding.Use.LITERAL,
   parameterStyle   = SOAPBinding.ParameterStyle.WRAPPED )

@WLHttpTransport( contextPath="Restaurant",
                  serviceUri="Restaurant" )

public class RestaurantService implements ServiceLifecycle
{

   @WebMethod( operationName = "getRestaurants" )
   public String getRestaurants( int latitude, int longitude ) {

      if( servletEndpointContext != null ) {
         MessageContext mcontext =
            servletEndpointContext.getMessageContext();

         //javax.Servlet.http.HttpSession session =
           mcontext.getHttpSession();

         if( mcontext.containsProperty( "userId" ) ) {
         String userId = (String) mcontext.getProperty( "userId" );

            String userType = "Classic";

            //String userType=UserDAO.getUserType(userId);

            if( userType.equals( "Premium" ) ) {
               return "<Restaurants>" +
                  "<Restaurant>Italiano</Restaurant>"     +
                  "<Restaurant>Pizza Hut</Restaurant>"    +
                  "<Restaurant>Chili's</Restaurant>"      +
                  "<Restaurant>Sushi Bistro</Restaurant>" +
                  "<Restaurant>Naan-N-Curry</Restaurant>" +
                  "</Restaurants>";
            }
         }
      }

      return "<Restaurants>" +
                  "<Restaurant>Italiano</Restaurant>"  +
                  "<Restaurant>Pizza Hut</Restaurant>" +
                  "<Restaurant>Mona Lisa</Restaurant>" +
                  "</Restaurants>";
   }

   private ServletEndpointContext servletEndpointContext = null;

   public void destroy() {
      servletEndpointContext = null;
      System.out.println("Destroyed ServletEndpointContext");

   }

   public void init( Object contextObject )
         throws ServiceException {
      System.out.println(
         "Initializing ServletEndpointContext...");

      this.servletEndpointContext = 
         (ServletEndpointContext) contextObject;

      System.out.println("Initialized ServletEndpointContext");
   }

}

Conclusion

This article has discussed HTTP's stateless nature and how Web Services can be implemented by using vendor-specific and standard JAX-RPC interfaces to gain access to Web Service context and HTTP Session under which the user operates. The context enables developers to implement advanced domain services with several features such as personalization, versioning, security, mediation, and so on. However, developers should take due diligence before using any vendor-specific interfaces because they will put them in vendor lock-ins and perhaps cause inherent migration problems in the future.

References

About the Author

Ayyappan Gandhirajan is an Architect with Perot Systems, Bangalore, India. He has a Master's degree in Software Systems from BITS, Pilani, India and a Bachelors degree in Electronics & Communication Engineering from MK University, India. He has 10 years of profound software experience in Travel, Telecom/Mobility, Healthcare, and e-commerce domains using technologies such as SOA, ESB, Web Service, Web Service Security, and J2EE. Prior to Perot Systems, he worked with Hewlett-Packard, India for five years in Mobility & SOA. He can be reached at G_Ayyapparaj@yahoo.com or ayyappan.gandhirajan@ps.net.

Sitemap | Contact Us

Thanks for your registration, follow us on our social networks to keep up-to-date