Composite Materials

Ron Ten-Hove's Weblog
Tuesday Feb 07, 2006

Technical: JBI Component Implementation: Using ExchangeStatus

It seems that there is some confusion in the world of JBI component implementors about how the ExchangeStatus of a MessageExchange instance should be used. This usually arises when looking at the ExchangeStatus.ERROR state.

The following code and comments give a basic outline of how a typical JBI component should use the exchange status when accepting a message exchange from its delivery channel, and what the component can assume about the state of the exchange instance. Note that the the component's role (as either consumer or provider) is important in determining what conditions hold, especially in when the instance's status is ERROR.

/**
 * Process an accepted message exchange instance. An instance received by this
 * component can be sent by a component that is consuming a service that this
 * component is offering, or send by a service provider component that this component
 * is consuming.
 *
 * @param me the MessageExchange instance sent to this component by the NMR
 * 
 */
void processAcceptedMessageExchange(MessageExchange me)
{
    if (me.getStatus() == ExchangeStatus.ACTIVE)
    {
        // next step in the ping-pong game
    }
    else if (me.getStatus() == ExchangeStatus.DONE)
    {
        // The game is over; the partner component
        // is closing the MEP, and so should I.
        // For the following MEPs the following are true:
        //
        // Pattern  me.getRole() me Invariant
        // -------  ------       ------------
        // In       CONSUMER     getInMessage() != null && getError() == null
        // In-out   PROVIDER     getInMessage() != null && 
        //                       (getOutMessage() != null xor getFaultMessage() != null) &&
        //                       getError() == null
        //
        // (the patterns with optional responses are
        // more complex.)
    }
    else if (me.getStatus() == ExchangeStatus.ERROR)
    {
        // The game is over; the partner component 
        // is abruptly closing the MEP, and so should I.
        // The only ME property I can count on is 
        // me.getError(). Other ME properties will reflect
        // the on-going state of the exchange before it
        // was ending by the partner abruptly.
        //
        // Pattern  me.getRole() me Invariant
        // -------  ------------ ------------
        // In       CONSUMER     getError() != null && getInMessage() != null
        // In-out   PROVIDER     getInMessage() != null && getError != null &&
        //                       (getOutMessage() != null xor getFaultMessage() != null )
        // In-out   CONSUMER     getInMessage() != null && getError() != null &&
        //                       (getOutMessage() == null || getFaultMessage() == null)
    }
}
Notice that the invariants change in the ERROR case for the In-out exchange, depending on the role of the receiving component.

This gets more complex looking when we add in the robust-in-only and in-optional-out message exchange patterns, but the basic processing pattern remains the same.

This information isn't new: it's all in the JBI specification, but is scattered in several places, so it is understandable that the role of MessageExchange.getStatus() gets overlooked. This actually works well in the so-called "happy path" for In-only and In-Out MEPs, but becomes problematic in the ERROR case or when dealing with the MEPs that have optional exchanges in their patterns.

Comments:

Thanks, Can you please comment on setting the status as well?

Posted by Hossam Karim on February 18, 2006 at 04:26 PM EST #

The message exchange status is normally set to "DONE" when the appropriate participant in the exchange hits the point where the exchange is done. This is shown in section 5.4.2 of the JBI spec for each of the MEPs defined. Basically a component sets the ME status to "DONE" when it is following the MEP to completion, and staying within the WSDL-declared definition of the operation being performed. If, on the other hand, the component hits an error condition for which there is no way to convey an error message to the partner component (perhaps an in-only MEP), and the ME cannot be completed, then the component MAY set the status to ERROR (usually using the MessageExchange.setError(java.lang.Exception) method. A shown in the boilerplate code in the blog entry, this causes the ME instance to end abruptly, and takes a very different processing path. There may be other ways to deal with failures other than using setError(), using application-specific means.

Posted by Ron Ten-Hove on February 20, 2006 at 10:30 AM EST #

Post a Comment:
Comments are closed for this entry.

Archives
Links
Referrers