package com.example.switchyard.docs; public interface Example { public void process(MyData data); }
The Rules Component is a pluggable container in SwitchYard which allows business rules to be exposed as a service. One fronts their rules with a custom interface and, if desired, can easily annotate it's methods to define which should execute the rules. The Rules Component currently supports Drools as the rule engine. Even though it is quite simple to write rules in Drools, that project's developer tooling and business analyst tooling are very mature.
A Rules Service is a type of Knowledge Service (the other type being a BPM Service). Thus, it is strongly suggested you familiarize yourself with the shared configuration capabilities of Knowledge Services.
To create a new Rules service in SwitchYard, you'll need the following information
File Name : the file name that will be used to create a new template rules definition.
Interface Type : the contract for the service being provided. Rules services support Java, WSDL, and ESB contract types.
Service Name : the name of the service your process will provide.
Package Name : package name used for the new Rules file.
The MyService interface can be as simple as this, with no SwitchYard-specific imports:
package com.example.switchyard.docs; public interface Example { public void process(MyData data); }
The generated rule template will look like this:
package com.example.switchyard.docs import org.switchyard.Message global Message message rule "RulesExample" when // insert conditional here then // insert consequence here System.out.println("service: ExampleService, payload: " + message.getContent()); end
SwitchYard provides a flexible way to map data in and out service operation invocations via MVEL expressions. First, please familiarize yourself with the general Knowledge Services documentation, specifically the sections related to what Globals, Faults, Inputs and Outputs are. Next, consider the following tooling screenshot:
The above will create XML configuration like this:
<operation name="process" type="EXECUTE"> <globals> <global from="context['org.switchyard.messageId']" to="messageId"/> </globals> <inputs> <input from="message.content.policy"/> <input from="message.content.driver"/> <input from="context['org.example.foobar']"/> </inputs> <outputs> <output from="globals.Result" to="message.content"/> </outputs> <faults> <fault from="globals.Fault" to="message.content"/> </faults> </operation>
The associated DRL could look like this:
package org.switchyard.example.docs global java.lang.String messageId global java.util.Map globals rule "Approval" when policy : Policy(threshold >= 600) then policy.setFlag(true); globals.put("Result", policy); end rule "Denial" when policy : Policy(threshold < 600) then policy.setFlag(false); globals.put("Result", policy); end
Globals represent variable in your rules that do not trigger rule execution, but can be used in either the LHS or RHS of your rules for customization. They also provide a nice way to define in/out "buckets" so you can get data out of rule execution. In the example above, the messageId is a global variable, and a Map (called "globals") is as well. This way, we can set the outgoing SwitchYard Message content to the modified Policy.
The global variable called globals (java.util.Map) is always available for in/out purposes. You don't have to configure it in your <globals> section for it to be available to your DRL. (See above.)
If you want to use your own application object as in in/out variable, you are free to do so.
You can even dynamically create your own Map using MVEL and name it what you want. For example, "holder" as shown below:
<operation name="process" type="EXECUTE"> <globals> <!-- the from is an MVEL construct which creates a new Map --> <global from="['':'']" to="holder"/> </globals> <outputs> <!-- this assumes your DRL did a holder.put("out", someObject) at some point --> <output from="holder.out" to="message.content"/> </outputs> </operation>
For the Rules component, Inputs are the "facts" that are inserted into the Drools rules engine. In the example above, a Policy object, a Driver object, and a Context property. The rules engine will react to these inserted objects, building an agenda so that the appropriate RHS clauses will execute.
If you do not specify your own Inputs, the default will be the incoming Message content. If you do specify your own Inputs, the incoming Message content will not be inserted as a fact, and you will have to include "message.content" yourself, if desired.
Using in/out variables (for example, the global Map called "globals"), we can extract data out of the rules execution and into the outgoing Message content.
If you do not specify your own Outputs, the default will be the result of the expression "globals.Result".
If you do not specify your own Outputs, or in your DRL, you do not populate the "Result" of the globals Map, then your Rules component execution will return null. For IN_OUT Exchange patterns, this could obviously be a problem, so in those cases make sure you configure (or populate the default) Output correctly!
Fault mapping is similar to Output mapping, however the data represents an Exception or data that will be wrapped in an Exception.
By default, service method invocation will create a new Drools knowledge session, execute it given the passed-in domain data, and then be cleanly disposed.
However, it is possible to configure SwitchYard so that a stateful knowledge session will be used. Specifically, it will "stick around" spanning multiple invocations. (Please visit the Drools documentation to learn more about stateless vs. stateful knowledge sessions.) To do this, you use the FIRE_ALL_RULES action type instead of EXECUTE.
There is also a new capability which allows you to insert facts into a stateful knowledge session without firing the rules (you might want to do that later). In this case, use the INSERT operation type.
Complex Event Processing, or "CEP", is an advanced topic, and can best be explained in the Drools Fusion documentation. What will be shown here in the SwitchYard documentation is how it can be configured via XML. Obviously this can be set using the Eclipse tooling as well.
<implementation.rules ...> <operations> <operation eventId="FooStream" name="processFooMessage" type="FIRE_UNTIL_HALT"/> <operation eventId="BarStream" name="processBarMessage" type="FIRE_UNTIL_HALT"/> </operations> ... <properties> <property name="drools.clockType" value="realtime"/> <property name="drools.eventProcessingMode" value="stream"/> <property name="drools.maxThreads" value="1"/> <property name="drools.multithreadEvaluation" value="false"/> </properties> </implementation.rules>
A Resource represents an artifact that is required by your Rules component. It could be anything you could think of, including a properties file, a Drools Rule Language file, or whatever. But it needs to be available to the Rules component's runtime for that process. The list of resources available to your process is a configurable aspect of the Rules service component.
Please see the Listeners and Loggers sections found in the Knowledge Services documentation.
Please see the Channels section found in the Knowledge Services documentation.