Reputation: 535
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 :
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; } }
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?
Upvotes: 2
Views: 1540
Reputation: 535
I found a solution using TransformerException and CXF OutFaultInterceptor. My approach is as follows:
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.
Upvotes: 1
Reputation: 911
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.
Upvotes: 0