Friday, August 15, 2008

Create Apache CXF Interceptor (1)

Recently I am working on Apache CXF web service framework. There was an requirement from my project that any exception or fault has to be returned with a desired platform exception. Also, any returned soap fault message should include a platform specific soap header. So it means no matter whether it is a runtime exception thrown from the business logic, or it's just a schema validation exception, a specific platform exception with soap header has to be returned so that the client side could be able to interpret in it's specific way.

To fulfill this requirement, one of the option is to write an interceptor in CXF. I have been looking for a sample but since CXF is fairly new web service framework (up to this moment, the version 2.1 is still in Apache Incubator), I could not find any good one. The only document I can look for is the interceptor introduction page in CXF website. But it's actually a good document. So I would prefer you to have a look at the document to get the concept before you keep going on below.

In here (supposed you have read the interceptor concept), I will try to provide a solution that fulfill the requirements above.

First, I will create a FaultHeaderInterceptor which extends org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor.

Before you write an interceptor, you should decide which phase that the interceptor should intercept the message. In the above case, since I have to manipulate the returned message, I put my interceptor into PREPARE_SEND phase. Also I put my interceptor to run after MessageSenderInterceptor to make sure CXF have done everything before I manipulate the message.

In the constructor,

public FaultHeaderInterceptor()
{
  super(Phase.PREPARE_SEND);
  addAfter(MessageSenderInterceptor.class.getName());
}

Since this interceptor is only responsible to change the soap message when a fault is returned, in CXF configuration, I put this interceptor in outFaultInterceptor tag, which means this interceptor only run when a fault happened.

In the configuration,


<bean id="faultHeaderInterceptor class="package.name.FaultHeaderInterceptor"/>

<cxf:bus>
  <cxf:outfaultinterceptors>
    <ref bean="faultHeaderInterceptor"/>
  </cxf:outfaultinterceptors>
</cxf:bus>


In the FaultHeaderInterceptor, I need to implement the method handleMessage(SoapMessage message), here is the logic,


public void handleMessage(SoapMessage message) throws Fault
{
  Exception exception = message.getContent(Exception.class);

  if (exception != null)
  {
    PlatformException platformException =
     new PlatformException(exception.getMessage());
    // overwrite Exception to PlatFormException
    Fault fault = new Fault(platformException);
    message.setContent(Exception.class, fault);
  }
}


**Note that the PlatformException is an annotated class with @WebFault, which means it represents the soapFault message.

Right now, whenever it is checked exception, or runtime exception that thrown by the CXF, it will return the PlatformException. That's easy! However, it only fulfill the first part of the requirement. To fulfill the second part, which I have to include the header.

To be continue...

No comments:

Post a Comment