WSO2 ESB Rule Mediator Example


This post is to demonstrate how to write Rule mediator in WSO2 ESB.
This example is tested in WSO2 ESB 4.7.0
The example, get the list of students with marks for their subjects and, inside the proxy it check whether the each student has passed the each subject and print the result. To define type of the input data POJO adapters are used in this example.

1.Write the following POJO classes.

Student class

package com.example.rulemediator;

public class Student {

	private String indexNumber;
	private String name;
	private Subject[] subjects;

	public String getIndexNumber() {
		return indexNumber;
	}
	public void setIndexNumber(String indexNumber) {
		this.indexNumber = indexNumber;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Subject[] getSubjects() {
		return subjects;
	}
	public void setSubjects(Subject[] subjects) {
		this.subjects = subjects;
	}
}

Subject class

package com.example.rulemediator;

public class Subject {

	private String subjectCode;
	private String subjectName;
	private int score;

	public String getSubjectCode() {
		return subjectCode;
	}
	public void setSubjectCode(String subjectCode) {
		this.subjectCode = subjectCode;
	}
	public String getSubjectName() {
		return subjectName;
	}
	public void setSubjectName(String subjectName) {
		this.subjectName = subjectName;
	}
	public int getScore() {
		return score;
	}
	public void setScore(int score) {
		this.score = score;
	}
}

2. Then create a Jar file containing above classes and copy it to ESB_HOME/repository/components/lib folder and start the ESB.

3. Create a proxy service in ESB, and to define rules use a rule mediator as follow.

<proxy xmlns="http://ws.apache.org/ns/synapse"
name="StudentsEvaluator"
transports="https,http"
statistics="disable"
trace="disable"
startOnLoad="true">
<target>
<inSequence>
<property xmlns:ir="http://example.com/rulemediator"
name="INPUT"
expression="//ir:facts"
scope="default"
type="OM"/>
<brs:rule xmlns:brs="http://wso2.org/carbon/rules">
<brs:source>$INPUT</brs:source>
<brs:target action="replace">$OUTPUT</brs:target>
<brs:ruleSet>
<brs:properties/>
<brs:rule resourceType="regular" sourceType="inline">

package com.example.rule
//list any import classes here.
import com.example.rulemediator.Student;
import com.example.rulemediator.Subject;
import com.example.rulemediator.ResultSheet;

//declare any global variables here

rule "check for pass subjects"
when $student: Student()
$subj: Subject(score >= 50) from $student.getSubjects()
then
System.out.println($student.getName()+" passed "+$subj.getSubjectName()+".");
end

rule "check for failed subjects"
when $student: Student()
$subj: Subject(!(score >= 50)) from $student.getSubjects()
then
System.out.println($student.getName()+" failed "+$subj.getSubjectName()+".");
end
</brs:rule>
</brs:ruleSet>
<brs:input namespace="http://example.com/rulemediator" wrapperElementName="facts">
<brs:fact xmlns:ir="http://example.com/rulemediator"
elementName="Student"
namespace="http://example.com/rulemediator"
type="com.example.rulemediator.Student"
xpath="//ir:Student"/>
<brs:fact xmlns:ir="http://example.com/rulemediator"
elementName="Subject"
namespace="http://example.com/rulemediator"
type="com.example.rulemediator.Subject"
xpath="//ir:Student/ir:subjects"/>
</brs:input>
<brs:output namespace="http://example.com/rulemediator" wrapperElementName="out"/>
</brs:rule>
</inSequence>
</target>
<description/>
</proxy>

Here the POJO adapters get initialized with the xpath values. Drool is used to define rules and according to the rules, it prints each students result ( pass or fail) for every  subject.

Note: If you use an ArrayList to keep Subjects in Student class then you have to de-serialize the Subject object inside the POJO,
             Example code snippet for De-Serializing

public void setSubjects(List<Subject> subjects) {
     this.subjects = convert2Subjects(subjects);
}
private List convert2Subjects(List list){
    List subjectObjList = new ArrayList();
    try {
	String ns = "http://example.com/rulemediator";
	QName elSubjectCode = new QName(ns, "subjectCode");
	QName elSubjectName = new QName(ns, "subjectName");
	QName elScore = new QName(ns, "score");
	Subject subjectObj = null;
	for(int i =0; i<list.size(); i++){
	    subjectObj = new Subject();
	    OMElement complexNode = (OMElement)list.get(i);
	    subjectObj.setSubjectCode(complexNode.getFirstChildWithName(elSubjectCode).getText());
	    subjectObj.setSubjectName(complexNode.getFirstChildWithName(elSubjectName).getText());
	    subjectObj.setScore(Integer.parseInt(complexNode.getFirstChildWithName(elScore).getText()));
	    subjectObjList.add(subjectObj);
	}
    } catch (OMException e) {
	e.printStackTrace();
    }
    return subjectObjList;
}

