Search code examples
wso2esbwso2-esb

How to generate a custome error in WSO2 ESB fault sequence based on service call?


I am trying to add some logic in the WSO2 ESB that will attempt to call a service as normal and return the response, but if for whatever reason there is a problem with the service I would like to check another service to see if it is down due to maintenance and then show the error message accordingly.

I tried using a fault sequence added to the proxy target. And with in this sequence I make a send call to a servlet, but it errors out saying that the response is not JSON which I know it is because it is hard coded.

Is this the correct way of doing this? What is the correct way of achieving this functionality?

Here is the servlet that will return an error code or message, currently it is hard coded:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    System.out.println("hit the servlet.......");
    response.setContentType("application/json");
    response.getWriter().append("{\"result\": \"1234\"}");
}

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    doGet(request, response);
}

Here is the Proxy:

<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse" name="mjstest" transports="https http" startOnLoad="true" trace="disable">
<target faultSequence="json_fault_handler">
    <inSequence>
        <log level="full"/>
        <property name="messageType" value="application/json" scope="axis2" type="STRING"/>
        <log level="full" category="TRACE"/>
        <send>
            <endpoint>
                <address uri="http://10.180.63.195:9088/rest/badServiceThatWillFailForThisTest" format="rest">
                    <timeout>
                        <duration>30000</duration>
                        <responseAction>fault</responseAction>
                    </timeout>
                    <suspendOnFailure>
                        <errorCodes>-1</errorCodes>
                        <initialDuration>0</initialDuration>
                        <progressionFactor>1.0</progressionFactor>
                        <maximumDuration>0</maximumDuration>
                    </suspendOnFailure>
                    <markForSuspension>
                        <errorCodes>-1</errorCodes>
                    </markForSuspension>
                </address>
            </endpoint>
        </send>
    </inSequence>
    <outSequence>
        <log level="full" separator=","/>
        <send/>
    </outSequence>
</target>

Here is the sequence:

<sequence xmlns="http://ws.apache.org/ns/synapse" name="json_fault_handler">
 <log category="INFO" level="custom" separator=",">
     <property name="failS" value="=======False Sequence==========="/>
 </log>
 <send>
     <endpoint>
         <address uri="http://localhost:8080/UGC_Images/BACMaintananceWindow" ></address>
     </endpoint>
 </send>
 <property name="messageType" value="application/json" scope="axis2"></property>

Any help is greatly appreciated.


Solution

  • So this is the solution I have working. It may not be the best of solutions but it does do what is needed. The solution flow is at follows:

    1. Attempt the original request
    2. If it fails, go to fault_handler, where
    3. goes to Java Class to read xml file to see if it is in maintenance block
    4. return values and show responce

    Here is the fault_handler:

    <sequence xmlns="http://ws.apache.org/ns/synapse" name="json_fault_handler">
    <log category="INFO" level="full" separator="," />
    <property xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope" xmlns:ns="http://org.apache.synapse/xsd" xmlns:ns3="http://org.apache.synapse/xsd" action="set" expression="get-property('ERROR_CODE')" name="ErrorCode" scope="default" type="INTEGER" />
    <log category="INFO" level="custom" separator=",">
        <property name="failS" value="=======False Sequence===========" />
        <property xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope" xmlns:ns="http://org.apache.synapse/xsd" xmlns:ns3="http://org.apache.synapse/xsd" expression="$ctx:ErrorCode" name="testCode" />
        <property xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope" xmlns:ns="http://org.apache.synapse/xsd" xmlns:ns3="http://org.apache.synapse/xsd" expression="get-property('Action')" name="Action" />
    </log>
    <class name="com.comp.synapse.mediator.ServiceMediatorClass"></class>
    <property action="set" name="HTTP_SC" scope="axis2" type="STRING" expression="$axis2:HTTP_SC" />
    <payloadFactory media-type="json">
        <format>{
            "code": "$1",
            "error": "$2",
            "error_description": "$3"
            }
        </format>
        <args>
            <arg expression="$axis2:SystemErrorCode" />
            <arg expression="$axis2:SystemErrorShort" />
            <arg expression="$axis2:SystemErrorDescription" />
        </args>
    </payloadFactory>
    <property action="set" name="messageType" scope="axis2" type="STRING" value="application/json" />
    <property action="remove" name="NO_ENTITY_BODY" scope="axis2" />
    <property action="set" name="RESPONSE" scope="default" type="STRING" value="true" />
    <header action="remove" name="To" />
    <send />
    

    Here is the mediator class method:

    public boolean mediate(MessageContext mc) {     
        org.apache.axis2.context.MessageContext msgContext = ((Axis2MessageContext) mc).getAxis2MessageContext();
        String httpStatusCode = ((Integer) msgContext.getProperty("HTTP_SC")).toString();
        String directory = "C:\\Temp\\maintenance.xml";
        File file = new File(directory);
        boolean inMaintenanceWindow = false;
        String errorDescription = "";
        Date now = new Date();
        try {           
            DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
            Document doc = dBuilder.parse(file);
    
            NodeList nList = doc.getElementsByTagName("downTimePeriod");
    
            for (int temp = 0; temp < nList.getLength(); temp++) {
                Node nNode = nList.item(temp);
    
                Date fromDate = null;
                Date toDate = null;
                SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy HH:mm");
                if (nNode.getNodeType() == Node.ELEMENT_NODE) {
                    Element eElement = (Element) nNode;
                    System.out.println("downTimePeriod id : " + eElement.getAttribute("id"));
                    String fromDateString = eElement.getElementsByTagName("FromDate").item(0).getTextContent();
                    String fromTimeString = eElement.getElementsByTagName("FromTime").item(0).getTextContent();
                    String toDateString = eElement.getElementsByTagName("ToDate").item(0).getTextContent();
                    String toTimeString = eElement.getElementsByTagName("ToTime").item(0).getTextContent();
                    fromDate = sdf.parse(fromDateString + " " + fromTimeString);
                    toDate = sdf.parse(toDateString + " " + toTimeString);
    
                    if(now.after(fromDate) && now.before(toDate)){
                        inMaintenanceWindow = true;
                        errorDescription = "Service is under maintenance until - " + toDateString + " " + toTimeString;
                        break;
                    }
                }
            }
        } catch (Exception e) {         
            e.printStackTrace();
        }
        if(inMaintenanceWindow){
            msgContext.setProperty("HTTP_SC", "503");
            msgContext.setProperty("SystemErrorCode", "503");
            msgContext.setProperty("SystemErrorShort", "Service is under maintenance.");
            msgContext.setProperty("SystemErrorDescription", errorDescription);
        }else{
            msgContext.setProperty("HTTP_SC", httpStatusCode);
            msgContext.setProperty("SystemErrorCode", httpStatusCode);
            msgContext.setProperty("SystemErrorShort", "Error occurred.");
            msgContext.setProperty("SystemErrorDescription", errorDescription);         
        }
    
        return true;
    }
    

    Hope this helps someone.