Sending a message to another JBI component
This section describes the mechanisms which provide
MessageExchanges transport between JBI components.
The messaging architecture in a Petals node is composed of 3 main layers to convey components messages.
The
DeliveryChannel, introduced in the JBI specifications, is the access point for JBI components to send messages. Each JBI component interacts with its
DeliveryChannel.
The Router, which is the core of the
NormalizedMessageRouter, assures the routing of
MessageExchanges toward their destinations.
It is the ''Router-impl'' Fractal component
The
Transporter, at the bottom level, provides the transport device to send and receive
MessageExchanges inside the PEtALS domain. It is the ''Joram-Transporter'' Fractal component

A service consumer asks for a service by sending a
MessageExchange object using the ''send()'' or ''sendSync()'' methods of its
DeliveryChannel.
A service provider treats requests from consumers by polling
MessageExchanges, using the ''accept()'' method of its
DeliveryChannel.
The consumer has to create and form a
MessageExchange object before using the ''send()'' method (via the
MessageExchangeFactory provided by the
DeliveryChannel).
MessageExchange implementation
This
MessageExchange, implemented by
org.objectweb.petals.jbi.messaging.MessageExchangeImpl is mainly composed of :
- the address of the service to invoke (an ''Interface'', ''Service'', or ''Endpoint''),
- the message to exchange (NormalizedMessage),
- its message exchange pattern (request, request-response),
- the DeliveryChannelImpl of the initiator of the exchange (the Consumer).
Sending a message asynchronously
When the
DeliveryChannel ''send()'' method is called, it begins by updating the status of the
MessageExchangeImpl, setting it to the terminate state if necessary.
If the
MessageExchangeImpl becomes terminated, and the ACK property is not set on the message, the
MessageExchangeImpl is not send. Otherwise, the
DeliveryChannelImpl calls the send() method of the
RouterImpl.
The
RouterImpl checks the current role of the
MessageExchangeImpl.
If the role is Consumer, it means that the message is addressed to the provider of the service, so the
RouterImpl asks to the
AdressResolver instance to resolve the targeted endPoint by calling ''resolveAdress()''. The
AdressResolver can deals with the register component to resolve the endPoint.
If the role is Provider, the consumer endPoint is already referenced in the
MessageExchangeImpl.
Once the endPoint retrieved, the
RouterImpl changes the current role of the
MessageExchangeImpl to match the role of the destination component.
Finally, it calls the ''send()'' method of the
Transporter implementation.
We propose for the moment only one implementation of the
Transporter, relying on JORAM, the
JoramTransporter. It takes care of the transport of the issued
MessageExchange to the destination address.
To optimize the transport, the
JoramTransporter cleans the payload of the
MessageExchangeImpl. This lightening permits to gain performance during serialization/unserialization processing and message transport duration.
A
MessageExchangeImpl is composed of a HashMap of
NormalizedMessageImpls, which constitute the payload of the message.
When an acknowledgement is sent, the attached
NormalizedMessageImpls are removed.
When a response
NormalizedMessageImpl is sent, the previous request
NormalizedMessageImpl, still attached to the
MessageExchangeimpl, is removed.
Receiving a message

Once the ''accept()'' method is called on the
DeliveryChannelImpl, this latter checks if he is opened, if so it calls the ''receive()'' method of the
RouterImpl.
The
RouterImpl extracts the name of the component from the
ComponentContextImpl, and calls the poll() method of the
JoramTransporter.
Any message issued in an asynchronous way is fetch from the JORAM server and returns by the
JoramTransporter.
Sending a message synchronously
When the issuer of the
MessageExchange want to send synchronously its message, a mechanism is supplied to correlate the
MessageExchangeImpl issued and the response received back.
In fact, the instance of
MessageExchange that the JBI component manipulates is a
MessageExchangeDecorator. This decorator contains a reference to a
MessageExchangeImpl.

When the ''sendSync()'' method of the
DeliveryChannelImpl is called, it extracts the
MessageExchangeImpl from the received
MessageExchangeDecorator, set SYNC properties to it and store it into an HashMap called ''waitingExchanges''.
After that, the normal processing of a send is called.
Once the send is done, a ''wait()'' is done on the
MessageExchangeDecorator, which makes the current thread to wait.

The
JoramTransporter is listening for the response by filtering incoming messages marked with the SYNC properties.
Once the response is received into the
JoramTransporter, it relays the
MessageExchangeImpl to the implementation of the
MessageExchangeListener, which is the
DeliveryChannelImpl by calling the method ''onMessageExchange()''.
Then the
DeliveryChannelImpl removes the SYNC properties from the
MessageExchangeImpl, retrieves the bounded
MessageExchangeDecorator from ''waitingExchanges'', attaches the
MessageExchangeImpl to it, notifies it to awaken the pending thread.
Finally, the awaken thread finishes the ''sendSync()'' method and returns true. The JBI component manipulates its
MessageExchangeDecorator to retrieve the response message.

In synchronous mode, it is possible to specify a timeout, to limit the duration of waiting a response. If the timeout is set, the wait done on the
MessageExchangeDecorator during the ''sendSync()'' processing is waiting until the response has been received OR until the timeout is reached.
If so, the owner of the
MessageExchangeDecorator is switched back, its status is set to the ERROR state and it is set to terminated.
Finally the ''sendSync()'' method returns false.