Multicasting messages (Intermediate)
Multicasting is the process of delivering the same message to multiple recipients at the same time. When the list of recipients is specified dynamically it is known as a Recipient List pattern. Camel supports both static and dynamic recipients. In this tutorial, we will specify the recipients as part of the route definition, but the same options apply also for dynamic recipients.
Getting ready
The complete source code for this tutorial is located under the project camel-message-routing-examples/multicasting-messages
.
How to do it...
When using a static Recipient List, we hardcode the outbound channels as part of the route definition. We can also specify a custom AggregationStrategy
, options for parallel processing, and whether to continue multicasting the message if an error occurs in any of the recipients.
from("direct:start") .multicast(new HighestQuoteAggregator()) .parallelProcessing().stopOnException(false) .to("mock:a", "mock:b", "mock:c") .end() .to("mock:result");
How it works...
When a message reaches multicast, if the parallelProcessing
options are not set, by default the message will be processed sequentially from the mock:a
, mock:b
, and mock:c
endpoints. But, notice that this is different from processing a message sequentially in a pipeline style by a Camel route. The reason is that multicast will create a copy of the original Exchange
for each recipient and mock:b
will not see any changes done by mock:a
or mock:c
. Each of the recipients will get their own copy of the original incoming Exchange
. One thing to keep in mind is that Camel will not do a deep copy and if we have any objects in the message body or headers, they will be shared across all recipients and potentially mutated concurrently. For these scenarios, a good place for making proper object copies is in the onPrepareRef
Processor:
.onPrepareRef(new Processor() { @Override public void process(Exchange exchange) throws Exception { Order body = exchange.getIn().getBody(Order.class); Order clone = body.deepClone(); exchange.getIn().setBody(clone); } })
Similarly to Splitter and Aggregator, we can use a custom AggregationStrategy
for aggregating replies from all recipients and create the outgoing message from the multicast. The default AggregationStrategy
will simply pick up the last reply from the recipients.
Also, notice that we had to specify the end of the multicast definition, otherwise all the remaining endpoints from the route would also be considered as part of the multicast. Then, there are options which are common with the Splitter pattern: executorServiceRef
, for custom thread pool, stopOnException
, to stop broadcasting a message to the remaining recipients in case of errors, shareUnitOfWork
, and so on. Sharing a unit of work allows multicasted Exchanges
to report back any failures and propagate the exceptions to the original Exchange
.
There's more...
There are two other Camel patterns which allow delivery of messages to multiple recipients: Recipient List which has very similar behavior to multicast but uses expression to choose the recipients dynamically; and Wire Tap which is a much simpler version of multicast and allows sending a copy of the incoming message to one additional recipient.
Dynamic multicasting
Using the Camel Recipient List is very similar to multicast, it supports the same options such as strategyRef
, parallelProcessing
, stopOnException
, onPrepareRef
, shareUnitOfWork
, streaming
, and timeout
, which have the same effect. The main advantage of the recipientList
statement is that it allows specifying the recipients dynamically using expression:
from("direct:a") .recipientList(header("recipients"));
A common way for specifying the recipients is with a header value as in the preceding example. The preceding example assumes that the recipients
header is set by a previous step. The expression used in recipientList
has to produce a result which is a java.lang.Iterable
such as java.util.Collection
, java.util.Iterator
, array
, org.w3c.dom.NodeList
, or a comma separated string value. Any other result will be treated as a single value. The values in the collection have to be either endpoints or string which will be converted to Endpoint
using URI syntax.
The Recipient List has two additional options: delimiter
that let us change the default delimiter (which is comma) for string values; and ignoreInvalidEndpoints
that tells whether to ignore unresolved endpoints or throw an exception.
Wire Tap
Wire Tap sends a copy of the incoming message to one separate channel while keeping the final destination of the message unchanged. By default, it will create a copy of the original message and process it using a separate thread pool in a fire-and-forget fashion.
Wire Tap cannot deliver messages to more than one additional destination or use dynamic recipients. Also, it doesn't allow propagating exceptions by sharing a unit of work or stopping when an exception is encountered. It is mainly useful for monitoring, logging, and troubleshooting purposes. It is fully documented on this page http://camel.apache.org/wire-tap.html.