Specifying SOAP Handlers for a Web Service

When designing a web service that accepts or returns SOAP messages, you may specify that the SOAP messages should be processed by message handlers. Handlers on incoming messages are invoked before the message is delivered to the web service operation, and handlers on outgoing messages are invoked after the web service operation has completed. The web service itself is unaware of the presence of handlers. SOAP message handlers are sometimes referred to as interceptors.

SOAP message handlers can be used for a variety of purposes. Examples include message logging, audit trails, and message transformations. Message handlers should not be used to implement security or encryption or to manage the redirection of messages; those facilities are provided by other mechanisms.

This topic contains the following sections:

JAX-RPC and SOAP Handlers

The standard Java interface to web services is called JAX-RPC, which stands for Java API for XML-Based Remote Procedure Calls. The term remote procedure call, or RPC, is a historical term that describes an application running on one machine invoking a procedure (a method) on another machine. Invoking a web service method is one form of a remote procedure call. The JAX-RPC API provides a Java interface that can be used by both a web service implementation and its clients to manipulate the underlying XML messages without having to be concerned with the details of the XML messages.

WebLogic Workshop leverages the classes defined in the message handler portion of the JAX-RPC API; specifically, the javax.xml.rpc.handler package. WebLogic Workshop provides annotations that allow you to easily specify the message handler(s) you would like to associate with a web service or Web Service control. The @jws:handler annotation is used to specify message handlers for JWSs, and the @jc:handler annotation is used to configure message handlers in Web Service control JCXs. The WebLogic Workshop runtime uses the annotations in a JWS or JCX file to automatically manage the message handlers.

Where Handlers Fit in the Message Path

Each web service or Web Service control may have a set of associated handlers.

The left column of the diagram below illustrates a message scenario in which the @jws:handler annotation is applied to the Web Service in the diagram. Invocation of a web service operation consists of an incoming request message followed by an outgoing response message. The scenario illustrates the case of three message handlers, A, B and C, specified in that order. Note the sequence in which incoming and outgoing messages encounter the handlers.

In WebLogic Workshop, web services may also define and invoke callbacks. A callback is a message to the client initiated by the JWS. In the case of a callback, the web service invokes a callback on the client by sending an outgoing request message and subsequently receiving an incoming response message.

The right column of the preceding diagram illustrates use of message handlers on a Web Service control. In this case, your code (a web service, business process or page flow) is the Client, and you are calling the Target Web Service via a Web Service control. Note the sequence in which incoming and outgoing messages encounter the handlers, and how it differs in the method invocation and callback cases.

JAX-RPC Specification

If you want to know more about the JAX-RPC Specification, visit the Java API for XML-Based RPC (JAX-RPC) page at java.sun.com.

The Handler Interface

The JAX-RPC API message handler interface is javax.xml.rpc.handler.Handler. When you design a handler, you define your own Java class that implements the javax.xml.rpc.handler.Handler interface. The Handler interface defines the following core methods:

The javax.xml.rpc.handler.Handler API specifies that the handleXxx methods take a javax.xml.rpc.handler.MessageContext as their argument type. In WebLogic Workshop, the arguments will in fact always be of the more specific type javax.xml.rpc.handler.soap.SOAPMessageContext. The SOAPMessageContext class provides access to all parts of the SOAP message.

weblogic.webservices.GenericHandler

The JAX-RPC API provides a generic handler from which you may derive your own handler classes. The JAX-RPC generic handler class is javax.xml.rpc.handler.GenericHandler.

WebLogic Server also provides a generic handler class that you may use as the basis for new handlers you create. The class is weblogic.webservices.GenericHandler. To learn more about the weblogic.webservices.GenericHandler class, see Creating SOAP Message Handlers to Intercept the SOAP Message.

Handler Chains

You may specify that more than one handler is associated with a particular web service. When multiple handlers are associated with one web service, the handlers form a handler chain. You may specify a handler chain using a handler configuration file, as is described in Specifying Handler Chains in a Handler Configuration File, below.

Note: the JAX-RPC API defines the javax.xml.rpc.handler.HandlerChain and javax.xml.rpc.handler.HandlerRegistry interfaces, which allow fine control over handler chains and the order of invocation of individual handlers in a chain. WebLogic Workshop 8.1, like most J2EE-based web service implementations, does not support the HandlerChain and HandlerRegistry interfaces.

Handler Annotations

In WebLogic Workshop, you associate message handlers with a web service using the @jws:handler annotation and you associate message handlers with a Web Service control using the @jc:handler annotation.

