Wednesday, May 23, 2007

Working with JBoss Rules and Web Services

I've recently just done a project where JBoss Rules was used via web services. So thought I'd detail parts of what I did.

With this particular project only the root object from the payload was asserted, the payload was not split into smaller relational objects and asserted, which is generally considered best practice; however we do show you here how to effectively work with nested XML payloads using 'from'.

The steps I undertook can roughly be defined as:
  1. Create an XSD for your model.
  2. Generate the classes using JAXB's XJC, command line seems to have less issues.
  3. Unmarshal in your XML payload and assert the root object.
  4. Use from in your rules for model navitation.
  5. Retrieve the modified model and marshal.

Create an XSD for your model
First you need an XSD that describes your mode, this will look something like this:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="creditscore" targetNamespace="creditscore">
<xs:complexType name="root">
<xs:sequence>
<xs:element name="division" type="xs:string"/>
<xs:element name="occupancy" type="xs:string"/>
<xs:element name="occupancyAdjustment" type="xs:double"/>
<xs:element name="creditScore" type="CreditScore" minOccurs="0"/>
</xs:sequence>
</xs:complexType>

<xs:complexType name="CreditScore">
<xs:sequence>
<xs:element name="programGroup" type="xs:string"/>
<xs:element name="lienType" type="xs:string"/>
<xs:element name="division" type="xs:string"/>
<xs:element name="score" type="xs:double"/>
</xs:sequence>
</xs:complexType>

<xs:element name="Root" type="root"/>
</xs:schema>
Generate the classes using JAXB's XJC
The pojo model can now be created using JAXB's XJC. Get the latest JAXB reference implementation from sun, https://jaxb.dev.java.net/, I used jaxb 2.1.3. And execute the following from the command line:
jaxb-ri-20070413\bin\xjc -p org.domain -d c:\folder MyModel.xsd
This creates three objects, the ObjectFactory plus the two classes that represent Root and CreditScore, which look like this:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "root", propOrder = {"division", "occupancy", "occupancyAdjustment", "creditScore1", "creditScore2"})
public class Root {
@XmlElement(required = true)
protected String division;
@XmlElement(required = true)
protected String occupancy;
protected double occupancyAdjustment;
protected CreditScore creditScore1;
protected List creditScore2;

public String getDivision() {
return division;
}

public void setDivision(String value) {
this.division = value;
}

public String getOccupancy() {
return occupancy;
}

public void setOccupancy(String value) {
this.occupancy = value;
}

public double getOccupancyAdjustment() {
return occupancyAdjustment;
}

public void setOccupancyAdjustment(double value) {
this.occupancyAdjustment = value;
}

public CreditScore getCreditScore1() {
return creditScore1;
}

public void setCreditScore1(CreditScore value) {
this.creditScore1 = value;
}

public List getCreditScore2() {
if ( creditScore2 == null ) {
creditScore2 = new ArrayList();
}
return this.creditScore2;
}
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "CreditScore", propOrder = {"programGroup", "lienType", "division", "score"})
public class CreditScore {

@XmlElement(required = true)
protected String programGroup;
@XmlElement(required = true)
protected String lienType;
@XmlElement(required = true)
protected String division;
protected double score;

public String getProgramGroup() {
return programGroup;
}

public void setProgramGroup(String value) {
this.programGroup = value;
}

public String getLienType() {
return lienType;
}

public void setLienType(String value) {
this.lienType = value;
}

public String getDivision() {
return division;
}

public void setDivision(String value) {
this.division = value;
}

public double getScore() {
return score;
}

public void setScore(double value) {
this.score = value;
}
}
Unmarshal in your XML payload and assert the root object
You can now use JAXB to unmarshal your XML payloads, this example just takes the payload from disk:
JAXBContextImpl jc = (JAXBContextImpl) JAXBContext.newInstance( "org.domain" );
Unmarshaller unmarshaller = jc.createUnmarshaller();
JAXBElement element = ( JAXBElement ) unmarshaller.unmarshal( new File( XML_FILE ) );
Root root = ( Root ) element.getValue();
Use from in your rules for model navitation
'from' is a new element in JBoss Rules 4.0 that allows a rule to localy reason over data not asserted into the working memory. We can use 'from' to navigate to sub objects in the model.
package creditscore

