Example of using Component Binding in Mule2 (part 3)

This is the last post in the series about using the Component Binding example in Mule2. In the previous two posts I explained the situation for which I use the component binding and how I configured this binding. In this post I show how I use the result of the component binding for targeting the next action.
After the component binding is called and I have both the original message and the corresponding response message in the payload of the MuleMessage (for context see here) the message is routed to ‘process-response’ VM queue. The configuration of this service looks like this:

<!--
- Process response from the application and check if order was processed successfully.
-->
<service name="ProcessOrderResponse">
  <inbound>
    <vm:inbound-endpoint path="process-response"/>
  </inbound>
  <component class="net.pascalalma.mule.ProcessResponse"/>
  <outbound>
    <filtering-router>
      <vm:outbound-endpoint path="order-post-service">
        <transformer ref="CreateFunctionOrderMessage"/>
        <transformer ref="JaxbObjectToXml"/>
      </vm:outbound-endpoint>
      <and-filter>
        <message-property-filter pattern="PROP_RESEND_ORIGINAL_PAYLOAD=true"/>
        <message-property-filter pattern="PROP_OPERATION=CREATE"/>
      </and-filter>
    </filtering-router>
    <filtering-router>
      <vm:outbound-endpoint path="order-post-service">
        <transformer ref="AppendFunctionOrderMessage"/>
        <transformer ref="JaxbObjectToXml"/>
      </vm:outbound-endpoint>
      <and-filter>
        <message-property-filter pattern="PROP_RESEND_ORIGINAL_PAYLOAD=true"/>
        <message-property-filter pattern="PROP_OPERATION=APPEND_INCREMENT"/>
      </and-filter>
    </filtering-router>
    <filtering-router>
      <vm:outbound-endpoint path="order-post-service">
        <transformer ref="AppendFunctionNewOrderMessage"/>
        <transformer ref="JaxbObjectToXml"/>
      </vm:outbound-endpoint>
      <and-filter>
        <message-property-filter pattern="PROP_RESEND_ORIGINAL_PAYLOAD=true"/>
        <message-property-filter pattern="PROP_OPERATION=APPEND"/>
      </and-filter>
    </filtering-router>
    <filtering-router>
      <vm:outbound-endpoint path="ignoreFurtherProcessing" />
      <message-property-filter pattern="PROP_RESEND_ORIGINAL_PAYLOAD=false"/>
    </filtering-router>
    <forwarding-catch-all-strategy>
      <vm:outbound-endpoint path="unknownEaiMessage">
        <transformer ref="JaxbObjectToXml"/>
      </vm:outbound-endpoint>
    </forwarding-catch-all-strategy>
  </outbound>
</service>

What the service does is it receives the combined message (described here) and passes it to the component ‘ProcessResponse’. This component ‘reads’ the response gotten from the ‘order service’ and based on the response adds some properties to the MuleMessage and sets its payload to either the original Order request message (if it has to be resend) or to the response originally gotten if the order request doesn’t have to be resend.
The source of the component ‘net.pascalalma.mule.ProcessResponse’ is shown here:

package net.pascalalma.mule;

import org.mule.api.lifecycle.Callable;
...

public class ProcessResponse implements Callable {

    private Logger logger = Logger.getLogger(ProcessResponse.class);
    private static final int MESSAGE_IS_RIGHTLY_PROCESSED = 0;
    private static final int ORDER_CANNOT_BE_DETERMINED = 4;
    private static final int MSG_REF_ALREADY_EXISTS = 8;
    private static final int ORDER_MAY_NOT_BE_SUPPLEMENTED = 16;
    private static final int MULTIPLE_SHIPMENTS_FOUND = 32;

    /**
     * This component checks the Order response. If a known error is detected,
     * the Original payload will be resend, including meta-data which the
     * transformer can use to modify the message.
     *
    */
    public Object onCall(MuleEventContext ctx) throws Exception {
        MuleMessage msg = ctx.getMessage();
        ObjectFactory of = new ObjectFactory();

        JAXBElement<myResponseType> jaxbElement = (JAXBElement<myResponseType>) msg.getPayload();

        MyResponseType myResponse = jaxbElement.getValue();
        OrderResponseType orderResponse = myResponse.getOrderResponse();

        if (!isMessageOK(orderResponse))
        {
            // Order reponse seems *not* OK ... determine reason");

            msg.setProperty(MuleConstants.SIP_RESEND_ORIGINAL_PAYLOAD, true);
            msg.setPayload( of.createInbound(myResponse.getInbound()) );

            if (responseContainsErrorCode(orderResponse, ORDER_CANNOT_BE_DETERMINED))
            {
                // Order not found, so appending not possible.
                // Re-ofer the order with 'create' option
                msg.setProperty(MuleConstants.SIP_OPERATION, Operation.CREATE);
            } else if (responseContainsErrorCode(orderResponse, ORDER_MAY_NOT_BE_SUPPLEMENTED)
                    || responseContainsErrorCode(orderResponse, MULTIPLE_SHIPMENTS_FOUND) )
            {
                // Adding to this order is not possible. Create a new ordernumber to append to.
                // First try to append to this new ordernumber due to threading
                msg.setProperty(MuleConstants.SIP_OPERATION, Operation.APPEND_INCREMENT);
            } else if (responseContainsErrorCode(orderResponse, MSG_REF_ALREADY_EXISTS))
            {
                // Creating a new orderr with this number is not possible.
                // Try to append to this ordernumber instead
                msg.setProperty(MuleConstants.SIP_OPERATION, Operation.APPEND);
            } else {
                // Unknown error situation. Just send the order-response
                msg.setProperty(MuleConstants.SIP_RESEND_ORIGINAL_PAYLOAD, false);
                msg.setPayload( of.createOrderResponse(myResponse.getOrderResponse()) );
            }
        } else {
            // Order response is OK, original payload will *not* be resend, instead
            // the Order response will be sent.
            msg.setProperty(MuleConstants.SIP_RESEND_ORIGINAL_PAYLOAD, false);
            msg.setPayload( of.createOrderResponse(myResponse.getOrderResponse()) );
        }
        return msg;
    }

    /**
     * Checks if incoming message is OK.
     * @param msg
     * @return
     */
    private boolean isMessageOK(OrderResponseType msg) {
        return responseContainsErrorCode(msg, MESSAGE_IS_RIGHTLY_PROCESSED);
    }
    private boolean responseContainsErrorCode(OrderResponseType msg, int errorCode) {
        if (msg != null) {
            for (LoggingType log : msg.getLogging()) {
                if (log.getErrorCode() == errorCode) {
                    return true;
                }
            }
        }
        return false;
    }
    public enum Operation {
    CREATE, APPEND, APPEND_INCREMENT;
    }
}

After the message is processed by the component it gets to the outbound endpoint. Here the next step is based on the properties set at the message by the component. Based on the situation (like described here) the original message is modified by using a transformer and rerouted to the order service or no further processing is necessary and the process ends here.
This post concludes a rather complete example of a real world situation in which Mule’s component binding offers a possible solution. We have chosen to do it this way but of course there might be other ways (even better??) to do this.

About Pascal Alma

Pascal is a senior IT consultant and has been working in IT since 1997. He is monitoring the latest development in new technologies (Mobile, Cloud, Big Data) closely and particularly interested in Java open source tool stacks, cloud related technologies like AWS and mobile development like building iOS apps with Swift. Specialties: Java/JEE/Spring Amazon AWS API/REST Big Data Continuous Delivery Swift/iOS
This entry was posted in Mule and tagged . Bookmark the permalink.