Producer endpoints normally follow a synchronous pattern when
processing an exchange. That is, when the preceding processor in a chain calls
process() on a producer, the process() method blocks until a
reply is received. In this case, the processor's thread remains blocked until the producer
has completed the cycle of sending the request and receiving the reply.
Sometimes, however, you might prefer to decouple the preceding processor from the
producer, so that the processor's thread is freed up immediately and the
process() call does not block. In this case, you should
implement the producer using an asynchronous pattern, which gives
the preceding processor the option of invoking a non-blocking version of the
process() method.
To give you an overview of the different implementation options, this section describes both the synchronous and asynchronous patterns for implementing a producer endpoint.
Figure 4.6 shows an outline of a synchronous producer, where the preceding processor blocks until the producer has finished processing the exchange.
The synchronous producer processes an exchange as follows:
The preceding processor in the chain calls the synchronous process()
method on the producer to initiate synchronous processing. The synchronous
process() method takes a single exchange argument.
In the body of the process() method, the producer sends the request
(In message) to the endpoint.
If required by the exchange pattern, the producer waits for the reply
(Out or Fault message) to arrive from the
endpoint. Potentially, this step could cause the process() method to
block indefinitely. If the exchange pattern does not mandate a reply, however, the
process() method could return immediately after sending the
request.
When the process() method returns (potentially after having been
blocked for some time), the exchange object contains the reply from the synchronous
call (either an Out message or a Fault
message).
Figure 4.7 shows an outline of an asynchronous producer, where the producer processes the exchange in a sub-thread and the preceding processor is not blocked for any significant length of time.
The synchronous producer processes an exchange as follows:
Before the processor can call the asynchronous process() method, it
must create an asynchronous callback object, which is
responsible for processing the exchange on the return leg of the route. For the
asynchronous callback, the processor must implement a class that inherits from the
AsyncCallback interface.
The processor calls the asynchronous process() method on the producer
to initiate asynchronous processing. The asynchronous process() method
takes two arguments: an exchange object and a synchronous callback object.
In the body of the process() method, the producer creates a
Runnable object that encapsulates the processing code. The producer
then delegates the execution of this Runnable object to a
sub-thread.
The asynchronous process() method returns, thereby freeing up the
processor's thread.
Processing of the exchange now takes place in the separate sub-thread. First of
all, the Runnable object sends the In message to the
endpoint.
If required by the exchange pattern, the Runnable object waits for
the reply (Out or Fault message) to arrive
from the endpoint. The Runnable object remains blocked until the reply is
received.
After the reply arrives, the Runnable object inserts the reply
(Out or Fault message) into the exchange
object and then calls done() on the asynchronous callback object. The
asynchronous callback is then responsible for processing the reply message (executed
in the sub-thread).