The @jws:handler annotation is applied to the class in a JWS file. The @jc:handler annotation is applied to the interface declaration in a Web Service control JCX file.

The @jws:handler and @jc:handler annotations have identical attributes:

Specifying Handlers Directly

You may specify handlers directly by setting the operation or callback attribute to a space-separated list of handler class names as shown in the following example:

  package handler;
  
  /**
   * @jws:handler operation="handler.ConsoleLoggingHandler"
   */
  public class HandlerExample1 implements com.bea.jws.WebService
  {
      static final long serialVersionUID = 1L;
	  
      /** @common:operation */
      public String echoString(String inputString)
      {
          return inputString;
      }
  }

The list of handlers specified in the operation attribute applies to all methods of the web service that accept SOAP messages.

Note: it is possible, using the @jws:protocol annotation, to configure methods or callbacks that do not accept SOAP messages. SOAP message handlers will not be applied to methods that do not accept SOAP messages.

To specify that more than one handler should be invoked, supply the list of handlers in a space-separated list:

@jws:handler operation="handler.ConsoleLoggingHandler somepackage.SomeOtherHandler"

See Where Handlers Fit in the Message Path, above, for examples of the order of handler invocations in various scenarios.

Specifying Handler Chains in a Handler Configuration File

As an alternative to specifying the handlers directly as the value of the operation or callback attribute, you may configure named handler chains in a handler configuration file and reference the handler chain names as the value of the operation or callback attribute. An example handler configuration file is shown below:

  <?xml version="1.0" encoding="UTF-8"?>
  <hc:wlw-handler-config xmlns:hc="http://www.bea.com/2003/03/wlw/handler/config/">
      <hc:handler-chain name="LoggingHandler">
          <hc:handler handler-name="Logger" handler-class="handler.ConsoleLoggingHandler"/>
          <hc:handler handler-name="Auditor" handler-class="handler.AuditHandler"/>
      </hc:handler-chain>
  </hc:wlw-handler-config>

Note: a <handler-chain> with no handlers is valid. It provides a means to remove handlers without changing the referencing source file.

The preceding handler configuration file defines a handler chain named LoggingHandler. The example web service that follows assumes the preceding XML is saved in a file named consoleLoggingConfig.xml and references the LoggingHandler chain as the value of the operation attribute:

  package handler;
  
  /**
   * @jws:handler operation="LoggingHandler" file="consoleLoggingConfig.xml"
   */
  public class HandlerExample2 implements com.bea.jws.WebService
  {
      static final long serialVersionUID = 1L;
	  
      /** @common:operation */
      public String echoString(String inputString)
      {  
          return inputString;
      }
  }

The handler chain specified in the operation or callback attribute applies to all methods or callbacks of the web service that accept SOAP messages. See Where Handlers Fit in the Message Path, above, for examples of the order of handler invocations in various scenarios.

Note: it is possible, using the @jws:protocol annotation, to configure methods or callbacks that do not accept SOAP messages. SOAP message handlers will not be applied to methods that do not accept SOAP messages.

Each <handler> element in a handler configuration file may also specify initialization parameters for the handler in <init-param> elements as shown in the following example:

  <hc:handler handler-name="MyHandler" handler-class="MyHandler"/>
      <hc:init-param>
          <hc:description>First Param</hc:description>
          <hc:param-name>param1</hc:param-name>
          <hc:param-value>value1</hc:param-value>
      </hc:init-param>
  </hc:handler>

All defined parameters are delivered to the handler's init method when it is invoked.

The handler configuration file approach has one advantage over the direct handler specification approach: you can reconfigure a handler chain simply by modifying the handler configuration file and redeploying the application - there is no need to recompile the application (unless you add or modify handler classes).

An Example Message Handler

