Chapter Six. Message Routing

Introduction

This chapter discusses message routing patterns. It includes discussion and application of patterns from [EIP] Messaging Systems and Message Routing. The chapter briefly discusses where a Java CAPS solution developer can make routing decisions and discusses each of the routing patterns in turn, specifically Splitter, Aggregator, Resequencer, Scatter-Gather, Routing Slip, Process Manager, and Message Broker.

Overview

A messaging-based integration solution, whether or not and however it transforms messages as they pass through, inevitably routes messages from one or more sources to one or more destinations. A Java CAPS solution can make message routing decisions in four areas: the JMS Message Server, the connectivity map, the Java Collaboration definition, and the eInsight Business Process. Typical solutions that use just the eGate infrastructure would perform routing through the JMS Message Server, the connectivity map, and possibly the Java Collaborations. Typical solutions that use eInsight Business Process Management (BPM) would perform routing predominantly within eInsight Business Processes but may also route in the connectivity map. In all but the simplest solutions, routing will likely be performed by multiple components.

Routing in the JMS Message Server is performed as a consequence of configuring nondefault redelivery handling, which can divert messages to Dead Letter Queues. This issue was discussed in Chapter 5, “Messaging Infrastructure,” section 5.13.

The connectivity map, the graphical representation of how Java CAPS components are connected, is the means to both collect all integration solution components that will be deployed as part of a single enterprise application and to configure certain aspects of the message endpoints that are logical in nature, such as JMS Destination names and properties, or names and name patterns for file system objects. The simplest functional Java CAPS solution must have a minimum of two components: a message source and a service that operates on messages from that source. Unlikely as it may seem, in special circumstance, such an apparently useless solution might be valid and reasonable. What [EIP] calls the Channel Purger would be an example of a solution that receives messages from an endpoint and routes them to nowhere. Figure 6-1 shows a connectivity map for a basic Channel Purger.

Channel Purger

Figure 6-1. Channel Purger

This is the simplest example of message routing: Fixed Routing [EIP].

Note

Note

A Java CAPS implementer would typically look at the connectivity map for routing information—which components publish and subscribe to which JMS Destinations and how many, and which JMS Destinations are subscribed to/published to by an eInsight Business Process. For that reason, a solution that makes explicit routing decisions in Java Collaboration Definitions (JCDs) or Business Processes will be more difficult to analyze by an implementer new to it. It will also make it harder for the original developers to recall where and how routing decisions are made. If no other considerations dictate specific choices, given a choice of explicit routing in a JCD and explicit routing in an eInsight Business Process, choose the latter, as its graphical depiction of processing logic makes it more obvious that explicit routing takes place. Multiple subscriptions and/or publications by a service on a connectivity map are a strong hint that explicit routing is taking place inside a service component.

Message Router [EIP], a specialized Filter [EIP], represents a component in an integration solution that causes messages to be passed from a source to a destination depending on a possibly empty set of criteria. Unlike connectivity map–based fixed routing, Message Router variants that make explicit routing decisions programmatically can all be implemented in a Java CAPS solution using either JCDs or eInsight Business Processes or both.

The following sections discuss implementation of most of the router patterns using Java CAPS as the infrastructure.

Fixed Router

A fixed router, one where a single channel is a source of messages and a single channel is a destination, is the most trivial form of a Message Router. You would typically configure the connectivity map source and destination to configure a fixed router. If necessary, however, a Java Collaboration or a Business Process can be constructed to explicitly choose a destination if that destination is a JMS Destination.

Given the connectivity map shown in Figure 6-2, we would expect that the Java Collaboration publishes messages to the JMS Destination (queue) qDummyDestination.

Connectivity map of an implicit fixed router

Figure 6-2. Connectivity map of an implicit fixed router

Inspection of the collaboration source, shown in Figure 6-3, reveals that it is the JMS Destination (queue) qNewQueue that is the actual destination of messages. This destination is hardcoded in the fixed router.

Hardcoded JMS queue name in a fixed router, which uses a sendTo() OTD method