 but in this example we are using an array instead of an array list, therefore no need to edit the POJO class as above.

4. Then using try this service or soapUI, send the following request,

<body>
 <ir:facts xmlns:ir="http://example.com/rulemediator">

  <ir:Student>
   <ir:indexNumber>4040</ir:indexNumber>
   <ir:name>Isuru</ir:name>

   <ir:subjects>
    <ir:subjectCode>001</ir:subjectCode>
    <ir:subjectName>Mathematics</ir:subjectName>
    <ir:score>89</ir:score>
   </ir:subjects>

   <ir:subjects>
    <ir:subjectCode>002</ir:subjectCode>
    <ir:subjectName>Physics</ir:subjectName>
    <ir:score>50</ir:score>
   </ir:subjects>

   <ir:subjects>
    <ir:subjectCode>003</ir:subjectCode>
    <ir:subjectName>Chemistry</ir:subjectName>
    <ir:score>45</ir:score>
   </ir:subjects>
 </ir:Student>

 <ir:Student>
   <ir:indexNumber>4041</ir:indexNumber>
   <ir:name>Vimesh</ir:name>
   <ir:subjects>
    <ir:subjectCode>001</ir:subjectCode>
    <ir:subjectName>Mathematics</ir:subjectName>
    <ir:score>95</ir:score>
   </ir:subjects>

   <ir:subjects>
    <ir:subjectCode>002</ir:subjectCode>
    <ir:subjectName>Physics</ir:subjectName>
    <ir:score>49</ir:score>
   </ir:subjects>

   <ir:subjects>
    <ir:subjectCode>003</ir:subjectCode>
    <ir:subjectName>Chemistry</ir:subjectName>
    <ir:score>98</ir:score>
   </ir:subjects>
 </ir:Student>
 <ir:Student> 
  <ir:indexNumber>4042</ir:indexNumber>
  <ir:name>Gayan</ir:name>
  <ir:subjects>
   <ir:subjectCode>001</ir:subjectCode>
   <ir:subjectName>Mathematics</ir:subjectName>
   <ir:score>43</ir:score>
  </ir:subjects>

  <ir:subjects>
   <ir:subjectCode>002</ir:subjectCode>
   <ir:subjectName>Physics</ir:subjectName>
   <ir:score>75</ir:score>
  </ir:subjects>

  <ir:subjects>
   <ir:subjectCode>003</ir:subjectCode>
   <ir:subjectName>Chemistry</ir:subjectName>
   <ir:score>95</ir:score>
  </ir:subjects>
 </ir:Student>
 </ir:facts>
</body>

5. When you send the above request, the output in ESB terminal will be,

Gayan failed Mathematics.
Gayan passed Chemistry.
Gayan passed Physics.
Vimesh failed Physics.
Vimesh passed Chemistry.
Vimesh passed Mathematics.
Isuru failed Chemistry.
Isuru passed Physics.
Isuru passed Mathematics.

 

Resources:
http://docs.wso2.org/display/ESB470/Rule+Mediator