Contact Us 1-800-596-4880

Customize a Message Thrown by a SoapFault

APIkit for SOAP uses the Apache CXF Framework to manage items related to SOAP messages. There is no connection between the exceptions handled internally and Mule exception strategies. If you want to customize the message thrown by a SoapFault, you can use the CXF interceptor.

This document uses the following product versions:

  • Anypoint Studio 6.4.4

  • Mule EE 3.9.0

  • SoapKit 1.0.3

  • SoapUI 5.4.0

Locate the Interceptor Components

  1. Open Studio 6 and import the attached project custom-soap-fault.zip file.

  2. In the unzipped file, locate the interceptor SoapFaultOutInterceptor.java in the src/main/java/org/example folder.

    Customizing the message from a SoapFault consists of editing the SoapFaultOutInterceptor.java and changing this statement as shown below:

    final Throwable myCustomError = new Throwable("This is a custom error message !!!");
    package org.example;
    
    import javax.xml.stream.XMLStreamException;
    
    import org.apache.cxf.binding.soap.SoapFault;
    import org.apache.cxf.binding.soap.interceptor.Soap11FaultOutInterceptor;
    import org.apache.cxf.interceptor.Fault;
    import org.apache.cxf.message.Message;
    import org.apache.cxf.phase.AbstractPhaseInterceptor;
    import org.apache.cxf.phase.Phase;
    
    /**
     * This interceptor runs just before create the SoapFault.
     * At this point you can change the exception used to create the SoapFault message
     * In this interceptor we are only change the exception when it is an instance
     * of XMLStreamException but you can adapt this behavior.
     */
    
    public class SoapFaultOutInterceptor extends AbstractPhaseInterceptor<Message> {
    
    	public SoapFaultOutInterceptor() {
    		super(Phase.PREPARE_SEND);
    		this.getBefore().add(Soap11FaultOutInterceptor.class.getName());
    		// If you are using SOAP version 1.2
    		//this.getBefore().add(Soap12FaultOutInterceptor.class.getName());
    	}
    
    	@Override
    	public void handleMessage(final Message message) {
      		 System.out.println("********** Start Custom SoapFault Interceptor ***********");
    
      		 // Original SoapFault
    	     final Fault f = (Fault) message.getContent(Exception.class);
    
    	     // Only Customize XMLStreamException
    	     if (f.getCause() instanceof XMLStreamException) {
    
    	    	 System.out.println("Original SoapFault:");
    	    	 System.out.println("\tClass: " + f.getCause().getClass());
    	    	 System.out.println("\tFaultCode :" + f.getFaultCode());
    	     	 System.out.println("\tCause :" + f.getCause().getMessage());
    
    	    	 final Throwable myCustomError = new Throwable("This is a custom error message !!!");
    	    	 final SoapFault myCustomFault = new SoapFault("Custom Error", myCustomError, f.getFaultCode());
    
    	    	 message.setContent(Exception.class, myCustomFault);
    	     }
    	     System.out.println("********** End Custom SoapFault Interceptor ***********");
    	}
    }

    In Studio, in the config file src/main/resource/cxf.xml are references to the interceptor:

    <?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"
    	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-2.0.xsd">
    
    <!-- 	<bean class="org.apache.cxf.interceptor.LoggingInInterceptor" id="logInbound"/> -->
    <!-- 	<bean class="org.apache.cxf.interceptor.LoggingOutInterceptor" id="logOutbound"/> -->
    	<bean class="org.example.SoapFaultOutInterceptor" id="soapfaultOutInterceptor"/>
    
    	<cxf:bus>
    		<cxf:features>
    			<cxf:logging/>
    		</cxf:features>
    
    <!-- 		<cxf:inInterceptors> -->
    <!-- 			<ref bean="logInbound"/> -->
    <!-- 		</cxf:inInterceptors> -->
    
    <!-- 		<cxf:outInterceptors> -->
    <!-- 			<ref bean="logOutbound"/> -->
    <!-- 		</cxf:outInterceptors> -->
    
    		<cxf:outFaultInterceptors>
    			<ref bean="soapfaultOutInterceptor"/>
    		</cxf:outFaultInterceptors>
    
    <!-- 		<cxf:inFaultInterceptors> -->
    <!-- 			<ref bean="logInbound"/> -->
    <!-- 		</cxf:inFaultInterceptors> -->
    	</cxf:bus>
    </beans>

Run the Application

Run the application from Studio.

*Run project soap* highlighted after right-clicking the application.

The application should deploy, and the following messages should appear in the Console:

**********************************************************************
* - - + APPLICATION + - - * - - + DOMAIN + - -  * - - + STATUS + - - *
**********************************************************************
* soap-SE-7813    * default                        * DEPLOYED        *

Send a SoapUI Request

  1. Using SoapUI, send a request to the deployed Mule app on port 8087.

    If you send an invalid XML, you see the SoapFault with the message customized in the SoapFaultOutInterceptor:

    SoapFault message in Studio.

    The console log should look like:

    ********** Start Custom SoapFault Interceptor ***********
    Original SoapFault:
    	Class: class com.ctc.wstx.exc.WstxParsingException
    	FaultCode :{http://schemas.xmlsoap.org/soap/envelope/}Client
    	Cause :Unexpected close tag </soapenv:Body>; expected </soapenv:Envelope>.
     at [row,col {unknown-source}]: [9,17]
    ********** End Custom SoapFault Interceptor ***********
    Studio project structure with *SoapFaultOutInterceptor* highlighted.
  2. To get rid of the console exception, you can change the log severity.

  3. Include this line (already included but commented out) in the src/main/resources/log4j2.xml file:

    <!-- CXF, avoid log for invalid XML messages, SE-7813 changing the severity to ERROR -->
     <AsyncLogger name="org.apache.cxf.phase.PhaseInterceptorChain" level="ERROR"/>