Search code examples
javasoapfaultmule-esb

How to throw a custom exception from inside JAVA Transformer in Mule ESB 3.8?


I am implementing a SOAP service in Mule ESB version 3.8 using the HTTP and CXF component. Please see attached image for the flow design.

The Mule flow is :

  1. HTTP and CXF component exposes the web service which gives sum of two integers. The object send in request is :

public class AddValues{ private int a; private int b; public setA(int a) { this.a =a; } public getA() { return a; } public setB(int b) { this.b =b; } public getB() { return b; } }

  1. Save the SOAP action using a variable.
  2. Based on the SOAP Action route the Flow control.
  3. Using a JAVA transformer to receive the payload and throw Custom Web fault exception as follows:

    public class AddValuesBusinessLogic extends AbstractMessageTransformer 
    {
        @Override
        public Object transformMessage(MuleMessage message, String outputEncoding) throws TransformerException {
        MuleMessage muleMessage = message;
        AddValues addValues = (AddValues) muleMessage.getPayload();
        if (addValues.getA() == null || addValues.getB() == null ) {
            //Make an AddValueException object
            throw new Exception("Add value exception");
        }
        return null;
    }
    

    }

But i am getting the error "Surround with try/catch"

My question is if I surround and handle the exception, how am I going to send the SOAP Fault to end user?

Can someone please suggest what is the best way to send a custom SOAP Fault from JAVA Transformer in Mule ESB?


Solution

  • I found a solution using TransformerException and CXF OutFaultInterceptor. My approach is as follows:

    1. Write a custom transformer class inside which add the validation rules. For example, if I want to throw Error for Integer a or b being null, I will add a Custom Transformer AddValuesBusinessLogic.class with the following code:

      public class AddValuesBusinessLogic extends AbstractMessageTransformer 
      {
          @Override
          public Object transformMessage(MuleMessage message, String outputEncoding) throws 
          TransformerException 
          {
              MuleMessage muleMessage = message;
              AddValues addValues = (AddValues) muleMessage.getPayload();
              if (addValues.getA() == null || addValues.getB() == null ) {
              //Make an AddValueException object
              throw new TransformerException(this,new AddValueException("BAD REQUEST"));
          }
          return "ALL OK";}
      

    This exception will then propagate to CXF where I am writing an OutFaultInterceptor like follows:

    public class AddValuesFaultInterceptor extends AbstractSoapInterceptor {
    
        private static final Logger logger = LoggerFactory.getLogger(AddValuesFaultInterceptor.class);
    
        public AddValuesFaultInterceptor() {
            super(Phase.MARSHAL);
        }
    
        public void handleMessage(SoapMessage soapMessage) throws Fault {
            Fault fault = (Fault) soapMessage.getContent(Exception.class);
    
            if (fault.getCause() instanceof org.mule.api.transformer.TransformerMessagingException) {           
                Element detail = fault.getOrCreateDetail();
                Element errorDetail = detail.getOwnerDocument().createElement("addValuesError");
                Element errorCode = errorDetail.getOwnerDocument().createElement("errorCode");
                Element message = errorDetail.getOwnerDocument().createElement("message");
                errorCode.setTextContent("400");
                message.setTextContent("BAD REQUEST");
                errorDetail.appendChild(errorCode);
                errorDetail.appendChild(message);
                detail.appendChild(errorDetail);
            }
        }
        private Throwable getOriginalCause(Throwable t) {
            if (t instanceof ComponentException && t.getCause() != null) {
                return t.getCause();
            } else {
                return t;
            }
        }
    }
    

    Now when I make a call using either SOAPUI or jaxws client, I get the custom fault exception in the SOAP response.

    To extract the values of errorCode and errorMessage in JAXWS client I am doing the following in the catch block of try-catch:

    catch (com.sun.xml.ws.fault.ServerSOAPFaultException soapFaultException) {
    
        javax.xml.soap.SOAPFault fault = soapFaultException.getFault(); // <Fault> node
        javax.xml.soap.Detail detail = fault.getDetail(); // <detail> node
        java.util.Iterator detailEntries = detail.getDetailEntries(); // nodes under <detail>'
        while(detailEntries.hasNext()) {
            javax.xml.soap.DetailEntry detailEntry = (DetailEntry) detailEntries.next();
            System.out.println(detailEntry.getFirstChild().getTextContent());
            System.out.println(detailEntry.getLastChild().getTextContent());
        }   
    } 
    

    This is working for me as of now. However I will request suggestionsto improve on this workaound or if there are any better solutions.

    Thanks everyone.