jboss drools

Download JBoss Drools

If you can't read please download the document

Upload: victorcr

Post on 16-Apr-2017

3.346 views

Category:

Documents


0 download

TRANSCRIPT

JBoss Drools

by Victor Polischuk

Business ProblemModel and Requirements

ParticipantPartyid

PartyDefpartyId

startTime

stopTime

publicCode

Roleid

publicCode

PartyRolepartyId

roleId

startTime

stopTime

OrderProductDefproductId

startTime

stopTime

publicCode

OrderItemorderId

quantity

productId

product

Orderid

time

inParty

inRole

outParty

outRole

inPartyId

inRoleId

outPartyId

outRoleId

Productid

Start-stop intervals must not overlap.

Entity exists only within start-stop interval.

Order must have valid and existent in party.

Order must have valid and existent out party.

Order must have valid and existent in role.

Order must have valid and existent out role.

Order items must have valid and existent product.

Order in and out parties must not be the same.

Order roles must be: (buyer, seller), (buyer, repairer), (repairer, seller), (seller, buyer).

Frontal AssaultConditions

public void placeOrder(Order order) {}

public void placeOrder(Order order) {PartyDef ip = dao.findPartyBy(...);}

public void placeOrder(Order order) {PartyDef ip = dao.findPartyBy(...);if (ip == null) {throw new Rule3Exception(...);}}

public void placeOrder(Order order) {PartyDef ip = dao.findPartyBy(...);if (ip == null) {throw new Rule3Exception(...);}PartyDef op = dao.findPartyBy(...);if (op == null) {throw new Rule4Exception(...);}}

public void placeOrder(Order order) {PartyDef ip = dao.findPartyBy(...);if (ip == null) {throw new Rule3Exception(...);}PartyDef op = dao.findPartyBy(...);if (op == null) {throw new Rule4Exception(...);}PartyRole ir = dao.findRoleBy(...);if (ir == null) {throw new Rule5Exception(...);}}

public void placeOrder(Order order) {PartyDef ip = dao.findPartyBy(...);

assertRule3(ip);

PartyDef op = dao.findPartyBy(...);

assertRule4(op);

PartyRole ir = dao.findRoleBy(...);

assertRule5(ir);}

public void placeOrder(Order order) {PartyDef ip = getValidatedByRule3(...);PartyDef op = getValidatedByRule4(...);PartyRole ir = getValidatedByRule5(...);}