Figure 6-3. Hardcoded JMS queue name in a fixed router, which uses a sendTo() OTD method

The same effect could be achieved by explicit assignment of the destination queue name prior to sending the message, as shown in Figure 6-4.

Hardcoded JMS queue name in a fixed router using a “destination” OTD node

Figure 6-4. Hardcoded JMS queue name in a fixed router using a “destination” OTD node

Given the connectivity map shown in Figure 6-5, we would again expect the queue qDummyDestination to be the destination of messages.

Implicit fixed router connectivity map

Figure 6-5. Implicit fixed router connectivity map

Inspecting the business rules embedded in the eInsight Business Process, shown in Figure 6-6, reveals this to not be the case.

Explicit JMS queue assignment in a Business Process

Figure 6-6. Explicit JMS queue assignment in a Business Process

In this example, an explicit assignment of a JMS Destination name to the destination node of the JMS OTD results in messages being explicitly routed to a JMS Destination (queue) qNewJMSDestination.

Note

Note

In all of the previous examples, the JMS Destination name contained the literal Dummy. This is a hint to the developer who inspects the connectivity map that the actual destination is likely different and is configured within the component that publishes to the “dummy” destination. This is a good practice suggestion, since no part of Java CAPS enforces naming conventions.

Content-Based Router

Content of the message may dictate the destination to which the message must be delivered. Content-based Router [EIP] inspects the message it receives and sends it to a destination depending on the content.

In a simple case, a Java Collaboration or a Business Process would have a set of destinations hardcoded within a switch or an if-then-else construct that operates on all or part of the message. An example in Figure 6-7 is a simple Java Collaboration that illustrates dynamic JMS Destination selection.

Hardcode dynamic router

Figure 6-7. Hardcode dynamic router

A Business Process that implements a dynamic router can be constructed similarly, as the example in Figure 6-8 shows.

eInsight Business Process–based dynamic router

Figure 6-8. eInsight Business Process–based dynamic router

Here a decision gate inspects a message to determine which branch to follow. A Business Rules activity assigns a string literal to the JMS Destination’s destination attribute, and the JMS.send activity gets the message delivered to the destination so set.

Whether a JCD or a Business Process is used, the connectivity map for the example will be identical to that used for the fixed router in the example in the previous section (i.e., the name of the JMS Destination will be unrelated to the actual JMS Destination to which messages will be delivered).

In the two examples shown in Figures 6-7 and 6-8, a conditional was evaluated to determine the destination of the message, which was hardcoded. If additional destinations were required, the collaboration or the process would have to be modified, and the application containing it would have to be redeployed to propagate changes to the runtime environment. This implementation of a Content-based Router is potentially a high-maintenance implementation if destinations change frequently.

In a special case, you could use the message, or the message component, as the complete name or a part of the name of the destination. You would not need to use a conditional or hardcode destination names.

The JCD in Figure 6-9 appends the first 10 characters of the input message to a literal qDest to form the name of the destination. The message is then written to the destination with the resulting name.

Dynamically generating JMS Destination names

Figure 6-9. Dynamically generating JMS Destination names

If the first 10 characters of messages were PRIMARY??? and SECONDARY?, where ? represents a space character, the resulting destination names would be qDestPRIMARY and qDestSECONDARY respectively. If using the Sun SeeBeyond JMS implementation, which does not require you to preconfigure JMS Destinations ahead of time but rather creates JMS Destinations on first reference if they don’t already exist, this could result in a completely dynamic Content-based Router. You could introduce a message whose initial characters were something other than PRIMARY??? and SECONDARY?, and the Sun SeeBeyond JMS implementation would create a new JMS Destination with that appropriate name and deliver the message there. There may not be a receiver for the message delivered to the new destination, but the Content-based Router itself would be dynamic and would not require modification. Addition of a destination would not require redeployment of the application containing such a router if no other changes were needed to take advantage of the new route. This solution does not require maintenance of the router if the number of destinations changes but makes it difficult to determine to how many destinations messages are routed, as it removes the setting of the content, upon which routing decisions are made, from the router to some other component upstream from the router or even outside the integration solution altogether.

