2
votes

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?

2

2 Answers

1
votes

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.

0
votes

You should create your own SOAP Fault (plain Java String) and return it as a message. If you want, you can also create a transformer and put it in your catch-exception-strategy like this:

@Override
public Object transformMessage(MuleMessage message, String outputEncoding)
    throws TransformerException {

    String exceptionMessage = message.getExceptionPayload().getException().getCause().getMessage();        

    String outputMessage = "<soap:Fault xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">        " +
        " <faultcode>soap:Server</faultcode> " +
        "<faultstring>" + exceptionMessage + "</faultstring>" +
        "</soap:Fault>";

    return outputMessage;
}

Mule always expects Exceptions to be encapsulated in a TransformerException, so you should throw a new TransformerException setting your own Exception as the cause.