public void placeOrder(Order order) {List problems = ;

PartyDef ip = getValidatedByRule3(...);PartyDef op = getValidatedByRule4(...);PartyRole ir = getValidatedByRule5(...); //???}

public void placeOrder(Order order) {List problems = ;

PartyDef ip = getValidatedByRule3(...);PartyDef op = getValidatedByRule4(...);if (ip != null) {PartyRole ir = getValidatedByRule5(...);}}

public void placeOrder(Order order) {List problems = ;

PartyDef ip = getValidatedByRule3(...);PartyDef op = getValidatedByRule4(...);if (ip != null) {PartyRole ir = getValidatedByRule5(...);}if (op != null) {PartyRole or = getValidatedByRule6(...);}}

public void placeOrder(Order order) {List problems = ;

PartyDef ip = getValidatedByRule3(...);PartyDef op = getValidatedByRule4(...);if (ip != null) {PartyRole ir = getValidatedByRule5(...);}if (op != null) {PartyRole or = getValidatedByRule6(...);}if (ip != null && op != null && ip == op) {problems.add(...); // Rule #8 violation}}

public void placeOrder(Order order) {List problems = ;

PartyDef ip = getValidatedByRule3(...);PartyDef op = getValidatedByRule4(...);PartyRole ir = getSafeValidatedByRule5(...);PartyRole or = getSafeValidatedByRule6(...);validateRule8(...);}

public void placeOrder(Order order) {List problems = ;

PartyDef ip = getValidatedByRule3(...);PartyDef op = getValidatedByRule4(...);PartyRole ir = getSafeValidatedByRule5(...);PartyRole or = getSafeValidatedByRule6(...);validateRule8(...);if (ir != null && or != null && (...)) {problems.add(...); // Rule #9 violation}}

public void placeOrder(Order order) {List problems = ;

PartyDef ip = getValidatedByRule3(...);PartyDef op = getValidatedByRule4(...);PartyRole ir = getSafeValidatedByRule5(...);PartyRole or = getSafeValidatedByRule6(...);validateRule8(...);validateRule9(...);if (problems.isEmpty()) {order.inPartyId = ip.partyId;...} }

public void placeOrder(Order order) {List problems = ;

PartyDef ip = getValidatedByRule3(...);PartyDef op = getValidatedByRule4(...);PartyRole ir = getSafeValidatedByRule5(...);PartyRole or = getSafeValidatedByRule6(...);validateRule8(...);validateRule9(...);fillOrderIdentifications(...);// TODO: Rule #7 }

Clean the MessIndependent Rules

ContextRuleRunnerRuleConfigDataRule

class RuleRunner...public List run( data) {List problems = ;Context context = ;RuleConfig config = ;while (config.hasNext(context)) {Rule rule = config.next(context);try {rule.execute(context, data);} catch () {problems.add(...);}
}}

class RuleConfig...private final List rules = ;public Rule next(Context context) {Rule rule = null;int i = context.getLatestRuleIndex();while (i < rules.size() && rule == null) {If (rules.get(i).accepts(context)) {rule = rules.get(i);}i++;}context.setLatestRuleIndex(i);return rules.get(i);}

interface Rule {

boolean accepts(Context context);

void execute(Context context, T data);

}

class RuleN3 implements Rule

public boolean accepts(Context ctx) {return true;}public void execute(Context ctx,Order data) {PartyDef ip = dao.findPartyBy(...);if (ip == null) {throw new Rule3Exception(...);}ctx.inPartyDef = ip;data.inPartyId = ip.partyId;}

class RuleN8 implements Rule

public boolean accepts(Context ctx) {return ctx.inPartyDef != null &&ctx.outPartyDef != null;}public void execute(Context ctx,Order data) {PartyDef ip = dao.findPartyBy(...);if (ctx.inPartyDef == ctx.outPartyDef) {throw new Rule8Exception(...);}}

One More StepExpert System

ContextRuleRunnerRuleConfigDataRule

WorkingMemoryRuleEngineKnowledgeBaseFactsRule

Simple Rule EngineRuleRuleRuleRule14563Decision Block

Decision BlockDecision BlockDecision Block

Result

Expert SystemRuleRuleRuleRule14563Decision Block

Decision BlockDecision BlockDecision Block

Result

Error?Fix RoutingProcess OrderEnd Processing

Fixed?

Rule 1Rule 2Rule 3Rule 4Rule N...

Fact 1Fact 2Fact 3Fact 4Fact M...

*

* Repeats = ?

Rule 1Rule 2Rule 3Rule 4Rule N...

Fact 1Fact 2Fact 3Fact 4Fact M...

*

* Repeats = ?

Inefficient

To the RescueRete

Rete = Net

Charles L. Forgy

1979

1974

1982

Wikipedia.org

Root Node

Start

All Facts Pass Through It

1-input Nodes

Alpha Network

IntraElement Conditions

2-input Nodes

Beta Network

Two Element Comparison

Terminal Nodes

Stop

Rules Have a Full Match

DroolsFinally

rule "Rule example" // Rule unique name... // Rule attributes: grouping, priority, etc.when... // Left hand side. Condition.then... // Right hand side. Consequence.end

Drools Rule Pattern

IF

THEN

rule "Rule #3 violation"when $o : Order($id:id, $t:time, $pty:inParty) not( Problem(orderId==$id, ruleId==3) ) eval( dao.findPartyBy($t, $pty)==null )then log.info("Rule #3 violated for the order: " + $id); insert(new Problem($id, 3));end

rule "Rule #3 fulfillment"when $o : Order(inPartyId==null, $id:id, $t:time, $pty:inParty) not( Problem(orderId==$id, ruleId==3) ) eval( dao.findPartyBy($t, $pty)!=null )then log.info("Rule #3 fulfilled for the order: " + $id); modify($o) { setInPartyId( dao.findPartyBy($t, $pty).getPartyId() ) };end

class RuleN3 implements Rule

public boolean accepts(Context ctx) {return true;}public void execute(Context ctx,Order data) {PartyDef ip = dao.findPartyBy(...);if (ip == null) {throw new Rule3Exception(...);}ctx.inPartyDef = ip;data.inPartyId = ip.partyId;}

If Java Is SimplerWhy Use Drools?

rule "Rule #7 violation"when $o : Order(items!=null, $id:id, $t:time) $item : OrderItem($prd:product) from $o.items not( OIProblem(orderId==$id, ruleId==7, product==$prd) ) eval(dao.findProductBy($t, $prd)==null)then log.info("Rule #7 violated for order: " + $id + " and product: " + $prd); insert(new OIProblem($id, 7, $prd));end

class RuleN7 implements Rule

public boolean accepts(Context ctx) {return true;}public void execute(Context ctx,Order data) {for (OrderItem item : data.items) {ProductDef pd = dao.findProductBy(...);

if (pd == null) {throw new Rule7Exception(...); //???} }}

Java Solution #1Complex Rule

class RuleN7_1 implements Rule

public boolean accepts(Context ctx) {return true;}public void execute(Context ctx,Order data) {for (OrderItem item : data.items) {ProductDef pd = dao.findProductBy(...);

if (pd == null) {ctx.addRule7Error(...); //OK} }}

Java Solution #2Complex Runner and Configuration

class RuleN7_2 implements Rule

public boolean accepts(Context ctx) {return true;}public void execute(Context ctx,OrderItem data) {ProductDef pd = dao.findProductBy(...);

if (pd == null) {throw new Rule7Exception(...); //OK}}

DroolsAgain?

rule "Rule #3 violation"when $o : Order($id:id, $t:time, $pty:inParty) not( Problem(orderId==$id, ruleId==3) ) eval( dao.findPartyBy($t, $pty)==null )then log.info("Rule #3 violated for the order: " + $id); insert(new Problem($id, 3));end

rule "Rule #7 violation"when $o : Order(items!=null, $id:id, $t:time) $item : OrderItem($prd:product) from $o.items not( OIProblem(orderId==$id, ruleId==7, product==$prd) ) eval(dao.findProductBy($t, $prd)==null)then log.info("Rule #7 violated for order: " + $id + " and product: " + $prd); insert(new OIProblem($id, 7, $prd));end

Yet Another Validation ToolOr Not?

package com.victor.droolsdialect "mvel"import com.victor.drools.*; // optional

global GeneralDao dao;global org.slf4j.Logger log;

declare Problem orderId : long @key ruleId : int @keyenddeclare OIProblem extends Problem product : String @keyend

declare ExampleClass // Class name[extends ParentExampleClass] // Inheritance@stringMetadata("I am String") // Metadata@dateMetadata(01-Jan-1970)

propertyName1 : ValidType, // PropertiespropertyName2 : AnotherValidTypeend

Drools Class Declaration

rule "Rule #7 violation"when $o : Order(items!=null, $id:id, $t:time) $item : OrderItem($prd:product) from $o.items not( OIProblem(orderId==$id, ruleId==7, product==$prd) ) eval(dao.findProductBy($t, $prd)==null)then log.info("Rule #7 violated for order: " + $id + " and product: " + $prd); insert(new OIProblem($id, 7, $prd));end

function String hello(String name) { return "Hello "+name+"!";}

Drools Function Declaration

rule "Function usage in LHS"when eval( hello("Victor")!="Hello Victor!" )thenint faults = ++alexeyFaults.count; log.fatal("Alexey, fix hello(..) function"); log.anger("You'd better be off"); log.info("You've broken it " +faults+ " time(s)");end

rule "Function usage in RHS"when eval(true)then log.happiness(hello("Victor")); log.worship(hello("Master"));end

query "Orders with inParty" $o : Order(inParty != null)end

query "Orders with inRole equals to" (String role) $o : Order(inRole == role)end

Drools Query Declaration

template headerfield1... // Template fieldstemplate TemplateName rule "ExampleRule_@{row.rowNumber}"... // Usage of declared fieldsendend template

Drools Templates

Promotional discount rulesAge BracketNumber of prior claimsPolicy type applying forDiscount %

Rewards for safe drivers18,240COMPREHENSIVE1

18,240FIRE_THEFT2

25,301COMPREHENSIVE5

25,302COMPREHENSIVE1

25,300COMPREHENSIVE20

jboss.org

Pice de RsistanceDSL

rule "Rule #3 violation"when $o : Order($id:id, $t:time, $pty:inParty) not( Problem(orderId==$id, ruleId==3) ) eval( dao.findPartyBy($t, $pty)==null )then log.info("Rule #3 violated for the order: " + $id); insert(new Problem($id, 3));end

rule "Rule #3 violation"whenEvery OrderWithout violations of rule 3Which violates inParty constraintsthenAdd the violation of the rule 3end

[when] Every Order = $o : Order($id:id, $t:time, $inPty:inParty)

[when] Without violations of rule {ruleNumber} = not(Problem(orderId==$id, ruleId=={ruleNumber}))[when] Which violates inParty constraints = eval( dao.findPartyBy($t, $inPty) == null )

[then] Add the violation of the rule {ruleNumber} = log.info("Rule #" + {ruleNumber} + " violated for order: " + $id); insert(new Problem($id, {ruleNumber}));

rule "Rule #4 violation"whenEvery OrderWithout violations of rule 4Which violates outParty constraintsthenAdd the violation of the rule 4end

[when] Every Order = $o : Order($id:id, $t:time, $inPty:inParty)

[when] Without violations of rule {ruleNumber} = not(Problem(orderId==$id, ruleId=={ruleNumber}))[when] Which violates inParty constraints = eval( dao.findPartyBy($t, $inPty) == null )

[then] Add the violation of the rule {ruleNumber} = log.info("Rule #" + {ruleNumber} + " violated for order: " + $id); insert(new Problem($id, {ruleNumber}));

[when] Every Order = $o : Order($id:id, $t:time, $inPty:inParty,$outPty:outParty)

[when] Without violations of rule {ruleNumber} = not(Problem(orderId==$id, ruleId=={ruleNumber}))[when] Which violates inParty constraints = eval( dao.findPartyBy($t, $inPty) == null )[when] Which violates outParty constraints = eval( dao.findPartyBy($t, $outPty) == null )[then] Add the violation of the rule {ruleNumber} = log.info("Rule #" + {ruleNumber} + " violated for order: " + $id); insert(new Problem($id, {ruleNumber}));

Seven?Let's have fun

rule "Rule #7 violation"when $o : Order(items!=null, $id:id, $t:time) $item : OrderItem($prd:product) from $o.items not( OIProblem(orderId==$id, ruleId==7, product==$prd) ) eval(dao.findProductBy($t, $prd)==null)then log.info("Rule #7 violated for order: " + $id + " and product: " + $prd); insert(new OIProblem($id, 7, $prd));end

rule "Rule #7 violation"when $o : Order(items!=null, $id:id, $t:time) $item : OrderItem($prd:product) from $o.items not( OIProblem(orderId==$id, ruleId==7, product==$prd) ) eval(dao.findProductBy($t, $prd)==null)then log.info("Rule #7 violated for order: " + $id + " and product: " + $prd); insert(new OIProblem($id, 7, $prd));end

rule "Rule #7 violation"when $o : Order(items!=null, $id:id, $t:time) $item : OrderItem($prd:product) from $o.items not( OIProblem(orderId==$id, ruleId==7, product==$prd) ) eval(dao.findProductBy($t, $prd)==null)then log.info("Rule #7 violated for order: " + $id + " and product: " + $prd); insert(new OIProblem($id, 7, $prd));end

rule "Rule #7 violation"when $o : Order(items!=null, $id:id, $t:time) $item : OrderItem($prd:product) from $o.items not( OIProblem(orderId==$id, ruleId==7, product==$prd) ) eval(dao.findProductBy($t, $prd)==null)then log.info("Rule #7 violated for order: " + $id + " and product: " + $prd); insert(new OIProblem($id, 7, $prd));end

rule "Rule #7 violation"when $o : Order(items!=null, $id:id, $t:time) $item : OrderItem($prd:product) from $o.items not( OIProblem(orderId==$id, ruleId==7, product==$prd) ) eval(dao.findProductBy($t, $prd)==null)then log.info("Rule #7 violated for order: " + $id + " and product: " + $prd); insert(new OIProblem($id, 7, $prd));end

rule "Rule #7 violation"when Every Order - which has items And every OrderItemWithout violations of order item rule 7 Which violates product constraintsthenAdd the violation of the rule 7 for the order itemend

[when] Every Order =

[when] Without violations of rule {N} =[when] Which violates inParty constraints =[when] Which violates outParty constraints =

[then] Add the violation of the rule {N} =

[when] Every Order = [when] - which has items = items != null

[when] And every OrderItem =[when] Without violations of rule {N} =[when] Which violates inParty constraints =[when] Which violates outParty constraints =[when] Without violations of order item rule {N} = [when] Which violates product constraints =

[then] Add the violation of the rule {N} for order item = [then] Add the violation of the rule {N} =

I Do BelieveAm I Alone?

Meanwhile in the Real World...Requirements Change

Start-stop intervals must not overlap.

Entity exists only within start-stop interval.

Order must have valid and existent in party.

Order must have valid and existent out party.

Order must have valid and existent in role.

Order must have valid and existent out role.

Order items must have valid and existent product.

Order in and out parties CAN be the same. ONLY IF they have roles (seller, repairer).

Order roles must be: (buyer, seller), (buyer, repairer), (repairer, seller), (seller, buyer). OR (seller, repairer) if they are the same.

rule "Rule #8 violation"when $o : Order(inPartyId != null, outPartyId != null,outPartyId == inPartyId,$id : id) not( Problem(orderId == $id, ruleId in (3, 4, 8)) )then log.info("Rule #8 violated for order: " + $id); insert(new Problem($id, 8));end

rule "Rule #8 violation"when $o : Order(!(inRole == "S" && outRole == "R"),inPartyId != null, outPartyId != null,outPartyId == inPartyId,$id : id) not( Problem(orderId == $id, ruleId in (3, 4, 8)) )then log.info("Rule #8 violated for order: " + $id); insert(new Problem($id, 8));end

rule "Rule #8 violation"when Every Order- with inPartyId- with outPartyId- where inPartyId equals outPartyId - and inRole not "S" and outRole not "R" Without violations of rules [3,4,8]thenAdd the violation of the rule 8end

rule "Rule #8 exceptional case"// salience 100when $o : Order(inRole == "S", outRole == "R",inPartyId != null, outPartyId != null,outPartyId == inPartyId,$id : id)then log.info("Rule #8 special case for order: " + $id);insertLogical(new SkipRule($id, 8));end

rule "Rule #8 violation"when $o : Order(inPartyId != null, outPartyId != null,outPartyId == inPartyId,$id : id)not( SkipRule(orderId == $id, ruleId == 8) ) not(Problem(orderId == $id, ruleId in (3, 4, 8)) )then log.info("Rule #8 violated for order: " + $id); insert(new Problem($id, 8));end

rule "Cleanup skipped rules"when$o : Order($id : id)SkipRule(orderId == $id, $rId : ruleId)$p : Problem(orderId == $id, ruleId == $rId)then log.info("Retract #" + $rId + " for order: " + $id);retract($p);end

Houston, we've got a problemPerformance & Resources

Rete

Entry Point

Object Type

Alpha

Adapters/Eval

Join

Not

Terminal

Rete

Entry PointEntry Point Node

Scope 1EntryPointNode#1

Scope 2EntryPointNode#2

Scope 3EntryPointNode#3

Entry Point Node

Object TypeObject Type Node

OrderObjectTypeNode#1

PartyDefObjectTypeNode#2

ProblemObjectTypeNode#3

OIProblemObjectTypeNode#4

Object Type Node (Order)

Fact Set

Order#112

Order#113

Order#114

Order#115

...

Object Type Node (Order)

LiteralAlpha Node

inParty == nullAlphaNode#1

inParty != nullAlphaNode#2

outParty == nullAlphaNode#3

outParty != nullAlphaNode#4

Alpha Node

Fact Set

Order#1

Order#5

Order#6

...

Join Node

Left

Order#1, SkipRule#5

Order#5, SkipRule#15

Order#6, SkipRule#11

...

Right

Problem#1

Problem#5

Problem#6

...

Problem#11

Problem#12

Not Node

Left

Order#1, OrderItem#5

Order#1, OrderItem#1

Order#1, OrderItem#3

...

Right

Problem#1

Problem#5

Problem#6

...

Problem#11

Problem#12

Eval

No Cache

No Memory

rule "Rule #3 violation"when $o : Order($id:id, $t:time, $pty:inParty) not( Problem(orderId==$id, ruleId==3) ) eval( dao.findPartyBy($t, $pty)==null )then log.info("Rule #3 violated for the order: " + $id); insert(new Problem($id, 3));end

rule "Rule #3 fulfillment"when $o : Order(inPartyId==null, $id:id, $t:time, $pty:inParty) not( Problem(orderId==$id, ruleId==3) ) eval( dao.findPartyBy($t, $pty)!=null )then log.info("Rule #3 fulfilled for the order: " + $id); modify($o) { setInPartyId( dao.findPartyBy($t, $pty).getPartyId() ) };end

Hard to TestInefficientHigh Cost of RefactoringImpossible Exception HandlingCan Change State Between InvocationsUsually Less Readable

Replace EVALPrefetch Data

rule "Rule #3 violation"when $o : Order($id:id, $t:time, $pty:inParty) not( Problem(orderId==$id, ruleId==3) ) not( PartyDef(publicCode == $pty,startTime $t) )then log.info("Rule #3 violated for the order: " + $id); insert(new Problem($id, 3));end

rule "Rule #3 fulfillment"when $o : Order(inPartyId==null, $id:id, $t:time, $pty:inParty) not( Problem(orderId==$id, ruleId==3) ) $p : PartyDef(publicCode == $pty,startTime $t) then log.info("Rule #3 fulfilled for the order: " + $id); modify($o) { inPartyId = $p.getPartyId(); };end

rule "Prefetch inParty PartyDef"salience 100whenOrder(inParty!=null, $t:time, $pCode:inParty)not( PartyDef(publicCode == $pCode,startTime $t) )thenPartyDef pd = dao.findPartyBy($t, $pCode);

if (pd != null) {log.info("insert party: " + pd.getPartyId());insert(pd);}end

rule "Prefetch inParty PartyDef"salience 100whenOrder(inParty!=null, $t:time, $pCode:inParty)not( PartyDef(publicCode == $pCode,startTime $t) )thenPartyDef pd = dao.findPartyBy($t, $pCode);log.info("insert party (if exists): " + pd);insert(pd); // null won't be insertedend

Hard to TestInefficientHigh Cost of RefactoringImpossible Exception HandlingCan Change State Between InvocationsUsually Less ReadableSeveral More Rules to Support

???

http://akinator.com/

http://docs.jboss.org/