The example below shows the code for the ConsoleLoggingHandler referenced in the previous examples:

  package handler;

  import java.util.Iterator;
  import javax.xml.rpc.handler.MessageContext;
  import javax.xml.rpc.handler.soap.SOAPMessageContext;
  import javax.xml.soap.SOAPElement;

  // for readability, using weblogic API instead of javax.xml.rpc.handler.GenericHandler
  // See http://edocs.beasys.com/wls/docs81/webserv/interceptors.html#1060763
  import weblogic.webservice.GenericHandler;

  /**
   * Purpose: Log all messages to the Server console
   */
  public class ConsoleLoggingHandler extends GenericHandler
  {
      /**
       * Handles incoming web service requests and outgoing callback requests
       */
      public boolean handleRequest(MessageContext mc)
      {
          logSoapMessage(mc, "handleRequest");
          return true;
      }
      /**
       * Handles outgoing web service responses and incoming callback responses
       */
      public boolean handleResponse(MessageContext mc)
      {
          this.logSoapMessage(mc, "handleResponse");
          return true;
      }

      /**
       * Handles SOAP Faults that may occur during message processing
       */
      public boolean handleFault(MessageContext mc)
      {
          this.logSoapMessage(mc, "handleFault");
          return true;
      }

      /**
       * Log the message to the server console using System.out
       */
      protected void logSoapMessage(MessageContext mc, String eventType)
      {
          try
          {
              System.out.println("*****************************");
              System.out.println("Event: "+eventType);
              System.out.println("Endpoint Method: " + getMethodName(mc));
              System.out.println("Soap message is: \n " +
                  com.bea.wlw.runtime.jws.soap.util.SAAJUtil.SOAPPart2String(
                      ((SOAPMessageContext)mc).getMessage() ) + "\n");
              System.out.println("*****************************");
          }
          catch( Exception e )
          {
              e.printStackTrace();
          }
      }
  
      /**
       * Get the method Name from a SOAP Payload.
       */
      protected String getMethodName(MessageContext mc)
      {
          String operationName = null;

          try
          {
             SOAPMessageContext messageContext = (SOAPMessageContext) mc;
  
             // assume the operation name is the first element
             // after SOAP:Body element
             Iterator i = messageContext.
                 getMessage().getSOAPPart().getEnvelope().getBody().getChildElements();
             while ( i.hasNext() )
             {
                 Object obj = i.next();
                 if(obj instanceof SOAPElement)
                 {
                     SOAPElement e = (SOAPElement) obj;
                     operationName = e.getElementName().getLocalName();
                     break;
                 }
             }
          }
          catch(Exception e)
          {
              e.printStackTrace();
          }
          return operationName;
      }
  }

If you use the weblogic.webservices.GenericHandler class as the base class for your handler, as the ConsoleLoggingHandler does, you do not need to implement methods (such as init()) that you do not need to customize.

Message Handlers and Web Service Controls

To call an external web service from WebLogic Workshop, you use a Web Service control. To configure message handlers for messages that pass between your application and the external web service, you specify the @jc:handler annotation on the interface defined in the Web Service control's JCX file.

The example below illustrates the @jc:handler annotation in the TargetServiceControl.jcx file that defines a Web Service control for communication with the TargetService external web service:

  /**
   * @jc:location http-url="TargetService.jws" jms-url="TargetService.jws"
   * @jc:wsdl file="#TargetServiceWsdl"
   * @jc:handler callback="handler.ConsoleLoggingHandler" operation="handler.ConsoleLoggingHandler"
   */
   public interface TargetServiceControl extends com.bea.control.ControlExtension, com.bea.control.ServiceControl
   {
       ...
   }

Testing Callback Handlers

When testing callback handlers, you must invoke the handler via a service control, not the test interface. The test interface can receive the request, but it cannot respond to it because it does not implement the callback interface set by the service. If the service is invoked from the test interface, the callback request is never sent. Because the request is never sent, the handlers are never invoked.

If the service with the callback handlers is invoked via a service control, then the callback handlers get invoked. So, to test callbacks, the callback handlers must be tested from a client that implements the callback interface. To do this you might create callbacks within the test JWS, then call these from your control's callback handlers.

Implementation Details

Message Handlers Not Supported Via HTTP GET

WebLogic Workshop 8.1 does not support SOAP message handlers on messages that arrive via HTTP GET.

When testing WebLogic Workshop web services with message handlers via Test View, remember that the Test Form page uses HTTP GET and the Test XML page uses HTTP POST. Your message handlers will not be invoked if you submit web service requests via HTTP GET from the Test Form page. Use the Test XML page instead.

Message Handler Limitations

All J2EE-based web service implementations that support SOAP message handlers place limitations on the types of operations that message handlers may perform on messages. This is because the web services are implemented as container-managed objects such as EJBs, and certain types of operations on SOAP messages will interfere with the operation of the container.

Below is a non-exhaustive list of things you can not do in a message handler:

WebLogic Workshop provides container-based security outside the context of message handlers. To learn more, see WebLogic Workshop Security Overview.

Related Topics

Web Service Control

@jws:handler Annotation

@jc:handler Annotation