SCDJWS Study Guide: JAX-RPC


Printer-friendly version Printer-friendly version | Send this 
article to a friend Mail this to a friend


Previous Next vertical dots separating previous/next from contents/index/pdf Contents

JAX-RPC Handler


What is JAX-RPC Handler?


When you develop your company's web services,  you would like to have

  • A logging component to show how based on SOAP message content specific logging actions can be undertaken;
  • A performance track component to calculate the time taken to process a SOAP message;
  • An authentucation component to process SOAP headers containing credentials;
  • A component to encrypt meesagge before you can send it across the network;
  • And more .....

The JAX-RPC sepcification provides us with a feature that can help us do these things: handlers. A handler is a component that can be associated with an entire Web service or with a particular Web service interface. A Web service can have a number of ports—a port is analogous to a Java interface—and a handler can be associated with just an interface. JAX-RPC handlers allow you to intercept a SOAP message at various times during a service invocation. Handlers can be very generic, such as logging or caching handlers, or very specific, such as handlers that want to process an application-specific SOAP header.

Handlers can be used in both the client and the server side. If you use JAX-RPC on the client side, you can have a handler process a SOAP request message right before it goes on the network, and you can process the response message before it is returned to the client. Similarly, you can intercept an incoming SOAP request message on the server before invoking the service implementation, as well as the outgoing response.

Several handlers can be combined into what is called a "handler chain". Each handler processes the SOAP message, which is then passed on to the next handler in the chain. The exact sequence in which this happens is configurable. If multiple handlers in a handler chain that are involved in one service invocation need to share information, they can do so by adding properties to the message context as it is passed from handler to handler. This message context will be available from the request to the response. In other words, we can use it to store information on an incoming request that we can reuse when the response comes back.

A handler is a java class  that implements the javax.xml.rpc.handler.Handler interface. It has three methods (handleRequest, handleResponse, and handleFault) to handle SOAP requests, responses and faults, respectively.

public abstract interface javax.xml.rpc.handler.Handler extends java.lang.Object {
    public abstract boolean handleRequest(MessageContext context);
    public abstract boolean handleResponse(MessageContext context);
    public abstract boolean handleFault(MessageContext context);
    public abstract void init(HandleInfo info);
    public abstract void destory();
    public abstract QName[] getHeaders;
};

In the javax.xml.rpc.handler package, the  javax.xml.rpc.handler.GenericHandler is an abstract class that provides default implementations all the methods in javax.xml.rpc.handler.Handler interface. You can extends the javax.xml.rpc.handler.GenericHandler class to write your own handler and you only overridden methods you want to.

When you design SOAP message JAX-RPC handlers you must decide the number of handlers, the order in which the handlers will be executed, and whether to invoke a back-end component.

Handler Life Cycle

The JAX-RPC runtime system considers all instances of a particular handler class to be equivalent. This allows the JAX-RPC runtime system to pool handler instances, although this is not required.

The life cycle of a handler consists of two states. A handler either does not exist, or is in a ready state. Once a handler is in its ready state, its various handle() methods can be invoked. The life-cycle methods of a handler should be used to initialize and clean up resources within a handler instance. A handler instance has two life-cycle methods. When a new instance of a handler is created, its init() method is called. That allows you to set up things that you can use for multiple invocations. Before the handler is removed, the destroy() method is called, so that you can do cleanup in there.

On a service client the handleRequest() method is invoked before the actual SOAP message is sent, and the handleResponse() method is invoked before the actual response is received.

On a service endpoint, the handleRequest() method is invoked before the actual service endpoint is invoked, and the handleResponse() method is invoked before the actual response is sent to the client.  

On a service client the handleFault() method is called before receiving a SOAP fault, and on the service endpoint the handleFault() method is called before generating a SOAP fault.



Stop JAX-RPC Handler's Processing

There are several ways to stop processing the message. One way is to throw a JAXRPCException that signals that a run-time error has occurred in the processing of the message. The server's handler chain will produce a SOAP fault and send it back to the client.

