When the Content Knows the Way - Content Based Routing in the SOA Platform
Join the DZone community and get the full member experience.
Join For FreeIn my last post to this blog, I examined the ESB-jBPM integration in
the SOA Platform. This time, we'll take a look at one aspect of the
integration with JBoss Rules.
Introduction
The
routing of data from one place to another is one of the most basic, and
common, problems facing any networked software application. This
routing can take many forms, such as email being sent to the correct
recipient or network traffic being routed around the globe based on
system names defined in DNS.
In the context of an Enterprise
Service Bus such as the JBoss ESB in the SOA Platform, where everything
is either a message or a service, routing means getting messages
delivered to the correct services. There are multiple ways to route
data to a service. It's possible to define these routes statically,
which can make sense for an application where some type of data is
always directed to a set endpoint. But, this approach will fail if a
destination service is unavailable or is moved. You can control the
route that the messages take across the ESB in a number of ways. In
this post, we'll examine routing messages based on message content with
the content based routing pattern as illustrated in one of the SOA
Platform "quickstart" sample programs.
JBoss Rules
One
of the great challenges in developing business application software is
the separation between the business logic, or the "rules" that you want
to govern the application, and the technical programming tasks
necessary to actually build the application. What's more, it can be
expensive and difficult to maintain application code, and keep it in
synch with constantly changing business conditions and while not
destroying the original design and turning the code into a set of ever
more complex if-then-else statements. What's needed is a mechanism to
define the business rules and then execute the rules without having to
hardcode the rules into the application code.
What's needed is a
rules engine. JRS-94[1] defines the standard for a Java rules engine
API. The standard defines the API to register, retrieve and execute
rules. JBoss Drools[2] (referred to as JBoss Rules in the SOA Platform)
is based on this standard, but more than just a rules API and rules
programming language, Drools is a complete enterprise platform for
rules-based application development, workflow, administration, and
event processing. It also provides an integration with JBossESB to
support content based routing.
Let's start by examining at the
term "content based routing."[3] The routing part of the term is easy;
we're talking about getting messages routed to the correct service.
When we talk about "content based" routing, what we want to have happen
is to have the ESB examine a message, and based on its content, select
the correct routing path. But, we don't want to have the code to make
these routing decisions built into the services or the ESB itself. We
want to use a rules-based approach, where we can take advantage of the
power and flexibility of a rules definition language to construct the
decision making routing. We also want to take advantage of the
efficiency of a rules engine to perform this routing, instead of coding
complex and hard to maintain if-then-else statements into the
application.
OK. It's time to look at a working example.
One
of the great features of the SOA Platform is its extensive set of
"quickstart" programs. These programs illustrate various features
supported by the ESB. For our example, we'll look at the fun_cbr
quickstart.
Like many of the quickstarts, fun_cbr starts by
placing a message into a queue. A service listening to that queue then
takes that message and sends it to a destination service. What we're
interested in looking at in this quickstart, is how the content of that
message determines the route that the message takes to one of three
defined destination services.
Let's start by examining with the
message and its content. When you run the quickstart, the
"SampleOrder.xml" (for a mythical DVD store) is file is read into the
message that is sent. The file looks like this:
In SampleOrder.xml:
<Order xmlns="http://org.jboss.soa.esb/Order" orderId="1" statusCode="0"
netAmount="59.97" totalAmount="64.92" tax="4.95">
<Customer userName="user1" firstName="Harry" lastName="Fletcher" state="SD"/>
<OrderLines>
<OrderLine position="1" quantity="1">
<Product productId="364" title="The 40-Year-Old Virgin " price="29.98"/>
</OrderLine>
<OrderLine position="2" quantity="1">
<Product productId="299" title="Pulp Fiction" price="29.99"/>
</OrderLine>
</OrderLines>
</Order>
Nothing
in this content is that unusual (except perhaps for Harry's taste in
movies). Make a mental note of the "statusCode" element on line #1.
We'll come back to this in a bit.
OK, we have build a message
that contains this content and place that message in a queue so that a
service can receive it and execute an action on it. Now what?
Let's
look at that action in the "jboss-esb.xml" file. (This file defines the
configuration of, and the actions performed, by the quickstart.)
In jboss-esb.xml:
44 <action class="org.jboss.soa.esb.actions.ContentBasedRouter" name="ContentBasedRouter">
45 <property name="ruleSet" value="FunCBRRules-XPath.drl"/>
46 <property name="ruleLanguage" value="XPathLanguage.dsl"/>
47 <property name="ruleReload" value="true"/>
48 <property name="destinations">
49 <route-to destination-name="blue" service-category="BlueTeam" service-name="GoBlue" />
50 <route-to destination-name="red" service-category="RedTeam" service-name="GoRed" />
51 <route-to destination-name="green" service-category="GreenTeam" service-name="GoGreen" />
52 </property>
53 </action>
Let's examine this section of the file line-by-line:
Line
44: The org.jboss.soa.esb.actions.ContentBasedRouter class is one of
the SOA Platform's predefined "Out-of-the-box Actions." The SOA
Platform provides a set of these actions, that you can always augment
by writing your own custom actions[4]. Before you write your own, you
should take a look at the out-of-the-box actions as you may find one
that meets your application's needs.
Line 45: Here's where we
define the set of rules that govern the content based routing. Remember
that in this context, the rules are defined as JBoss Rules. We'll
examine these rules in just a minute.
Line 46: In order to be
able to parse information out of XML data in a message, the SOA
Platform includes a domain specific language (DSL) implementation to
use XPath to traverse the XML. This is defined in the
jboss-as/server/production/deploy/jbrules.esb/XPathLanguage.dsl file.
If you're unfamiliar with XPath[5], it's really worth learning as it
has many useful applications. For example, some GUI automation tools
such as Selenium support using XPath to locate UI elements if you are
unable to rely on the UI elements having static ID's. Also note that
XPathLanguage.dsl supports both namespace specific and non-namespace
specific syntaxes. In this quickstart, a namespace specific syntax is
used.
Line 47: This property allows you to specify if the rules
should be reloaded each time they are used. This has no effect on the
small set of rules used in the quickstart, but it can cause a
performance hit on a large set of rules. So, setting this to "true"
enables you to modify the rules as defined in the copy of
FunCBRRules-XPath.drl deployed to the server without having to redeploy
the quickstart to the SOA-P server. Modifying the local copy of the
rules file will not cause the rules to be reloaded. You have to update
the drl file that is deployed with the quickstart.
Lines 49-51: These are the routes to the destination services.
Now it's time to take a look at the rules that are defined in FunCBRRules-XPath.drl
In FunCBRRules-XPath.drl:
package com.jboss.soa.esb.routing.cbr
#list any import classes here.
import org.jboss.soa.esb.message.Message;
import org.jboss.soa.esb.message.format.MessageType;
expander XPathLanguage.dsl
#declare any global variables here
global java.util.List destinations;
rule "Blue Routing Rule using XPATH"
when
xpathEquals expr "/order:Order/@statusCode", "0" use namespaces "order=http://org.jboss.soa.esb/Order"
then
Log : "Blue Team";
Destination : "blue";
end
rule "Red Routing Rule using XPATH"
when
xpathEquals expr "/order:Order/@statusCode", "1" use namespaces "order=http://org.jboss.soa.esb/Order"
then
Log : "Red Team";
Destination : "red";
end
rule "Green Routing Rule using XPATH"
when
xpathEquals expr "/order:Order/@statusCode", "2" use namespaces "order=http://org.jboss.soa.esb/Order"
then
Log : "Green Team";
Destination : "green";
end
Line 7: Here is the reference to the XPath definitions.
Line 10: The destinations global variable is the point of integration to the destinations defined in the jboss-esb.xml file.
The
rules are all the same, except for the status code value, so we'll only
examine one of them. (In the process, we'll walk through a short lesson
in writing a rule.)
Line 12: The start of a rule definition.
Line
13: The start of the "when" construct of a rule. Each rule definition
includes a "when" construct (the criteria that must be met) and a
"then" construct (the action to take if the "when" construct is met).
Line
14: The XPath syntax translates to "starting at the root of the
document, find an Order element with a statusCode attribute equal to 0."
Line 15: The then construct starts here.
Line 16: Generate a log message
Line
17: Add a destination's name to the global list called "destinations, "
which is then evaluated by org.jboss.soa.esb.actions.ContentBasedRouter
that invoked the rule.
If you're getting a little lost now, this diagram may shows how things are connected.So what happens when the quickstart is deployed and run?
- An incoming message is placed into the queue that is watched by the listener configured with the ContentBasedRouter action
- That action is configured with the rule set defined in FunCBRRules-XPath.drl
- The action class puts the message into the Rules' working memory and fires the rules
- Based on the results of the rules, a list of destinations is created
- And the message is sent to the services at those destinations - in the case of this test, the message is sent to the blue team
(There's actually a bit more to it for the incoming message. JBoss ESB actually routes ESB formatted messages to services. The ESB supports adapters to enable other formats for incoming messages. These adapters operate with "gateway" services to enable you to connect existing services to the SOA Platform.[6])
Closing Thoughts
As we discussed in the introduction, one of the great strengths of the SOA Platform is the set of integrations that it supports. With its integration with JBoss Rules, you can deploy Rules-based services to the SOA Platform server and utilize JBoss Rules for content based routing. With content based routing, the information in the messages themselves determine the messages' destinations.
References
[1] http://jcp.org/en/jsr/detail?id=94
[2] http://www.jboss.org/drools
[3] http://www.jboss.org/jbossesb/docs/4.3.GA/manuals/html/services/ContentBasedRouting.html
[4] http://www.redhat.com/docs/en-US/JBoss_SOA_Platform/4.3.GA/html/Programmers_Guide/ch11s05.html
[5] http://www.w3schools.com/XPath/default.asp
[6] http://magazine.redhat.com/2008/05/22/adapters-for-an-esb
Acknowledgments
As always, I'd like to thank the members of the JBossESB (see http://anonsvn.labs.jboss.com/labs/jbossesb/trunk/Contributors.txt), JBoss Rules projects, SOA Platform project - especially Burr Sutter, Mark Little, Mark Proctor and Jarek Kijanowski - for their help and timely review comments! Also, this article relies heavily on the extensive JBossESB and JBoss Rules user documents and the quickstarts.
Published at DZone with permission of Len DiMaggio, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments