Thursday, September 25, 2008

Using JAX-WS Handlers

The JAX-WS provides a good facility to do pre/post processing on SOAP messages using SOAPHandler. The handlers are useful for auditing, logging and potentialy some more functionality. In this entry I will try to explain a typical usage of handlers for logging the SOAP messages. Every handler class needs to implement javax.xml.ws.handler.soap.SOAPHandler interface as shown below-
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);

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

        SOAPMessage message = smc.getMessage();
        try {
            message.writeTo(System.out);
        } catch (Exception e) {
            System.out.println("Exception in handler: " + e);
        }
    }

}
Now create a handler confiuration file say 'handlers.xml' as shown below and put it in 'WEB-INF' directory of your application.

<handler-chains xmlns="http://java.sun.com/xml/ns/javaee">
   <handler-chain>
      <handler>
         <handler-class>my.server.pkg.LoggingHandler</handler-class>
      </handler>
   </handler-chain>
</handler-chains>
Using @HandlerChain annotation we can instruct the JAX-WS runtime to apply the handlers configured in the above-mentioned configuration on a web service endpoint-
@WebService(endpointInterface = "my.server.pkg.IMyService")
@HandlerChain(file = "handlers.xml")
public class MyServiceImpl implements IMyService {
Now all incoming and outgoing SOAP messages will be logged to standard output stream. Source code for this example is available here.
For developing and deploying web services see my earlier posts-
http://blog.vinodsingh.com/2008/09/building-jax-ws-web-service.html
http://blog.vinodsingh.com/2008/09/jax-ws-web-service-and-jboss.html

14 Comments:

Anonymous said...

Very easy & useful !!
Can I use it for authentication purpose ? how ?

obaid
Dhaka

Vinod Singh said...

Of course why not. One can do so using-
public boolean handleMessage(SOAPMessageContext context)
method. Returning false from there will stop further processing.

Manish said...

Great Help!! I'v been searching for a help like this for the entire day and at last found this.

Anonymous said...

thanks man. this is very clear.
can i use my old jaxrpc handler with jaxws service?

Vinod Singh said...

Though I never tried but JAX-RPC handlers may not work directly under JAX-WS as they use different APIs. IMO porting of handlers from JAX-RPC to JAX-WS should be pretty easier.

siddhartha said...

Hi Vinod .... its been vary useful for me ... thanks ...
but i am not able to log the Exceptions ...
handleFault is not being called in case of an Exception thrown.

can u help me ??

Siddhartha.
sidd.aec@gmail.com

jR said...

Excellent job Vinod,
The code worked like a charm, the very first time! And it addressed my need perfectly.
I am bookmarking you blog for future :), keep up the good work.
Thanks a mil,
jR

Thomas said...

Thanks for the tutorial! We try to incorporate a SAML Token that we receive from another party into the header by using a JAX-WS handler.

Bit of a problem is, that we have the SAML token not as object but as plain xml string. How can we insert this into the header of the SOAP message as easy as possible?

Regards,
Thomas

James Weakley said...

Don't suppose you know whether higher-level handlers can be attached? e.g. view the raw HTTP message before the SOAP body is read by JAX-WS? I have a need to handle all messages, not just the ones that are valid.

Vinod Singh said...

James,

By the time handler is invoked SOAP body is already read by JAX-WS. Why don't you try filters for the task you mentioned?

James Weakley said...

Thanks Vinod.

I'm talking about the client side, and I'm calling the service from a J2SE client.

So it's the response from the server that i'm interesting in handling. Sometimes the remote server returns 500 with an HTML error page rather than SOAP. The resulting UnsupportedMediaException
(Unsupported Content-Type: text/html) doesn't have the page contents in it, which I'd like to be able to log so that we know what was returned instead of the SOAP response.

I didn't think it was possible to add filters in these situations, but hopefully I'm wrong.

Vinod Singh said...

James,

Handlers can be attached on client side as well, see here.

James Weakley said...

Thanks again Vinod.

I registered both SOAP and logical handlers, but the exception is already thrown before the handler is called for the response.

If it were possible to register a filter, that would probably work, however I can't find a way to access the HTTP level objects that the JAX webservice will use for the call, it appears they aren't exposed.

Appreciate your responses, thank you.

prabahar said...

Can you shed some light on how to pass the values through the messagecontext? from the client to the handler?