In the previous examples, a very simple text message was used and some leading or trailing characters were extracted from the text for use in the conditional or as a part of a destination name. Messaging systems will rarely deal with such unstructured text messages. Much more likely, messages will be structured. The contents of one or more fields in the message will then be used for routing decisions or destination name derivation. For simplicity, we will continue using simple text messages wherever message structure has no bearing on the discussion.

These trivial examples demonstrate how explicit routing can be performed programmatically within a JCD or a Business Process. This method will be used to set destinations for more complex Message Routers.

Message Filter

Message Filter [EIP] is a component in an integration solution that selectively processes messages. A Java CAPS solution offers two ways in which a Message Filter can determine whether or not to process a message.

If the message source is a JMS Destination, such as a queue or a topic, the Message Filter can be configured, through the connectivity map, to only accept messages whose attributes match an SQL-like selection expression. This method leverages the JMS selector mechanism. Rather than receiving a message and, if not of interest, discarding it, the JMS selector–based Message Filter prevents delivery of messages that do not match the selector expression to the filtering receiver. This mechanism is static in that the selection expression is configured through the connectivity map and cannot be changed without redeploying the enterprise application.

Java CAPS provides the means to implement a dynamic selection solution using a Java Collaboration. This technique, discussed at length in Chapter 5, section 5.6.7, and Chapter 11, “Message Correlation,” section 11.11, allows selection expression to change at runtime, thus providing the means to implement dynamic routing solutions.

Recipient List

By Saurabh Sahai

Often, it is required that a message be selectively sent to more than one recipient. The recipients that are to receive each message are determined either dynamically, based on the message content, or statically, based on external business rules. For example, an expense approval request message, pertaining to expenses below a certain amount, may get sent to the immediate manager for approval, whereas a message above the defined limit must also be sent to the business unit head for special approval.

A recipient list processor is similar to a Content-based Router; however, unlike a Content-based Router that routes the message to a specific destination based on message content, a recipient list processor sends the message to one or more designated recipients. The list of recipients can be static, hardcoded within the implementation, or dynamic, provided to the implementation from an externally maintained source. The latter approach provides greater flexibility as it allows the recipient list to be dynamically configured.

In Java CAPS, a recipient list can be implemented using either a JCD or a Business Process. In either case, once the message is received, the list of intended recipients is computed from the available recipients, and the message is forwarded as required.

The Java Collaboration shown in Figure 6-10 receives an expense report message for an amount greater than $300. Based on business rules, the collaboration looks up additional approvers that are required to approve this expense report and sends a copy of the message to these approvers in addition to the default approver. This is an example of a dynamic recipient list, where the collaboration uses information stored in an external store such as the organization’s Lightweight Directory Access Protocol (LDAP) server to create the required recipient list. Exception processing has been omitted in Figure 6-10 to focus on the essentials of the example.

Recipient list example

Figure 6-10. Recipient list example

In the example in Figure 6-10, the additional approval threshold has been hardcoded within the Java Collaboration. In a more realistic example, externally configurable delegation of authority rules would be loaded into the collaboration using one of the techniques for dealing with dynamic runtime reconfiguration of components, discussed elsewhere in the book.

The example uses a hypothetical sendMail() method to send the expense report to a recipient for approval. The collaboration could have equally validly used multiple JMS Destinations, a single JMS Destination with target recipient indicated using JMS user properties, a Batch eWay, WebSphere MQ eWay, or any number of other endpoints, as dictated by the environment or business requirements.

Splitter

By Saurabh Sahai

An incoming message may encapsulate one or more submessages. It is often desired to process submessages independently as separate messages. For example, an order message may consist of multiple order line items, each of which corresponds to a unique item type and may be fulfilled by a separate inventory store.

A splitter solves the problem of processing a composite message comprising multiple submessages, each of which may be processed differently by breaking up the message into individual messages and sending each separate message for further processing by a downstream component.

