CAA Web Services Home

 

Maintaining the Session State

Sharing the same session while consuming one or several ENOVIA LCA V5 CAA Web services
Use Case

Abstract

Applications built on top of ENOVIA LCA V5 CAA Web services must maintain a session state across multiple requests from the same client. This article describes how to perform this task when using the Axis SOAP runtime.


Need for Web Service Conversation

ENOVIA LCA V5 CAA Web services can be combined together in order to build loosely coupled applications that communicate with ENOVIA LCA V5. The first requirement consists in establishing a session between a client instance and a target ENOVIA LCA V5 server instance. The client first logs in to the server with a given role through the use of the ENOPosApplicationBinderImpl CAA Web service [1]. The opened session can then be used to interact with ENOVIA LCA V5 through the other available ENOVIA LCA V5 CAA Web services. They allow to perform various types of integration scenarios such as lifecycle management, query, concurrent engineering, document management, change management, and product structure management.

CAA Web services communicate with client applications through SOAP messages conveyed by the standard HTTP protocol which is stateless by nature. In such context, each HTTP request-response cycle is independent and isolated. But when a Web server replies to a request, it usually includes additional information in the headers of the HTTP response. The response includes one or more cookie headers (when enabled). As a result, the client can use a cookie in order to identify itself to the server for subsequent calls, so that the server knows which session to associate with the incoming request. The exact cookie used for that purpose is described further below.

When consuming ENOVIA LCA V5 CAA Web services, it is mandatory to maintain a session throughout a cycle of interactions between a client instance and the target ENOVIA LCA V5 server instance proceeding the requests. The purpose of this article is to provide a way to perform this task with the Axis SOAP runtime.

[Top]

Consuming Multiple ENOVIA LCA V5 CAA Web Services With Axis

When consuming multiple CAA Web services with Axis, it is required to generate a Java client binding [2] for each Web service participating in the integration scenario. Among the generated classes, one can be used to invoke methods on the remote CAA Web service by marshalling/demarshalling SOAP messages. Upon generation, this class is the one named with the suffix "Stub", but it will be further referred to as the proxy in the rest of this article, as it best describes its purpose.

Upon generation, all the proxies are independent from one another. From the server perspective, each call performed with a given proxy is interpreted as coming from an isolated client instance. By default, no session state is maintained while using multiple proxies combined together in an attempt to perform a given integration scenario.

The Axis SOAP engine provides an open architecture allowing to create custom handlers that can be used to modify both the HTTP headers and the SOAP message content. By writing a dedicated handler class and configuring it to be used for each of the proxies participating in the integration scenario, the client can use one of the cookies sent back by the Web server to maintain the HTTP session state throughout its requests. A sample of such handler class is given further below.

[Top]

Step-by-step Maintaining the Session State

The first task consists in writing a custom session handler class in order to extract the JSESSIONID cookie from the HTTP response sent back by the Web server and use it for all subsequent requests from the same client. The second task requires to configure the Axis SOAP engine so that it uses this handler with each generated proxy participating in the integration scenario. These steps are described in the following sections:

  1. Writing a Custom Session Handler
  2. Configuring the Generated Proxy
  3. Using the Axis TCP Monitor to Analyze the HTTP SOAP Transport

Writing a Custom Session Handler

The use of the sample class detailed in this section is demonstrated in all of the use cases describing how to consume the available ENOVIA LCA V5 CAA Web services. The custom session handler class itself can be found in the CAAJAXRPCHTTPSessionHandler.mj module of the CAAWebServices.edu framework, at the following location:

Windows: <Install-root-directory>\CAAWebServices.edu\CAAJAXRPCHTTPSessionHandler.mj\src\Package\CustomSessionHandler.java
Unix: <Install-root-directory>/CAAWebServices.edu/CAAJAXRPCHTTPSessionHandler.mj/src/Package/CustomSessionHandler.java

The following class can be used to maintain the HTTP session state:

public class CustomSessionHandler implements Handler {
  public static String HEADER_COOKIE = "Cookie";
  public static String CLIENT_ID = "ClientID";
  private static Map clientIdToHttpSession = new HashMap();
  private String clientId = null;

  /**
   * @see javax.xml.rpc.handler.Handler#handleRequest(javax.xml.rpc.handler.MessageContext)
   */

  public boolean handleRequest(MessageContext messageContext) {
    if (clientId == null) {
      return false;
    }

    SOAPMessageContext ctx = (SOAPMessageContext) messageContext;
    Object headerCookie = clientIdToHttpSession.get(clientId);

    String property = null;

    if (headerCookie != null && headerCookie instanceof String[]) {
      String[] values = (String[]) headerCookie;
      System.out.println("Reading cookies from memory. Client ID: " + clientId);

      StringBuffer params = new StringBuffer();
      for (int i = 0; i < values.length; i++) {
        if (i != 0 && i <= (values.length - 1)) {
          params.append("; ");
        }
          params.append(values[i]);
      }

      if (values.length > 0) {
        property = params.toString();
      }
    }

    if (property != null) {
      System.out.println("Setting cookies on HTTP request: " + property);
      ctx.setProperty(CustomSessionHandler.HEADER_COOKIE, property);
    }

    return true;
  }

  /**
   * @see javax.xml.rpc.handler.Handler#handleResponse(javax.xml.rpc.handler.MessageContext)
   */