For another way to return false, the server will stop processing the handleRequest() side of the chain and instead start processing the handleResponse() side of the handler chain. The handlers in the chain are responsible for producing the response SOAP message, either in this handleRequest() method or in one of the handleResponse() methods called in the chain. This alternative is intended for a scenario in which there is no error, but the handler wants to process the response itself.

Handlers can be configured either programmatically or, in case you are running a J2EE application server, they are configured in the Web service deployment descriptor. Handlers and handler chains are defined on a per service basis. They can be defined in both the server and client side deployment descriptors.

JAX-RPC defines a mechanism with which you can manage service invocations by intercepting request and response messages without having to change the actual service consumer or provider. In J2EE, you can configure handlers in a deployment descriptor, without writing any code, providing you with a powerful way of controlling SOAP message as they pass through your system.

Here we will look at how to write generic handlers and how to configure them for a JAX-RPC client and a JAX-RPC server.

JAX-RPC Server-Side Handler

Here is a sample of a Hello Web Service:

  • a) Service Definition Interface

    package com.example.service;
    import java.rmi.Remote;
    import java.rmi.RemoteException;
    public interface HelloIF extends Remote {
      public String sayHello(String s) throws RemoteException;
    }

  • b) Service Implementation

    package com.example.service;
    public class HelloImpl implements HelloIF {
      public String message ="Hello";
      public String sayHello(String s) {
        return message + s;
      }
    }


The following code is a simple performance track handler on the above Hello Web service. The performance measurement is the spending time between SOAP request and SOAP response.  In this sample, we store the transaction start time (the current system time) in the message context as a property called "startTime" in the handleRequest method. The application server will guarantee that the same message context object is passed into the handleResponse method, so that we can measure the elapsed time there:

package com.example.handler;
public class PerformanceHandler extends GenericHandler {
 
    protected HandlerInfo info = null;
    protected Logger logger = null;

    public void init(HandlerInfo arg) {
        info = arg;
        logger = Logger.getLogger("c://temp//HelloWorldServiceLog");
    }
   
    public void destroy() {
        try {
            logger.close();
        } catch (Exception x) {}
    }           

    public boolean handleRequest(MessageContext context) {
        try {
        Long startTime = new Long(System.currentTimeMillis())
            context.setProperty("startTime", start);
        } catch (Exception x) {
            x.printStackTrace();
        }
        return true;
    }

    public boolean handleResponse(MessageContext context) {
        try {
            Long startTime = (Long)context.getProperty("startTime");
            long elapsedTime = System.currentTimeMillis() - startTime.longValue;
            logger.write("Elapsed time is " + elapsedTime+"\n");
        } catch (Exception x) {
            x.printStackTrace();
        }
        return true;
    }

}
 

Here is the deployment descriptor for our sample service, showing how a handler class called handler.PerformanceHandler is registered for the HelloWorldService service (webservices.xml). The list shows that webservices.xml is also used for configuring the handlers via the <handler> element, which contains a logical name for the handler in the <handler-name> element and the actual Java class handler reference inside the <handler-class> element.

<webservices>
   <webservice-description>
      <webservice-description-name>HelloWordService</webservice-description-name>
      <wsdl-file>WEB-INF/wsdl/HelloWorld.wsdl</wsdl-file>
      <jaxrpc-mapping-file>WEB-INF/mapping.xml</jaxrpc-mapping-file>
      <port-component>
         <port-component-name>....</port-component-name>
         <wsdl-port>
            <namespaceURI>....</namespaceURI>
            <localpart>.........</localpart>
         </wsdl-port>
         <service-endpoint-interface>pack.HelloWorld</service-endpoint-interface>
         <service-impl-bean>
            <servlet-link>...</servlet-link>
         </service-impl-bean>
         <handler>
            <handler-name>Performance Handler</handler-name>
            <handler-class>com.example.handler.PerformanceHandler</handler-class>
         </handler>
      </port-component>
   </webservice-description>
</webservices>

In the server-programming model, a handler can be configured with initial parameters < init-param>.  Handlers can also obtain such configuration information when they are initialized. This configuration information is passed as a part of the HandlerInfo object that is passed to the init() method of the handler instance.

