WSO2 Rule Mediator
The Rule mediator allows users to cope with the uncertainty of business logic through rule-based message mediation. Let’s see how we can develop simple rule mediator logic.
In this blog we will be using the below rule logic.
<brs:rule xmlns:brs="http://wso2.org/carbon/rules">
<brs:source>soapBody</brs:source>
<brs:target action="replace" resultXpath="//m0:symbol" xmlns:m0="http://services.samples" xpath="//m0:getQuote/m0:request/m0:symbol">soapBody</brs:target>
<brs:ruleSet>
<brs:properties/>
<brs:rule resourceType="regular" sourceType="inline"><![CDATA[
package SimpleRoutingRules;
rule InvokeIBM
when
symbol: String()
eval( symbol.equals("MSFT") || symbol.equals("SUN") )
then
update(drools.getWorkingMemory().getFactHandle(symbol),"IBM");
end
]]></brs:rule>
</brs:ruleSet>
<brs:input namespace="http://services.samples" wrapperElementName="getQuote">
<brs:fact elementName="symbol" namespace="http://services.samples" type="java.lang.String" xmlns:m0="http://services.samples" xpath="//m0:getQuote/m0:request/m0:symbol/child::text()"/>
</brs:input>
<brs:output namespace="http://services.samples" wrapperElementName="getQuote">
<brs:fact elementName="symbol" namespace="http://services.samples" type="java.lang.String"/>
</brs:output>
</brs:rule>
If we consider each section in the rule mediator,
source:
Specifies the source of the input message for the rule. In this case, it is set to “soapBody”
target:
Defines how the rule should modify the message. It uses the “replace” action and specifies an XPath expression (//m0:getQuote/m0:request/m0:symbol) to identify the element in the message that should be replaced. The replacement value is set to “soapBody,” which means that the content of the “soapBody” element will replace the matched element.
rule:
Defines the actual rule logic. This rule is named “InvokeIBM” and triggers when certain conditions are met. It checks if the “symbol” variable (which is expected to be a string) equals “MSFT” or “SUN.” If the conditions are met, it updates the fact represented by the “symbol” with the value “IBM”
input:
Specifies how the input fact for the rule should be extracted from the message. It defines an XPath expression to locate the “symbol” element within the SOAP message.
output:
Specifies how the output fact from the rule should be placed back into the message. It defines the element name (“symbol”) and its namespace for the output data.
In Summary,
It extracts the “symbol” element from the message, applies a rule called “InvokeIBM” to that symbol, and replaces the original “symbol” element with “IBM” in the message if certain conditions are met.
We can write the inline rules and also rules can be read from a registry resource as well. So let’s discuss both the approaches.
Approach 01: Using inline rules
Create a proxy service with the below content.
<?xml version="1.0" encoding="UTF-8"?>
<proxy name="testproxy" startOnLoad="true" transports="http https" xmlns="http://ws.apache.org/ns/synapse">
<target>
<inSequence>
<log level="full"/>
<brs:rule xmlns:brs="http://wso2.org/carbon/rules">
<brs:source>soapBody</brs:source>
<brs:target action="replace" resultXpath="//m0:symbol" xmlns:m0="http://services.samples" xpath="//m0:getQuote/m0:request/m0:symbol">soapBody</brs:target>
<brs:ruleSet>
<brs:properties/>
<brs:rule resourceType="regular" sourceType="inline"><![CDATA[
package SimpleRoutingRules;
rule InvokeIBM
when
symbol: String()
eval( symbol.equals("MSFT") || symbol.equals("SUN") )
then
update(drools.getWorkingMemory().getFactHandle(symbol),"IBM");
end
]]></brs:rule>
</brs:ruleSet>
<brs:input namespace="http://services.samples" wrapperElementName="getQuote">
<brs:fact elementName="symbol" namespace="http://services.samples" type="java.lang.String" xmlns:m0="http://services.samples" xpath="//m0:getQuote/m0:request/m0:symbol/child::text()"/>
</brs:input>
<brs:output namespace="http://services.samples" wrapperElementName="getQuote">
<brs:fact elementName="symbol" namespace="http://services.samples" type="java.lang.String"/>
</brs:output>
</brs:rule>
<respond/>
</inSequence>
<outSequence/>
<faultSequence/>
</target>
</proxy>
Approach 02: Using registry rule resource
Create registry resource with below content (For example, the registry resource can be created in, /_system/config/custom/rules.drl)
package SimpleRoutingRules;
rule InvokeIBM
when
symbol: String()
eval( symbol.equals("MSFT") || symbol.equals("SUN") )
then
update(drools.getWorkingMemory().getFactHandle(symbol),"IBM");
end
And use it in the proxy as below.
<?xml version="1.0" encoding="UTF-8"?>
<proxy name="testproxy" startOnLoad="true" transports="http https" xmlns="http://ws.apache.org/ns/synapse">
<target>
<inSequence>
<log level="full"/>
<brs:rule xmlns:brs="http://wso2.org/carbon/rules">
<brs:source>soapBody</brs:source>
<brs:target action="replace" resultXpath="//m0:symbol" xmlns:m0="http://services.samples" xpath="//m0:getQuote/m0:request/m0:symbol">soapBody</brs:target>
<brs:ruleSet>
<brs:properties/>
<brs:rule resourceType="regular" sourceType="registry">conf:/custom/rules.drl</brs:rule>
</brs:ruleSet>
<brs:input namespace="http://services.samples" wrapperElementName="getQuote">
<brs:fact elementName="symbol" namespace="http://services.samples" type="java.lang.String" xmlns:m0="http://services.samples" xpath="//m0:getQuote/m0:request/m0:symbol/child::text()"/>
</brs:input>
<brs:output namespace="http://services.samples" wrapperElementName="getQuote">
<brs:fact elementName="symbol" namespace="http://services.samples" type="java.lang.String"/>
</brs:output>
</brs:rule>
<respond/>
</inSequence>
<outSequence/>
<faultSequence/>
</target>
</proxy>
After you deploy the relevant carbon application with the proxy service (In my case it was testproxy), you can navigate to the ‘Home > Manage > Services > List’ and get the wsdl definition (Example: http://prabod:8280/services/testproxy?wsdl) and import it to the SOAP UI to create a project.
Then invoke the proxy service from the SoapUI as below.
Request:
http://prabod:8280/services/testproxy.testproxyHttpSoap11Endpoint
Request payload:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<m0:getQuote
xmlns:m0="http://services.samples">
<m0:request>
<m0:symbol>SUN</m0:symbol>
</m0:request>
</m0:getQuote>
</soapenv:Body>
</soapenv:Envelope>
After you make the request, you will be able to observe the below log with the payload received with the request (Using the log added before the rule mediator).
INFO {org.apache.synapse.mediators.builtin.LogMediator} - To: /services/testproxy.testproxyHttpSoap11Endpoint, WSAction: urn:mediate, SOAPAction: urn:mediate, MessageID: urn:uuid:92838e2f-44b5-4bdb-b607-c15e3e6924e4, Direction: request, Envelope: <?xml version='1.0' encoding='utf-8'?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body>
<m0:getQuote xmlns:m0="http://services.samples">
<m0:request>
<m0:symbol>SUN</m0:symbol>
</m0:request>
</m0:getQuote>
</soapenv:Body></soapenv:Envelope>
And in the SOAP UI you can observe the response after applying the rules logic based on the request payload.
<?xml version='1.0' encoding='UTF-8'?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body>
<m0:getQuote xmlns:m0="http://services.samples">
<m0:request>
<symbol xmlns="http://services.samples">IBM</symbol>
</m0:request>
</m0:getQuote>
</soapenv:Body></soapenv:Envelope>
Hope you have got an understanding on how to work with the rule mediator. For further reading please check the documentations [1] and [2].
[1] https://wso2docs.atlassian.net/wiki/spaces/EI660/pages/6521739/Setting+Up+the+ESB+Samples