Monday, July 6, 2009

When the Content Knows the Way - Content Based Routing in the SOA Platform

In 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:

1 <Order xmlns="http://org.jboss.soa.esb/Order" orderId="1" statusCode="0"
2 netAmount="59.97" totalAmount="64.92" tax="4.95">
3 <Customer userName="user1" firstName="Harry" lastName="Fletcher" state="SD"/>
4 <OrderLines>
5 <OrderLine position="1" quantity="1">
6 <Product productId="364" title="The 40-Year-Old Virgin " price="29.98"/>
7 </OrderLine>
8 <OrderLine position="2" quantity="1">
9 <Product productId="299" title="Pulp Fiction" price="29.99"/>
10 </OrderLine>
11 </OrderLines>
12 </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:

1 package com.jboss.soa.esb.routing.cbr
2
3 #list any import classes here.
4 import org.jboss.soa.esb.message.Message;
5 import org.jboss.soa.esb.message.format.MessageType;
6
7 expander XPathLanguage.dsl
8
9 #declare any global variables here
10 global java.util.List destinations;
11
12 rule "Blue Routing Rule using XPATH"
13 when
14 xpathEquals expr "/order:Order/@statusCode", "0" use namespaces "order=http://org.jboss.soa.esb/Order"
15 then
16 Log : "Blue Team";
17 Destination : "blue";
18 end
19
20 rule "Red Routing Rule using XPATH"
21 when
22 xpathEquals expr "/order:Order/@statusCode", "1" use namespaces "order=http://org.jboss.soa.esb/Order"
23 then
24 Log : "Red Team";
25 Destination : "red";
26 end
27
28 rule "Green Routing Rule using XPATH"
29 when
30 xpathEquals expr "/order:Order/@statusCode", "2" use namespaces "order=http://org.jboss.soa.esb/Order"
31 then
32 Log : "Green Team";
33 Destination : "green";
34 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.

1 comment:

JavaSuccess said...

when we have multiple conditions on when clause this seem to be useless