<webservices>
   <webservice-description>
   ..........
    <port-component>
         .........
     <handler>
      <handler-name> ... </handler-name>
      <handler-class>.... < /handler-class>
      <init-param>
        <param-name>loglevel1</param-name>
        <param-value>stdout</param-value>
      </init-param>
      <init-param>
        <param-name>loglevel2</param-name>
        <param-value>log</param-value>
      </init-param>
     </handler>
    </port-component>
   </webservice-description>
</webservices>

Here is code fragment of a JAX-RPC handler to handle the configuration in the file:

public void init(HandlerInfo handlerInfo) {
    Map handlerConfig = handlerInfo.getHandlerConfig();
    String logLevel1 = (String)handlerConfig.get("logLevel1");
    String logLevel2 = (String)handlerInfo.get("logLevel2");
     .... 
  }

JAX-RPC Client-Side Handler


We can also add the above handler into the client code to trace the SOAP message round-trip time.  

The following is a sample of static-stub client with the perfomance handler:


package hello;
import javax.xml.rpc.Stub;
.........
public class HelloClient {
    public static void main(String[] args) {
        try {
            MyHelloService_Impl impl = new MyHelloService_Impl();
            Stub stub = (Stub)(impl.getHelloIFPort());
            stub._setProperty (javax.xml.rpc.Stub.ENDPOINT_ADDRESS_PROPERTY, args[0]);
            HelloIF hello = (HelloIF)stub; 

            //Get Iterator for all service ports
            Iterator iter = impl.getPorts();

            // Now create a new List of HandlerInfo objects - only one really. Our client handler
            List handler
Chain = new ArrayList();
            handlerChain.add(new HandlerInfo(PerformanceHandler.class, null, null));

            //Get Handler Registry
            HandlerRegistry registry = impl.getHandlerRegistry();

            //Register each port with the handler
            while (iter.hasNext())
                registry.setHandlerChain((QName)iter.Next(), handler
Chain);
 
            System.out.println(hello.sayHello(args[1]));
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}


The following is a sample of DII client with the perfomance handler:

package dii;
import javax.xml.rpc.Call;
import javax.xml.rpc.Service;
import javax.xml.rpc.JAXRPCException;
import javax.xml.namespace.QName;
import javax.xml.rpc.ServiceFactory;
import javax.xml.rpc.ParameterMode;
import com.example.handler.PerformanceHandler;

public class HelloClient {
    private static String qnameService = "MyHelloService";
    private static String qnamePort = "HelloIF";
    private static String BODY_NAMESPACE_VALUE = "urn:Foo";
    private static String ENCODING_STYLE_PROPERTY ="javax.xml.rpc.encodingstyle.namespace.uri";
    private static String NS_XSD = "http://www.w3.org/2001/XMLSchema";
    private static String URI_ENCODING = "http://schemas.xmlsoap.org/soap/encoding/";

    public static void main(String[] args) {
        System.out.println("Endpoint address = " + args[0]);
        try {
            ServiceFactory factory = ServiceFactory.newInstance();
            Service service =factory.createService(
                new QName(qnameService));
            QName port = new QName(qnamePort);

            // Now create a new List of HandlerInfo objects - only one really. Our client handler
            List handler
Chain = new ArrayList();
            handler
Chain.add(new HandlerInfo(PerformanceHandler.class, null, null));
            HandlerRegistry registry = service.getHandlerRegistry();
            registry.setHandlerChain(port, handler
Chain);

            //Create an instance of the Call object
            Call call = service.createCall(port);
 
            //Set service endpoint
            call.setTargetEndpointAddress(args[0]);
 
            //Configure your Call instance with its setter methods
            call.setProperty(Call.SOAPACTION_USE_PROPERTY,
                    new Boolean(true));
            call.setProperty(Call.SOAPACTION_URI_PROPERTY,"");
            call.setProperty(ENCODING_STYLE_PROPERTY,URI_ENCODING);
            //Set definition of the return Type
            QName QNAME_TYPE_STRING =new QName(NS_XSD, "string");
            call.setReturnType(QNAME_TYPE_STRING);
 
            //Set Name of the method to invoke 
            call.setOperationName(
                    new QName(BODY_NAMESPACE_VALUE,"sayHello"));
 
            //Set parameters defintions in the call object
            call.addParameter("String_1", QNAME_TYPE_STRING,
                    ParameterMode.IN);
            String[] params = { "Murph!" };
 
            //Finally invoke the method
            String result = (String)call.invoke(params);
            System.out.println(result);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

In the JAX-RPC Server-Side Handler, we have shown how to add init parameters into HandleInfo class by using the configuration file. In the above stand-alone JAX-RPC client code, we can use "programmatic configuration: HandlerInfo" to pass the init parameters to a handler instance:

    .........
    //Now create a new List of HandlerInfo objects
    List handlerChain = new ArrayList();
    //Create the init parameters information
    Map logConfig = new HashMap();
    logConfig.put("logLevel1", "stdout");
    logConfig.put("logLevel2", "file");
    handlerChain.add(new HandlerInfo(PerformanceHandler.class,
                logConfig, null));
    ........


Client side handlers can be similarly arranged as a 'handler chain' inside the <service-ref> tag of J2EE1.4 clients (for example web.xml,ejb-jar.xmlor an application-client.xml).

<service-ref>
   <service-ref-name>service/MyHelloServiceRef</service-ref-name>
   <service-interface>javax.xml.rpc.Service</service-interface>
      ....
      <port-component-ref>
      ....
      </port-component-ref>
      <handler>
         <handler-name>My Handler One</handler-name>
         <handler-class >com.example.handler.MyHandlerOne</handler-class>
         <port-name>...</port-name>
      </handler>
      <handler>
         <handler-name>My Handler Two</handler-name>
         <handler-class>com.example.handler.MyHandlerTwo< /handler-class>
         <port-name>...</port-name>
      </handler>
</service-ref>
 

Note: Unlike the server-side handlers, client side handlers are associated with <service-ref> (service references) instead of <port-component> (port component references). However, they have a configurable parameter, <port-name>, by which handlers can be associated with the port of the service which is invoked. With port names, you can restrict which handlers to run when a service endpoint (WSDL port) is invoked.


Handlers Process


Handler Chains


A HandlerChain delegates processing of the SOAP message to its configured chain of handlers. When you design your SOAP message handlers, you must decide the number of handlers needed to perform all the work and the sequence of handlers excution. You specify the handlers in the web-services.xml deployment descriptor file. An ordered group of handlers is referred to as a  handler chain.

The handleRequest, handleResponse and handleFault methods for a SOAP message handler get access to the SOAPMessage from the SOAPMessageContext. The implementation of these methods can modify the SOAPMessage including the headers and body elements.

When invoking a Web service, Web service container executes handlers as follows:

scdjws:server side handler flow

  1. The handleRequest() methods of the handlers in the handler chain are all executed, in the order specified in the web-services.xml file. Any of these handleRequest() methods might change the SOAP message request.
  2. When the handleRequest() method of the last handler in the handler chain executes, Web service container invokes the backend component that implements the Web service, passing it the final SOAP message request.
  3. When the backend component has finished executing, the handleResponse() methods of the handlers in the handler chain are executed in the reverse order specified in the web-services.xml file. Any of these handleResponse() methods might change the SOAP message response.
  4. When the handleResponse() method of the first handler in the handler chain executes, Web service container returns the final SOAP message response to the client application that invoked the Web service.


handleRequest Method

The handleRequest method performs one of the following steps after performing handler specific processing of the request SOAP message:

  • Return true to indicate continued processing of the request handler chain. The HandlerChain takes the responsibility of invoking the next entity. The next entity may be the next handler in the HandlerChain or if this handler is the last handler in the chain, the next entity is the target service endpoint. The mechanism for dispatch or invocation of the target service endpoint depends on whether the request HandlerChain is on the client side or service endpoint side.

  • Return false to indicate blocking of the request handler chain. In this case, further processing of the request handler chain is blocked and the target service endpoint is not dispatched. The JAX-RPC runtime system takes the responsibility of invoking the response handler chain next with the appropriate SOAPMessageContext. The Handler implementation class has the responsibility of setting the response SOAP message in the handleRequest method and perform additional processing in the handleResponse method. In the default processing model, the response handler chain starts processing from the same Handler instance (that returned false) and goes backward in the execution sequence.

  • Throw the javax.xml.rpc.soap.SOAPFaultException to indicate a SOAP fault. The Handler implementation class has the responsibility of setting the SOAP fault in the SOAP message in either handleRequest and/or handleFault method. If SOAPFaultException is thrown by a server-side request handler's handleRequest method, the HandlerChain terminates the further processing of the request handlers in this handler chain and invokes the handleFault method on the HandlerChain with the SOAP message context. Next, the HandlerChain invokes the handleFault method on handlers registered in the handler chain, beginning with the Handler instance that threw the exception and going backward in execution. The client-side request handler's handleRequest method should not throw the SOAPFaultException. Refer to the SOAP specification for details on the various SOAP faultcode values and corresponding specification.

  • Throw the JAXRPCException or any other RuntimeException for any handler specific runtime error. If JAXRPCException is thrown by a handleRequest method, the HandlerChain terminates the further processing of this handler chain. The Web service container catches the exception, terminates further processing of the handler request chain, and invokes the handleFault() method of this handler. 

    On the server side, the HandlerChain generates a SOAP fault that indicates that the message could not be processed for reasons not directly attributable to the contents of the message itself but rather to a runtime error during the processing of the message. Refer to the SOAP specification for details on the various SOAP faultcode values.

    On the client side, the JAXRPCException or runtime exception is propagated to the client code as a RemoteException or its subtype.

handleResponse Method

The handleResponse method performs the processing of the SOAP response message. It does one of the following steps after performing its handler specific processing of the SOAP message:

  • Return true to indicate continued processing of the response handler chain. The HandlerChain invokes the handleResponse method on the next Handler in the handler chain.

  • Return false to indicate blocking of the response handler chain. In this case, no other response handlers in the handler chain are invoked. On the service endpoint side, this may be useful if response handler chooses to issue a response directly without requiring other response handlers to be invoked.

  • Throw the JAXRPCException or any other RuntimeException for any handler specific runtime error. If JAXRPCException is thrown by the handleResponse method, the HandlerChain terminates the further processing of this handler chain. On the server side, the HandlerChain generates a SOAP fault that indicates that the message could not be processed for reasons not directly attributable to the contents of the message itself but rather to a runtime error during the processing of the message. On the client side, the JAXRPCException or runtime exception is propagated to the client code as a RemoteException or its subtype.

handleFault Method

The handleFault method performs the SOAP fault related processing. The JAX-RPC runtime system should invoke the handleFault method if a SOAP fault needs to be processed by either client-side or server-side handlers. The handleFault method does one of the following steps after performing handler specific processing of the SOAP fault:

  • Return true to indicate continued processing of the fault handlers in the handler chain. The HandlerChain invokes the handleFault method on the next Handler in the handler chain.

  • Return false to indicate blocking of the fault processing in the handler chain. In this case, no other handlers in the handler chain are invoked. The JAX-RPC runtime system takes the further responsibility of processing the SOAP message.

  • Throw JAXRPCException or any other RuntimeException for any handler specific runtime error. If JAXRPCException is thrown by the handleFault method, the HandlerChain terminates the further processing of this handler chain. On the server side, the HandlerChain generates a SOAP fault that indicates that the message could not be processed for reasons not directly attributable to the contents of the message itself but rather to a runtime error during the processing of the message. On the client side, the JAXRPCException or runtime exception is propagated to the client code as a RemoteException or its subtype.

Please note that when a JAXRPCException or RuntimeException raised on the server is converted to a SOAP fault for the purpose of being transmitted to the client, there are no guarantees that any of the information it contains will be preserved.





Previous Next vertical dots separating previous/next from contents/index/pdf Contents

  |   |