A splitter can be implemented in Java CAPS in multiple ways. Java Collaborations can be used to receive the composite message, iterate over the individual submessages, and, on the basis of the message content, send each of them to a unique destination that is responsible for processing a specific type of message.

The collaboration shown in Figure 6-11 is an example of processing an incoming message consisting of multiple order items. The collaboration iterates over each order item and creates a new message, enriched with the original order item information, and sends it for processing by a specific system. The item number contained in each order item is used to determine the destination address where the enriched order item message is to be sent. Exception processing has been omitted in the example to focus on the essentials of the example.

Dynamic content-based routing

Figure 6-11. Dynamic content-based routing

Splitter is a component that, as the name suggests, breaks messages into component parts. How easy or difficult it is to split original messages and create component messages largely depends on the size and complexity of the message structures involved. As a general rule, it is easier to handle a composite message with more than one level of components using a Java Collaboration than to do so using an eInsight Business Process. Implementing nested loops in a Java Collaboration is easier and more compact than doing the same in Business Process Execution Language (BPEL) using the graphical environment. While loops, whether single-level or nested, are clearly visible in an eInsight Business Process graphic, making it obvious that splitting is taking place, it is necessary to reset the target OTD structure prior to its being populated in each iteration, which is neither obvious nor easily discovered by the casual observer.

Aggregator

Aggregator [EIP] is a special Filter that collects related messages until some completeness condition has been reached, at which point it processes the related messages to obtain a single aggregated message that is then passed on to the next component.

An Aggregator must be able to correlate related messages, store related messages until ready to process, determine when the completeness condition is met, and implement the aggregation logic.

Java CAPS eInsight engine is a convenient tool to use for building Aggregators, as it inherently supports correlations and transparently stores related messages. The specific eInsight Business Process must only implement the completeness condition and the aggregation logic in order to become a specific Aggregator.

At the heart of every Aggregator is correlation logic, logic that determines which messages are related and therefore are subject to aggregation. Chapter 11 discusses at length the topic of message correlation with references to a number of specific examples presented in Part II (located on the accompanying CD-ROM). Chapter 11, section 11.10, discusses in detail a number of correlation implementations that incorporate an Aggregator.

Implementing an Aggregator without the benefit of eInsight is much harder. In addition to having to implement a completeness condition and aggregation logic, the solution designer must also do all the work related to storing and correlating messages. Chapter 11, section 11.11, discusses this topic and presents an example of how to accomplish the task of storing and correlating messages using just eGate and the Sun SeeBeyond JMS Message Server.

[EIP] discusses a number of completeness conditions an Aggregator might implement: Wait for All, Timeout, First Best, Timeout with Override, and External Event. Variants of these completeness conditions are discussed in Chapter 11, section 11.10. Implementing these conditions using eInsight with correlations is rather trivial. Implementing most of them using just eGate is much more difficult.

[EIP] also discusses a number of aggregation algorithms, including Select Best, Condense, and Collect for Later. Variants of these are also discussed in Chapter 11, section 11.10. Since aggregation will not start until all related messages are collected—that is, until the completeness condition has been satisfied—implementing aggregation logic is equally simple whether eInsight or eGate is used.

Resequencer

By Sebastian Krueger

Messages can arrive out of order for many reasons. If these messages are required to be delivered in sequence to a downstream component, the easiest solution would be to make sure that they never get out of order in the first place. Such approaches were discussed in Chapter 4, “Message Exchange Patterns,” section 4.8. However, there may be times when we don’t have a choice of how the upstream components are implemented; for example, we may control only the receiving side. Thus, the need to implement a component that will reorder messages may arise.

A number of implementations of a resequencer are possible. Chapter 4, section 4.2, “Resequencer,” in Part II, discusses and illustrates two implementations using examples: a simple buffered resequencer and a persisted resequencer, both of which are discussed in the remainder of this section.

The simple buffered resequencer operates as follows. When the resequencer receives a message, it adds that message to an internal buffer. It then sends all consecutive messages from the buffer.

In order to send all consecutive messages, the resequencer component needs to know the current sequence number index and whether a message with this index is in the buffer. If the index is not found in the buffer, then the message has not arrived yet. The resequencer will not send out buffered messages until at least the next message arrives.

