How To Define Handlers Chain in JAX-WS Using LogicalHandler and SOAPHandler At Same Time

JAX-WS Handlers implement Interceptor Pattern and Chain of Responsibility Pattern, that means when a client sends a SOAP request to a service endpoint, the handles intercept the request, perform some processing and (optionally) forward request to next handler in the chain, until the actual service implementation process the request.


A handler may process the request by itself by replying to the service client. It depends how you have implemented the handlers. JAX-WS provides two types of handlers i.e. LogicalHandler and SOAPHandler. In this article I will show have you can define both types of handlers in the a chain and how/when the runtime calls their life cycle method i.e. handleMessage() to provide them opportunity of processing the request. Generally handlers do not process the request, they only perform 'cross cutting concerns' tasks e.g. authentication, authorization, logging, accounting, validation, etc.

Let us define a web service, which have only one method. We can also inject the handlers xml file name using annotation:
@WebService
@HandlerChain(file = "handlers.xml")

public class TestingService {
@WebMethod
public String sayHi(String name) {
return "Hi! " + name;
}
}

When sayHi() method is called by web service client, it returns passed parameter back to client after joining "Hi". The annotation @HandleChain is used to specify the XML file which contains the description of handlers. Please note, this is not the only way to define handlers chain. You can also define in descriptor file usually name WEB-INF/sun-jaxws.xml. Lets assume, we are not deploying the service inside a Servlet container. Here is, how the handlers.xml file looks like:



com.bitspedia.jaxws.MySOAPHandler



com.bitspedia.jaxws.MyLogicalHandler





From XML file you can see, I have defined one handler of each type. A SOAP Message consists of two parts, SOAP Part and Attachment Part. The SOAP Part consists of SOAP envelop which contains header and body section. Attachment Part is optional and when present, it contains attachments. Lets focus on handlers, so there two type of handlers as defined in above code section. Fundamentally there are two differences between two types of handlers:
  1. When Message arrives at server, first all SOAPHandlers are processed, once they have finished, then Logical Handlers are processes. 
  2. The context of SOAPHanlder is wider, i.e. they can act on whole SOAP Message. While LogicalHandler can only act on body part of the SOAP envelop.
  3. When the SOAP request processing is done by service implementation and SOAP response is ready to send. This is called outbound message. Same handlers chain again process the message but in different order. First all Logical Handlers process the message then SOAP Handlers process it.

When handlers are initialized, the are given MessageContext. From the MessageContext, they can get their required information about the message. The Logical Handlers are given an instance of LogicalMessageContext and SOAP Handlers are given SOAPMessageContext. These context a just key value map that represent different components of SOAP message. Now you must be in a position to understand Handlers better, lets view each Handler code:
package com.bitspedia.jaxws;

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;

public class MySOAPHandler implements SOAPHandler {

@Override
public boolean handleMessage(SOAPMessageContext smc) {
Boolean outboundProperty = (Boolean) smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

if (outboundProperty.booleanValue()) {
System.out.println("\n MySOAPHandler ... Outgoing message:");
} else {
System.out.println("\n MySOAPHandler ... Incoming message:");
}
return true;
}

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

@Override
public void close(MessageContext context) {
System.out.println("MySOAPHandler - close() called ");
}

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

Here I define, MyLogicalHandler.
package com.bitspedia.jaxws;

import javax.xml.ws.handler.LogicalHandler;
import javax.xml.ws.handler.LogicalMessageContext;
import javax.xml.ws.handler.MessageContext;

public class MyLogicalHandler implements LogicalHandler {

@Override
public boolean handleMessage(LogicalMessageContext lmc) {
Boolean outbound = (Boolean) lmc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

if (outbound) {
System.out.println(" MyLogicalHandler - This is Outbound Message ... ");
} else {
System.out.println(" MyLogicalHandler - This is Inbound Message ... ");
}

return true;
}

@Override
public boolean handleFault(LogicalMessageContext context) {
System.out.println(" MyLogicalHandler ... handleFault() called ");
return true;
}

@Override
public void close(MessageContext context) {
System.out.println("MyLogicalHandler ... close() called ");
}
}

From log, we can see when each handler is called for inbound and outbound message. Please note that, if you have defined multiple handlers of same type (say SOAPHandler) in the chain, those handlers will be called in same order as configured. But if you mixed the both types, for outbound message, first all Logical Handlers would be called, then all SOAP Handlers. Hope you got the idea.

Now, if we call the sayHi() webservice method. At seerver side log will be printed as follows:

MySOAPHandler ... Incoming message:
MyLogicalHandler - This is Inbound Message ...
MyLogicalHandler - This is Outbound Message ...

MySOAPHandler ... Outgoing message:
MyLogicalHandler ... close() called
MySOAPHandler - close() called

I have skipped some steps intentionally e.g. how to generate client code from WSDL file, and how to deploy the endpoint. As in this article my object was to define handlers chain and checking when exactly they are called. You can read http://java.dzone.com/articles/jax-ws-hello-world to see how to define and call hello world service. Your feedback would be highly appreciated.

Comments

  1. Is there any way to configure the handler chain on the client side without having to use an XML? I want to do it via java code.

    ReplyDelete

Post a Comment