Go beyond sequential processing:
6.2 Whose message is this, anyway?
6.2.3 Routers with multiple destinations
Our payment example showed how to use a router when you have one possible desti- nation out of a few. This is the most common situation you’ll encounter, but it’s also possible to have more than one next destination channel for a message.
Let’s consider a notification system that has different ways of notifying customers and different notification types. A simple weather update may be sent through email, but more urgent notifications, such as a cancellation notice, may require sending a Short Message Service (SMS) text, an email, and placing an automated phone call at the same time to make sure the customer is reached by all means possible.
Because there is a single source of notifications, the notifications are sent on a sin- gle channel. From there, a router distributes them to the channels that correspond to the individual notification strategies: SMS, email, phone. The difference between this notification scenario and the payment scenario is that a notification can be sent by multiple channels simultaneously.
MULTIPLE RETURN VALUES
In the previous POJO-based example, the routePaymentSettlement method of the PaymentSettlementRouter returned a single value. But sometimes you must handle multiple values. Let’s consider the following configuration for notifications:
<channel id="notifications"/>
118 CHAPTER 6 Go beyond sequential processing: routing and filtering method="routeNotifications"> </router> <channel id="sms"/> <channel id="email"/> <channel id="phone"/>
The intent is to contact the client in as many ways as the business logic requires. Rout- ing logic must take into account both the notification settings of the user and the urgency of the notification. Receiving an automated phone call in the event of a can- cellation is pretty sensible, but being called every time there’s a sale doesn’t fall into the same category. Both are notifications, and will be delivered initially on the noti- fications channel, where they’ll be distributed by the router:
package siia.booking.integration.notifications;
import siia.booking.domain.notifications.FlightNotification; import siia.booking.domain.notifications.Priority;
import java.util.ArrayList; import java.util.List;
public class NotificationsRouter {
public String[] routeNotification(FlightNotification notification) { List<String> notificationTypes = new ArrayList<String>();
if (notification.getPriority() >= Priority.HIGH) { notificationTypes.add("phone"); } if (notification.getPriority() >= Priority.MEDIUM) { notificationTypes.add("sms"); } if (notification.getPriority() >= Priority.LOW) { notificationTypes.add("email"); }
return notificationTypes.toArray(new String[0]); }
}
In this case, the router sends messages to all the channels returned by the method, and please note that the resulting combination can vary from case to case (both the priority and the user settings are factors to be considered).
If the only job for the router is to dispatch messages to a set of fixed channels, the application can use a Recipient List Router.
RECIPIENT LIST ROUTERS
A recipient list router is slightly different from the routers you’ve seen so far that make decisions about the next destination channel. Recipient list routers are configured with a group of destination channels and will forward incoming messages to all of them.
You may wonder what such a router is good for. After all, publishing to multiple des- tinations is the job of a publish-subscribe channel. This may be true when you’re design- ing a system from scratch, but the recipient list router works well when the destination
119
Under the hood
channels are already defined and the target components are already listening to them. Another possible use is for broadcasting a message to multiple channel adapters:
<channel id="notifications"/> <recipient-list-router input-channel="notifications"> <recipient channel="sms"/> <recipient channel="email"/> <recipient channel="phone"/> </recipient-list-router> <channel id="sms"/> <channel id="email"/> <channel id="phone"/>
With such a configuration, any message sent to the notifications channel is automati- cally forwarded to all the channels defined on the recipient list of the recipient list router.
This overview of the message routers provided out of the box by the framework wraps up the second part of this chapter. Now you know pretty much all that you can do for filtering and routing by using the namespace configuration. If you’re inter- ested in learning more about the classes used to implement these features and how they interact, you’ll find more information in the next section, where we lift the hood and take a peek at the internal parts of the framework.
6.3
Under the hood
The most common way to use filters and routers is through the namespace configura- tion. This section dives deeper into details and explains what happens underneath. It’s optional reading, because knowing the internals of the framework isn’t a prerequi- site for using it efficiently.
But there are two valid reasons to investigate what happens inside the framework and what main actors are at play. First, it helps with debugging. Second, the frame- work provides a few out-of-the-box components that treat the most common use cases and allow you to create problem-specific implementations. Expanding the framework in such a way requires some detailed knowledge about the collaborating classes and the APIs provided by the framework, and this is what we focus on next.