A resequencer implementation requires all messages to have a unique sequence number. Not only do these sequence numbers have to be unique, they also have to be consecutive. That is, no gaps are allowed to exist in the sequence.

If a message gets lost and never arrives, messages would be queued up and would never be sent out because the resequencer component would be waiting for a message that will never arrive. To get around this issue, the designer could implement a solution whereby the resequencer only waits a set time for a message to arrive and then moves on to the next messages, effectively ignoring the message that never arrived. However, what if the message arrives late? What if a duplicate message arrives? Strategies for dealing with these conditions would have to be considered in designing a robust resequencer. The designer could, for example, discard the message, or send it to a Dead Letter Channel for alerting and auditing purposes.

When a simple resequencer starts, it expects the first message to have a sequence number of 0. However, what if this is not the case? For example, the resequencer might restart. Unless the sequence is persisted, the resequencer would expect the message sequence to start at 0 again. There are two ways to get around this problem. An initialization message could be sent that informs the resequencer which number is the start of the sequence. Alternatively, the sequence could be persisted so that it can be recovered in appropriate circumstances.

Another point that a simple resequencer does not handle is buffer overrun. If too many messages get queued up, the HashMap, used to store messages while assembling message sequences, may get too large to fit into the JVM allocated memory.

Implementation of a robust and scalable resequencer would require a significant amount of code and would likely be domain specific. An improved resequencer is discussed next. Implementation of a perfect resequencer is beyond the scope of this book.

An improvement to the previous resequencer would be to implement the buffer as a database table. By moving the message buffer to a persistent store, we solve two problems exhibited by the previous implementation. First, we effectively have an unlimited buffer, so no buffer overflow will occur. Second, in case of a server failure, buffered messages are not lost.

There are still unresolved issues with this persisted resequencer. The initialization of sequence numbers expects the first message to always start at 0. Also, we have not accounted for messages that never arrive. We briefly touched on the some of these issues in the previous section. They are out of the scope of this chapter.

While the two resequencers discussed in this chapter are by no means perfect, they do give examples of simple resequencers and give an indication of what is required to implement a robust resequencer.

Composed Message Processor

Composed Message Processor [EIP] is a higher-order component of a messaging system that accepts a message, breaks it up into submessages that are dispatched and processed by multiple lower-order components, then reassembles submessages into a final message.

In Java CAPS, as in any messaging system, implementation of a Composed Message Processor requires the use of correlations. Superficially, Composed Message Processor pattern is no different from the Scatter-Gather pattern [EIP]. Both involve breaking a message and reassembling the pieces once they are processed by independent intermediate components.

Chapter 11 discusses correlation implementation options provided by Java CAPS and presents a number of correlation examples. Section 11.10.5 provides a Java CAPS example of a Scatter-Gather pattern and Composed Message Processor pattern implementation.

Scatter-Gather

The Scatter-Gather [EIP] pattern involves breaking up a message, or replicating a message, delivering multiple messages to multiple components, then collecting related messages back together. Implementation of a Scatter-Gather pattern requires the use of correlations. It is discussed in various sections of Chapter 11.

Routing Slip

Routing Slip [EIP] is a mechanism that can be used to dynamically route a message through a series of components such that individual components do not embed routing logic. The route the message is to take can be computed by a router that embeds the necessary logic. This route is then attached to the message as a Routing Slip, and each component through which the message passes, once it performs its processing, forwards the message onto the next component specified in the Routing Slip. [EIP] discusses at length the rationale behind a desire to implement the Routing Slip pattern. Java CAPS, and its underlying JMS Message Server implementation, lends itself to building Routing Slip–based solutions; however, eInsight Business Processes may be better, in many circumstances, as an approach to conditional component invocation and dynamic route determination.

In a fixed Routing Slip solution, the message, once it leaves the router, is passed from component to component. There is no opportunity to change the message route once it is computed. An alternative to this approach is to have the router compute the next component to which to send the message, send the message to it, and have the component return the message back to the router once it is done. Routing decisions are still centralized, making routing logic simple to maintain, and the route the message takes can be changed by the router at any time based on the outcome of message processing.

