Web services Handler Chains tutorial

Web Services and their clients may need to access the SOAP message for additional processing of the message request or response. You can create SOAP message handlers to enable Web Services and clients to perform this additional processing on the SOAP message. A SOAP message handler provides a mechanism for intercepting the SOAP message in both the request and response of the Web Service.

In order to use Handler chains in your Web service you have to add the @javax.jws.HandlerChain annotation at class level:

package com.sample.ws;

import javax.jws.HandlerChain;
import javax.jws.WebService;


@WebService(endpointInterface = "com.sample.ws.SampleWS", serviceName = "SampleWS")
@HandlerChain(file="/com/sample/ws/handler-chain.xml")
public class SampleWSImpl implements SampleWS {
 public SampleWSImpl() {}
 public String hello(String s) {
 return "Hello "+s;
 }
}

Ok, now your Web service will be proxied by one or more Handler defined in the handler-chain.xml configuration file.

In earlier releases of JBoss you had to place this file beneath the META-INF folder of your Web application. When using JBoss 7 just place it in the package folder which is included in the file property (In our example com/sample/ws).

Here is the handler-chain.xml which defines a Logging Handler:

<?xml version="1.0" encoding="UTF-8"?>
<handler-chains xmlns="http://java.sun.com/xml/ns/javaee">
 <handler-chain>
 <handler>
 <handler-class>com.sample.LoggingHandler</handler-class>
 </handler>
 </handler-chain>
</handler-chains>

And this is the Handler Class:

package com.sample.handler;

import java.util.Set;

import javax.xml.namespace.QName;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;

import org.apache.commons.io.output.ByteArrayOutputStream;

public class LoggingHandler implements SOAPHandler<SOAPMessageContext> {

 @Override
 public Set<QName> getHeaders() {
 return null;
 }

 @Override
 public void close(MessageContext context) {
 }

 @Override
 public boolean handleFault(SOAPMessageContext context) {
  logToSystemOut(context);
  return true;
 }

 @Override
 public boolean handleMessage(SOAPMessageContext context) {
 logToSystemOut(context);
  return true;
 }

 private void logToSystemOut(SOAPMessageContext smc) {
 
  Boolean outboundProperty = (Boolean) smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

  try {
   if (!outboundProperty.booleanValue()) {
 
   SOAPMessage message = smc.getMessage();
 
  System.out.println("Incoming message:");
  ByteArrayOutputStream stream = new ByteArrayOutputStream();
  message.writeTo(stream);
 
  System.out.println(stream.toString());
  System.out.println("=====================================");                
   }
  }
  catch (Exception e) {
  System.out.println("Exception in handler: " + e);
  }
  }
}

The above Handler will just print out all the SOAP incoming messages which are gathered as InputStream and finally converted to String using the ByteArrayOutputStream utility class from Apache Commons IO.

You can use SOAP message Handlers as well to improve the performance of your Web Service. After your Web Service has been deployed, you might discover that many consumers invoke it with the same parameters. You could improve the performance of your Web Service by caching the results of popular invokes of the Web Service (assuming the results are static) and immediately returning these results when appropriate, without ever invoking the back-end components that implement the Web Service. You implement this performance improvement by using handlers to check the request SOAP message to see if it contains the popular parameters.

Similarities between Handlers and CXF Interceptors

JAX-WS handlers are internally implemented in CXF by use of interceptors, so by definition anything that can be done with the former can be done with the latter. Handlers and interceptors are quite similar, in fact both have a handleMessage()  which is defined by the top level interfaces. Both provide mechanisms for SOAP messages as well as more generic XML over HTTP routing. The routing direction is also similar in that handleFault(), when errors occur, causes the interceptors to run in reverse order.

Differences between Handlers and CXF Interceptors

The most important difference is that CXF Interceptors are split into two main categories: inbound and outgoing interceptors which are used to collect the server incoming message and the outgoing response. On the other hand  when using JAX-WS handlers, the same handlers are activated both on request and reply. When using Handlers you can discriminate if it’s an inbound/outbound message by checking the MessageContext.MESSAGE_OUTBOUND_PROPERTY.

public boolean handleMessage(SOAPMessageContext messageContext)
{
 Boolean outboundProperty = (Boolean)
 messageContext.get (MessageContext.MESSAGE_OUTBOUND_PROPERTY);

 if (outboundProperty.booleanValue()) {
 System.out.println("\nOutbound message:");
 } else {
 System.out.println("\nInbound message:");
 }

 System.out.println("** Response: "+messageContext.getMessage().toString());
 return true;
}

Another difference is that an additional close() method,used for object cleanup, is available with handlers but not interceptors.

public void close(MessageContext messageContext)
 {
 }

Another difference is how Fault exception are treated. When using Interceptors you can retrieve the Fault from the MessageContent:

public void handleMessage(SoapMessage message) throws Fault {
 Fault fault = (Fault) message.getContent(Exception.class);
 fault.setDetail(createDetailSomehow());
}

…provided that you registered your Fault Interceptor:

@org.apache.cxf.interceptor.OutFaultInterceptors (interceptors = {"com.sample.CustomFaultInterceptor" })
@WebService(
public class SayHiImpl  implements SayHi {
public long sayHi(long arg) {
return arg;
}

}
Found the article helpful? if so please follow us on Socials