  public boolean handleResponse(MessageContext messageContext) {
    if (clientId == null) {
      return false;
    }

    SOAPMessageContext ctx = (SOAPMessageContext) messageContext;
    Object headerCookieProperty = ctx.getProperty(CustomSessionHandler.HEADER_COOKIE);

    if (headerCookieProperty != null && headerCookieProperty instanceof String[]) {
      String[] cookies = (String[]) headerCookieProperty;
      System.out.println("Reading " + cookies.length + " cookies from HTTP response");

      boolean newHttpSession = false;
      for (int i = 0; i < cookies.length; i++) {
        System.out.println("Cookie[" + i + "]: " + cookies[i]);

        if (cookies[i].startsWith("JSESSIONID")) {
          // If timeout occurs on the server side, the JSESSIONID
          // coookie has to be updated with the newly generated value

          newHttpSession = true;
        }
      }

      if (newHttpSession) {
        System.out.println("Storing cookies in memory. Client ID: " + clientId);
        clientIdToHttpSession.put(clientId, cookies);
      }
    }

    return true;
  }

  /**
   * @see javax.xml.rpc.handler.Handler#handleFault(javax.xml.rpc.handler.MessageContext)
   */

  public boolean handleFault(MessageContext arg0) {
    return true;
  }

  /**
   * @see javax.xml.rpc.handler.Handler#init(javax.xml.rpc.handler.HandlerInfo)
   */

  public void init(HandlerInfo info) {
    Map config = info.getHandlerConfig();
    if (config != null) {
      clientId = (String) config.get(CustomSessionHandler.CLIENT_ID);
    }
  }

  /**
   * @see javax.xml.rpc.handler.Handler#destroy()
   */

  public void destroy() {
  }

  /**
   * @see javax.xml.rpc.handler.Handler#getHeaders()
   */

  public QName[] getHeaders() {
    return new QName[0];
  }
}

Warning: Please note that this class is provided as a sample reference only and may not be appropriate to any type of client application. It may be improved in order to support more complex scenarios than the ones provided with the use cases. These use cases are only intended to describe how to consume CAA Web services with Axis from a simple stand-alone Java application.

The javax.xml.rpc.handler.Handler interface is required to be implemented by a SOAP message handler. The handleRequest, handleResponse and handleFault methods have access to the SOAPMessage from a SOAPMessageContext instance. The implementation of these methods can modify the SOAP message including the headers and body elements. The main methods implemented on the sample custom handler are handleRequest and handleResponse:

Configuring the Generated Proxy

Every available CAA Web service use case relies on a wrapper class that demonstrates the use of the proxies generated using the WSDL2Java emitter tool. Each proxy has a handler chain that must be configured in order to add the custom session handler so that it gets invoked by the Axis SOAP engine at runtime. It ensures that the session state will be maintained throughout requests performed from the configured proxy, but also throughout requests coming from other proxies configured with the same pattern.

The code below provides an example of how to configure the proxy for the ENOPosApplicationBinderImpl CAA Web service use case [1]:

public class CAAENOPosApplicationBinderImplWrapper {
...
  public CAAENOPosApplicationBinderImplWrapper(
    String clientId,
    String uri,
    String credUser,
    String credPwd,
    int timeOut) {
    ...

    if (clientId != null) {
      // Required to maintain HTTP session state accross services
      HandlerInfo info = new HandlerInfo();
      info.setHandlerClass(CustomSessionHandler.class);
      Map handlerConfig = new HashMap();
      handlerConfig.put(CustomSessionHandler.CLIENT_ID, clientId);
      info.setHandlerConfig(handlerConfig);

      HandlerRegistry registry = locator.getHandlerRegistry();
      String portName = locator.getENOPosApplicationBinderImplPortWSDDServiceName();
      QName name = new QName(portName);
      List chain = registry.getHandlerChain(name);
      chain.add(info);
    }
  }
}

Using the Axis TCP Monitor to Analyze the HTTP SOAP Transport

The Axis toolkit provides a utility that can be used to monitor both SOAP messages and related HTTP headers content. This may come in handy when trying to maintain the HTTP session state, as it provides a way to ensure the proper use of the JSESSIONID cookie required to keep track of a client session.

You can refer to the "Appendix : Using the Axis TCP Monitor (tcpmon)" section of the Axis User's Guide for a detailed description of how to use the Axis TCP Monitor utility. The Axis 1.3 User's Guide can be accessed at the following location: <Axis-unzipped-folder>\axis-1_3\docs\index.html.

The picture below shows an example of client/server interactions that are tracked down through the Axis TCP Monitor utility:

Fig.1: Axis TCP Monitor Tool
Axis TCP Monitor Tool

[Top]


In Short

ENOVIA LCA V5 CAA Web services enable middleware oriented integration of ENOVIA LCA V5 with other Dassault Systemes products and third-party enterprise applications. In order to achieve these type of integration scenarios, the available CAA Web services must be combined together, starting with the creation of a session between a client instance and a target ENOVIA LCA V5 server instance. It is then required to use this HTTP session scope for all requests coming from the same client instance.

While the available use cases describe in details how to generate and use the Java client bindings required to consume CAA Web services with Axis, this article focused on how to maintain the HTTP session state with the use of the open handler architecture provided by the Axis SOAP engine.

[Top]


References

[1] Consuming the ENOPosApplicationBinderImpl CAA Web Service
[2] Generating a Java Client Binding
[Top]

History

Version: 1 [Apr 2005] Document created
Version: 2 [Jan 2006] Document updated
[Top]

Copyright © 1994-2006, Dassault Systèmes. All rights reserved.