This site explains how ServiceMix implements and performs Normalized Message Routing in terms of both JBI- and ServiceMix-defined interfaces and classes.

Before reading this page, please have a look at the explanation of JBI, especially the Normalized Message Router.

See also How Stuff Works.

Principal Steps

Typically, normalized message routing consists of the following steps:

  • A component acting as Consumer sends a MessageExchange to its DeliveryChannel (methods: AsyncBaseLifeCycle.sendConsumerMessageExchange for asynchronous, several others, component-dependent ones for synchronous delivery)
  • The DeliveryChannel passes the MessageExchange to the NMR (method: send, sendSync)
  • The NMR chooses a Flow through which to send the MessageExchange
  • The Flow selects the Component which is the destined Provider (method: AbstractFlow.doRouting)
  • The Flow passes the MessageExchange to the DeliveryChannel of the component which is/has been found to be the Provider (method: processInBound.
  • The MessageExchange is either passed via push (if the Component implements {{MessageExchange}}Listener) or being put in a queue, from which the component can pull it.

Principal Classes and Interfaces

ServiceMix provides the following classes and interfaces relating to normalized message routing:

  • Broker and its subclasses corresponding to the NMR
  • Flow is a ServiceMix-interface for different dispatch policies
  • DeliveryChannelImpl is the DeliveryChannel implementation
  • MessageExchangeImpl is the implementation of MessageExchange

Broker and Implementations

The core ServiceMix NMR interface is the Broker. It has implementations: the DefaultBroker and the SecuredBroker, which adds basic authorization. For the later, see also Security.

MessageExchange and Implementation

A MessageExchange (ME) is a JBI-defined interface. It serves as a container for normalized messages following an exchange pattern, which specifies names, sequences and cardinalities for an excange.

Its ServiceMix implementation is MessageExchangeImpl.

Roles of an ME

As pointed out in the JBI page, an ME can be in different roles. A Role.PROVIDER indicates that an ME is being sent from a consumer to a provider, whereas a Role.CONSUMER means that the ME goes from the provider to the consumer.

The ServiceMix implementation never changes the role for a given instance of the MessageExchangeImpl class. Instead, the consumer component and the provider component are given two different objects, which are related to one another via the mirror property.

This is done to enforce exchange ownership; a component can not modify the exchange if it is not the owner. This is controlled by the CAN_OWNER flag and checked at several locations, e.g. various setter-methods.

MessageExchange instances are owned by either the initiator, servicer,
or NMR. Creating or accepting a message exchange instance confers
ownership on the creating (or accepting) component. Upon calling send()
for a particular ME instance, the component surrenders ownership of the
ME instance immediately. sendSync() causes ownership to be surrendered
during the course of the call; when the call ends (returning true) the
component resumes ownership of the ME instance.

Ownership of an ME instance gives the owner the right to read from and
write to the instance. When a component (or the NMR) doesn't have
ownership of an ME instance, it MUST NOT read from or write to the
instance, except for reading the message exchange status, which can be
queried regardless of ownership. If a component that is not the current
owner of the instance does attempt to call any method (other than
getStatus()) on the instance an appropriate
java.lang.IllegalStateException MUST be thrown.

(Taken from the JSR 208 Specification)

States of an ME

Depending on which kind of pattern was chosen, an ME can be in different states. In ServiceMix, these states depend on the ME}'s role. A given state encodes an {{ME's properties and allows or disallows certain operations.

ServiceMix models possible states via a 2-dimensional integer array (int [][]states). It is only being set in the constructor of MessageExchangeImpl and differs depending on the type of the ME (PROVIDER vs. CONSUMER).

Every row of the array corresponds to a description of a state with all possible succeeding states. The ownership mentioned above is also described within the states. The current state is being kept in an index variable pointing to the current state/row.

When being sent, the methods:

public void handleSend(boolean sync) throws MessagingException

...and:

public void handleAccept() throws MessagingException

... change the current state depending on the value of the ExchangeStatus and whether there is a Fault.

DeliveryChannel and Implementations

A DeliveryChannel (DC) provides for asynchronous, bi-directional communication between a Component and the NMR.

A DC is calling handleSend during its send and sendSync methods.

It is calling handleAccept during push-delivery in processInBound and accept.

  • No labels