import creditscore.CreditScore

rule "Credit_Score_Adjustments_0"
dialect "mvel"
no-loop true
when
r : Root( division=="wholesale",
occupancy=="Investors" )
cs : CreditScore( programGroup=="ACMEPowerBuyerGroup",
lienType=="FIRST_TD; SECOND_TD",
division=="Wholesale",
score >= 500,
score <= 579) from r.creditscore
then
cs.score = cs.score + 1;
modify(cs);
end

Retrieve the modified model and marshal
 RuleBase ruleBase = RuleBaseFactory.newRuleBase();
ruleBase.addPackage( pkg );

StatelessSession session = ruleBase.newStatelessSession();

StatelessSessionResult results = session.executeWithResults( new Object[] { root } );

Root returnedRoot = ( Root ) results.iterateObjects().next();
Marshaller marshaller = jc.createMarshaller();
marshaller.marshal( new JAXBElement( new QName("org.domain", "Root"), returnedRoot.getClass(), returnedRoot ), System.out );

8 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. Hi Mark Proctor,

    Drools Spring Integration.
    ~~~~~~~~~~~~~~~~~~~~~~~~~~
    This is Suresh, Can u give me a brief idea about Drools Integration with Springs

    because i am new to springs i didn't get where i can cal a drl file and how will i execute it.

    please help me,

    thanks and regards;
    Suresh

    ReplyDelete
  3. Ask on the mailing list, although yuou are probably best off asking on the spring mailing list than the jboss rules one.

    ReplyDelete
  4. This comment has been removed by the author.

    ReplyDelete
  5. We are developing a Factmodel which is the foundation of our new SOA infrastructure. The Factmodel is described as XSDs.
    We would like to avoid the marshalling/unmarshalling of XSD to Java or to have it automized with good performance. We plan to use a Rule Engine for Process decision points, validation etc.

    Could u please create an option in BRMS to import an XSD to be used as the Factmodel and not only a java package. Maybe a Factmodel adapter?

    How about XMI 2.x?

    I imagine there must be some tools out there for any conversion necessary...

    ReplyDelete
  6. If you have an XSD and the data is in XML you have to marshall, whether that marhsalling to a pojo class model (generated with xjc) or to some "template" type model the overhead is the same - more for the later. If you simple want an XSD to allow you to locally create facts, again a one off generation with XJC gives you a model you can instantiate and populate locally, there is little difference between a pojo approach or "template" - except the additional bytecode generation, which does not add any overhead that you should worry about.

    That said better modelling is planned for our next release and will be based, somewhat, on the OWL ontology language.

    ReplyDelete
  7. Rules in JBR work on POJOs/Java API. BRMS can import a set of java packages (fx from a jar file).
    What if existing "Business Model" is defined in XSD for use in WSDLs (SOA)?

    We would have to manually use a tool such as XJC to convert the XSDs to Java equivalent (POJOs), then import packages/jar in BRMS.

    Would be nice to have a more direct (1 step) model import feature - enabling direct importation of Fact model (to use for modellign rules) from an XSD.

    Better to have the BRMS resolve the XSD and marshal it into a set of java packages.

    Would be nice to be able to configure which XSD/Java mapper to be used in the BRMS config file.

    What if the model is defined as a DB schema or XMI.
    Would be nice to have a set of model adapters (seen in many BPMS systems) to be plugged in IoC style. In some instances additional mapping files might be needed (Castor/Hibernate style)?

    This "model to Java" mapping framework might already be out there to be plugged into BRMS?

    OWL sounds like an interesting modeling approach!

    ReplyDelete
  8. I have some rules which need to be exposed as webservices. Could you please tell us the best way to build ? This one you built by XML. What if I have simple then for a webservice.

    ReplyDelete