Tuesday, June 5, 2018

Creating CXF Interceptor in Mule (3.9)

1.0 Overview

When working on creating Mule applications that connects to SOAP web services, developers will often find that they need to have access to the underlying soap fault when a SOAP exception happens. This article will demonstrate how this can be achieved by creating a CXF interceptor.
There is two parts to this article, the first part will talk about how to create the mock soap service, and the second part will talk about creating the Mule app that implements the interceptor. The reason why I have created the Mock SOAP service, is because I want to proof that the recommended steps work, and they are not just merely theoretical suggestions.
I came to know about intercepting Mule Soap calls while working on the following issue:-

2.0 Creating the Mock Soap Service

The source code for the mock soap service is provided in the links at section 1.0, you just need to git clone the code and run the following maven command.


mvn clean package
Once this is done you will now be able to run the SOAP web service, while inside the project folder run the following command.

java -cp .\target\CCCJavaSoapMocker-0.0.1-SNAPSHOT.jar com.kian.mock.soap.service.Main
This command will start up the soap web service, to verify that the soap service is started browse to the following URL in your local machine.

http://localhost:8080/WS/MockService?wsdl
I have used the port 8080 for the mock soap service feel free to change it from the source code, recompile it and run. If the mock soap service is running you will see the following results when you browse to the following wsdl url (Figure 2.0a).
Figure 2.0a

3.0 Creating the custom CXF Interceptor

There is 2 things you need to do to create the custom CXF interceptor. Step 1 is to create the interceptor java class (the implementation) and step to is to create the cxf.xml file that intercepts and divert soap service call to the class.
Then the interceptor is implemented it divers all soap calls in your mule application to the interceptor, if you are only interested to intercept certain soap service call you need to implement that locally, this article will show you how to implement it globally.
The source code for the mule application that has this global CXF Interceptor implementation is provided in the links mentioned in section 1.0.

3.1 Creating the Custom CXF Interceptor Class

The custom interceptor class that is created is located in the following package.

com.kian.cxf.interceptor
Lets zoom in on the following method, because this is the meat of the whole intercepting mechanism, this is the method that will be used to get the SOAP fault.

@Override
        
public void handleMessage(SoapMessage message) throws Fault {
                  InputStream is = (InputStream) message.getContent(InputStream.class);
                  ByteArrayOutputStream os = 
new ByteArrayOutputStream();
                  
try {
                        IOUtils.copy(is, os);
                  } 
catch (IOException e) {
                        log.error(
"SoapFaultInterceptor.handleMessage", e);
                  }
                  InputStream newIs = 
new ByteArrayInputStream(os.toByteArray());
                  message.setContent(InputStream.class, newIs);
                
                  MuleEvent event = (MuleEvent)
                           message.getExchange().get(org.mule.module.cxf.CxfConstants.MULE_EVENT);

                  event.getMessage().setInvocationProperty(
"OriginalPayload",os.toString());
                  log.info(
"Intercepting completed !!!!");
        }
Listing 3.1a
I need you to pay attention to the first line of the code statement in the method, it is getting InputStream from the SoapMessage. This method implementation is specifically for “cxf:inInterceptors” and “cxf:inFaultInterceptors”, (if you use it for “cxf:outInterceptors” or cxf:outFaultInterceptors you will get errors because “message.getContent(InputStream.class)” will return null). This interceptor merely copies the intercepted soap payload into a flow variable called “OriginalPayload”.

3.2 Creating the CXF Interceptor Global Configuration

Now once the java implementation for the CXF interceptor is complete we are ready to configure the global CXF interceptor file. This file will be created in the src/main/resource folder.
The following is a snippet of the contents in the file.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:cxf=
"http://cxf.apache.org/core"
        xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context=
"http://www.springframework.org/schema/context"
        xsi:schemaLocation=
"http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd
                       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"
>
        
<bean class="com.kian.cxf.interceptor.CustomInterceptor" 
                id="customInterceptor" />
        
<cxf:bus>
                
<cxf:inInterceptors>
                        
<ref bean="customInterceptor" />
                
</cxf:inInterceptors>
        
</cxf:bus>
</beans>
In the configuration file you will need to create a spring bean entry referring to the java class we have previously created in section 3.1 and will later refer to the bean in the “cxf:inInterceptors” configuration (as shown in the snippet).
Your mule project folder should look like the following format (Figure 3.2 a), notice the location of the cxf.xml file.
Figure 3.2a
Your Mule application would look like the following (Figure 3.2b).
The mule app starts to set two numbers a and b, and then assigns these numbers to the soap payload that will be used to invoke the mock soap service, as mentioned earlier the soap service merely conducts a division between “a” and “b”. If you assign “b” with a zero(0), you will get a divide by zero soap fault.
The set payload message processor is used to set the flow variable called “OriginalPayload” as the payload, this is because in the java interceptor code (mentioned in Listing 3.1a), gets the payload that is passing through the interceptor and sets it in a flow variable calle a similar name.

4.0 Conclusion

Now that we have the mule application built it is time to test the interceptor, run the mule application in debug mode. Once the mule app is running in debug mode, use google chrome and browse to the following URL.

http://localhost:8081/test
If you step through the debugger, you will see that the following values for the flow variables that is being passed pas part of the web service payload (Figure 4.0a). This will create a soap fault because we are trying to divide 1 with zero (0).
Figure 4.0a
If you step through the debugger it will also stop at the breakpoints that you have set in the interceptor java code (Figure 4.0b).
Figure 4.0b
The last statement in the interceptor method logs a “Intercepting completed !!!!” complete message. You will see that the interceptor method will only be executed once because in your log you will only see one entry (Figure 4.0c).
Figure 4.0c
SoapFaults will come back to Mule as exception (Figure 4.0d), notice the red dotted square (during debug mode) indicating an exception has been thrown (an error has occurred).
Figure 4.0d
When exception occured during a soap fault, the soap fault payload would be lost when it execution control is passed to “Catch Exception Strategy”, but we have used the intercepting java code to set the intercepted soap fault payload into a flow var, and in the catch exception strategy we have a set payload message processor to set the flow variable named “OriginalPayload” as the payload, this is so that the soap fault would be bubbled up into mule for later manipulation or display.
If the implementation is successful you will see the following response when you do a get on the mule app url (Figure 4.0a).
Figure 4.0a

8 comments:

  1. Hi Kian,

    Thanks for the detailed post. With the approach you mentioned, can we use a HTTP Transport component in WSC configuration? Will it still not swallow up the SOAP fault? Please suggest. We have been stuck on this for quite some time. Any suggestion would be appreciated.

    ReplyDelete

  2. Thanks for sharing such a great information..Its really

    nice and informative..

    training mulesoft

    ReplyDelete
  3. Thanks for sharing valuable information. Keep posting.
    mulesoft certification
    learn mulesoft

    ReplyDelete