In Java CAPS, a Routing Slip, or return destination, can be attached to the message in one of two ways. It can be passed via JMS user-defined properties if the message is passed from component to component over JMS, or the message can be packaged into an Envelope Wrapper and the Routing Slip can be incorporated into the Envelope metadata.

Envelope Wrapper is discussed at length in Chapter 8, “Message Transformation,” section 8.2. The route, computed by the router, could be represented in the Envelope node as a series of labels delimited by some delimiter, or an ordered, repeating collection of labels.

Chapter 4, section 4.3, “Routing Slip,” in Part II, illustrates this discussion with an example implementation of a Routing Slip pattern using Java Collaborations and JMS.

We could have used an eInsight Business Process to implement the kind of functionality that the Routing Slip facilitates. Each processing component could have been implemented as a New Web Service Java Collaboration or an eInsight subprocess. The Business Process would orchestrate execution of these components according to routing logic rules it implements.

Process Manager

One of the Routing Slip solutions involves a single routing component that determines the next component to which a message must be sent and receives the message back once the component is finished with it. This central routing component directs flow of messages using routing logic it embeds. Since it always receives messages that are processed by the processing components, it can modify the route a message is to take based on the outcome of processing by a particular component. Thus, the route the message finally takes may be different from the route a fixed router, which does not use intermediate processing results for routing decisions, would have determined.

Process Manager is a component that implements conditional routing logic and orchestrates execution of other processing components. Java CAPS supports implementation of the Process Manager, with functionality as described in the opening paragraph, as a Java Collaboration using JMS, possibly in Request/Reply mode, to dispatch and receive messages to and from processing components. The disadvantage of this approach is that the routing logic is hidden away in the Java code and, depending on the size and complexity of logic involved, may be difficult to understand.

Java CAPS eInsight Business Process Manager provides a graphical Business Process modeling environment. It overcomes the understandability limitations of a Java-only implementation and offers a number of features for Business Process modeling, component orchestration, and runtime monitoring that are not available with Java-only implementations.

Using eInsight Business Process Manager, you can implement any desired routing and component orchestration solutions. eInsight examples appear in most sections of this book and illustrate all manner of solutions of varying complexity. When a dynamic routing or component orchestration is required, eInsight Business Process can be developed to satisfy the requirement.

Message Broker

Message Broker [EIP] is an EAI architectural style wherein a component of a messaging system implements centralized routing for all messages flowing through the system. [EIP] also uses the term hub-and-spoke when referring to this architectural style. SeeBeyond’s DataGate 3.6 product, predecessor to eGate 4.x, ICAN 5.0, and Java CAPS 5.1, is a Message Broker–based EAI package.

Message Broker architecture allows decoupling of senders from receivers. The senders need not know where the messages are going, and receivers need not know from where the messages are coming. The Message Broker embeds all routing logic necessary to get messages from senders to receivers. This centralizes routing logic maintenance.

In Java CAPS, and ICAN before it, each connectivity map could be considered to represent a Message Broker–based solution. In effect, all collaborations and Business Processes present in a connectivity map route messages from sources to destinations. Each eInsight Business Process could also be considered a Message Broker implementation, as it, too, makes routing decisions when orchestrating a series of activities. Collections of connectivity maps sharing common channels could be considered hierarchies of Message Brokers [EIP].

While Java CAPS can certainly be used to implement centralized routing solutions in the spirit of Message Broker, doing so does not appear particularly necessary or particularly advantageous.

Chapter Summary

This chapter discussed [EIP] message routing and message routing–related patterns. It included discussion and application of patterns from [EIP] Messaging Systems and Message Routing.

The chapter briefly discussed where a Java CAPS solution developer can make routing decisions and discussed each of the routing patterns, specifically Splitter, Aggregator, Resequencer, Scatter-Gather, Routing Slip, Process Manager, and Message Broker.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset