JBoss Drools

         by Victor Polischuk
Business Problem
 Model and Requirements
Party               PartyDef
id                     partyId
                       startTime
                       stopTime
             Partici   publicCode
 PartyRole
              pant
partyId
roleId                    Role
startTime              id
stopTime               publicCode
Order                   ProductDef
id                        productId
time          Order       startTime
inParty                   stopTime
inRole                    publicCode
outParty
outRole       OrderItem
inPartyId    orderId
inRoleId     quantity
outPartyId   productId         Product
outRoleId    product      id
1)Start-stop intervals must not overlap.
2)Entity exists only within start-stop interval.
3)Order must have valid and existent in party.
4)Order must have valid and existent out party.
5)Order must have valid and existent in role.
6)Order must have valid and existent out role.
7)Order items must have valid and existent
 product.
8)Order in and out parties must not be the
 same.
9)Order roles must be: (buyer, seller), (buyer,
 repairer), (repairer, seller), (seller, buyer).
Frontal Assault
    Conditions
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<Problem> problems = …;

    PartyDef ip = getValidatedByRule3(...);
    PartyDef op = getValidatedByRule4(...);
    PartyRole ir = getValidatedByRule5(...); //???
}
public void placeOrder(Order order) {
  List<Problem> problems = …;

    PartyDef ip = getValidatedByRule3(...);
    PartyDef op = getValidatedByRule4(...);
    if (ip != null) {
        PartyRole ir = getValidatedByRule5(...);
    }
}
public void placeOrder(Order order) {
  List<Problem> 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<Problem> 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<Problem> problems = …;

    PartyDef ip = getValidatedByRule3(...);
    PartyDef op = getValidatedByRule4(...);
    PartyRole ir = getSafeValidatedByRule5(...);
    PartyRole or = getSafeValidatedByRule6(...);
    validateRule8(...);
}
public void placeOrder(Order order) {
  List<Problem> 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<Problem> 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<Problem> problems = …;

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




Context          RuleRunner




          Data
class RuleRunner...
public <T> List<Problem> run(<T> data) {
  List<Problem> 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<Rule> 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<T> {

    boolean accepts(Context context);

    void execute(Context context, T data);

}
class RuleN3 implements Rule<Order>

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<Order>

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 Step
  Expert System
Rule            RuleConfig




Context          RuleRunner




          Data
KnowledgeBas
    Rule
                             e



WorkingMemor
                        RuleEngine
      y



               Facts
Simple Rule Engine

  Decision Block     3
                     1   Rule

  Decision Block     4   Rule

  Decision Block     5   Rule

  Decision Block     6   Rule

      Result
Expert System

Decision Block   3
                 1   Rule

Decision Block   4   Rule

Decision Block   5   Rule

Decision Block   6   Rule

   Result
Process
              Order


 Fix          Error
Routing         ?

Fixed
          End Processing
   ?
Rule 1       Fact 1
Rule 2       Fact 2
Rule 3       Fact 3
         *            * Repeats = ?
Rule 4       Fact 4
  ...          ...
Rule N       Fact M
Rule 1       Fact 1
Rule 2       Fact 2
Rule 3       Fact 3
         *            * Repeats = ?
Rule 4       Fact 4
  ...          ...
Rule N       Fact M

             Inefficient
To the Rescue
     Rete
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
Drools
 Finally
Drools Rule Pattern
rule "Rule example" // Rule unique name
... // Rule attributes: grouping, priority, etc.
when
      ... // Left hand side. Condition.
then
      ... // Right hand side. Consequence.
end
THE <consequence
IF   <condition>
                    N        >
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<Order>

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 Simpler
       Why 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<Order>

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 #1
   Complex Rule
class RuleN7_1 implements Rule<Order>

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 #2
Complex Runner and Configuration
class RuleN7_2 implements Rule<OrderItem>

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
    }
}
Drools
 Again?
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 Tool
           Or Not?
package com.victor.drools
dialect "mvel"
import com.victor.drools.*; // optional

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

declare Problem
  orderId : long @key
  ruleId : int @key
end
declare OIProblem extends Problem
  product : String @key
end
Drools Class Declaration
declare ExampleClass // Class name
[extends ParentExampleClass] // Inheritance
    @stringMetadata("I am String") // Metadata
    @dateMetadata(01-Jan-1970)


    propertyName1 : ValidType, // Properties
    propertyName2 : AnotherValidType
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
Drools Function Declaration
function String hello(String name) {
    return "Hello "+name+"!";
}
rule "Function usage in LHS"
when
  eval( hello("Victor")!="Hello Victor!" )
then
  int 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
Drools Query Declaration
query "Orders with inParty"
  $o : Order(inParty != null)
end


query "Orders with inRole equals to" (String
 role)
  $o : Order(inRole == role)
end
Drools Templates
template header
field1... // Template fields
template “TemplateName”
rule "ExampleRule_@{row.rowNumber}"
... // Usage of declared fields
end
end template
Promotional       Age      Number of     Policy type    Discount %
 discount rules    Bracket     prior       applying for
                              claims

Rewards for safe    18,24       0        COMPREHENSIVE        1
    drivers


                    18,24       0          FIRE_THEFT         2



                    25,30       1        COMPREHENSIVE        5



                    25,30       2        COMPREHENSIVE        1



                    25,30       0        COMPREHENSIVE       20



                                                           © jboss.org
Pièce de Résistance
        DSL
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"
when
  Every Order
  Without violations of rule 3
  Which violates inParty constraints
then
  Add the violation of the rule 3
end
[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"
when
  Every Order
  Without violations of rule 4
  Which violates outParty constraints
then
  Add the violation of the rule 4
end
[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 OrderItem
  Without violations of order item rule 7
  Which violates product constraints
then
  Add the violation of the rule 7 for the order item
end
[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 Believe
  Am I Alone?
Meanwhile in the Real World...
       Requirements Change
1)Start-stop intervals must not overlap.
2)Entity exists only within start-stop interval.
3)Order must have valid and existent in party.
4)Order must have valid and existent out party.
5)Order must have valid and existent in role.
6)Order must have valid and existent out role.
7)Order items must have valid and existent
 product.
8)Order in and out parties CAN be the same.
 ONLY IF they have roles (seller, repairer).
9)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]
then
  Add the violation of the rule 8
end
rule "Rule #8 exceptional case"
// salience 100
when
   $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 problem
      Performance & Resources
Rete          Adapters/Eval


Entry Point            Join


Object Type            Not


Alpha              Terminal
Rete

 Entry Point     Entry Point Node
Scope 1      EntryPointNode#1
Scope 2      EntryPointNode#2
Scope 3      EntryPointNode#3
Entry Point Node

Object Type      Object Type Node
Order         ObjectTypeNode#1
PartyDef      ObjectTypeNode#2
Problem       ObjectTypeNode#3
OIProblem     ObjectTypeNode#4
Object Type Node (Order)

             Fact Set
Order#112
Order#113
Order#114
Order#115
...
Object Type Node (Order)

     Literal            Alpha Node
inParty == null    AlphaNode#1
inParty != null    AlphaNode#2
outParty == null   AlphaNode#3
outParty != null   AlphaNode#4
Alpha Node

            Fact Set
Order#1
Order#5
Order#6
...
Join Node

         Left              Right
Order#1, SkipRule#5    Problem#1
Order#5, SkipRule#15   Problem#5
Order#6, SkipRule#11   Problem#6
...                    ...
                       Problem#11
                       Problem#12
Not Node

         Left              Right
Order#1, OrderItem#5   Problem#1
Order#1, OrderItem#1   Problem#5
Order#1, OrderItem#3   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 Test            Inefficient

      High Cost of Refactoring

    Impossible Exception Handling

Can Change State Between Invocations

       Usually Less Readable
Replace EVAL
  Prefetch 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, stopTime > $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, stopTime > $t)
then
  log.info("Rule #3 fulfilled for the order: " + $id);
  modify($o) {
     inPartyId = $p.getPartyId();
  };
end
rule "Prefetch inParty PartyDef"
salience 100
when
  Order(inParty!=null, $t:time, $pCode:inParty)
  not( PartyDef(publicCode == $pCode,
                startTime <= $t, stopTime > $t) )
then
  PartyDef pd = dao.findPartyBy($t, $pCode);

  if (pd != null) {
      log.info("insert party: " + pd.getPartyId());
      insert(pd);
  }
end
rule "Prefetch inParty PartyDef"
salience 100
when
  Order(inParty!=null, $t:time, $pCode:inParty)
  not( PartyDef(publicCode == $pCode,
                startTime <= $t, stopTime > $t) )
then
  PartyDef pd = dao.findPartyBy($t, $pCode);
  log.info("insert party (if exists): " + pd);
  insert(pd); // null won't be inserted
end
Hard to Test            Inefficient

      High Cost of Refactoring

    Impossible Exception Handling

Can Change State Between Invocations

       Usually Less Readable

    Several More Rules to Support
???

      http://docs.jboss.org/

      http://akinator.com/

JBoss Drools

  • 1.
    JBoss Drools by Victor Polischuk
  • 2.
    Business Problem Modeland Requirements
  • 3.
    Party PartyDef id partyId startTime stopTime Partici publicCode PartyRole pant partyId roleId Role startTime id stopTime publicCode
  • 4.
    Order ProductDef id productId time Order startTime inParty stopTime inRole publicCode outParty outRole OrderItem inPartyId orderId inRoleId quantity outPartyId productId Product outRoleId product id
  • 5.
    1)Start-stop intervals mustnot overlap. 2)Entity exists only within start-stop interval. 3)Order must have valid and existent in party. 4)Order must have valid and existent out party. 5)Order must have valid and existent in role. 6)Order must have valid and existent out role. 7)Order items must have valid and existent product. 8)Order in and out parties must not be the same. 9)Order roles must be: (buyer, seller), (buyer, repairer), (repairer, seller), (seller, buyer).
  • 6.
    Frontal Assault Conditions
  • 7.
  • 8.
    public void placeOrder(Orderorder) { PartyDef ip = dao.findPartyBy(...); }
  • 9.
    public void placeOrder(Orderorder) { PartyDef ip = dao.findPartyBy(...); if (ip == null) { throw new Rule3Exception(...); } }
  • 10.
    public void placeOrder(Orderorder) { PartyDef ip = dao.findPartyBy(...); if (ip == null) { throw new Rule3Exception(...); } PartyDef op = dao.findPartyBy(...); if (op == null) { throw new Rule4Exception(...); } }
  • 11.
    public void placeOrder(Orderorder) { 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(...); } }
  • 12.
    public void placeOrder(Orderorder) { PartyDef ip = dao.findPartyBy(...); assertRule3(ip); PartyDef op = dao.findPartyBy(...); assertRule4(op); PartyRole ir = dao.findRoleBy(...); assertRule5(ir); }
  • 13.
    public void placeOrder(Orderorder) { PartyDef ip = getValidatedByRule3(...); PartyDef op = getValidatedByRule4(...); PartyRole ir = getValidatedByRule5(...); }
  • 14.
    public void placeOrder(Orderorder) { List<Problem> problems = …; PartyDef ip = getValidatedByRule3(...); PartyDef op = getValidatedByRule4(...); PartyRole ir = getValidatedByRule5(...); //??? }
  • 15.
    public void placeOrder(Orderorder) { List<Problem> problems = …; PartyDef ip = getValidatedByRule3(...); PartyDef op = getValidatedByRule4(...); if (ip != null) { PartyRole ir = getValidatedByRule5(...); } }
  • 16.
    public void placeOrder(Orderorder) { List<Problem> problems = …; PartyDef ip = getValidatedByRule3(...); PartyDef op = getValidatedByRule4(...); if (ip != null) { PartyRole ir = getValidatedByRule5(...); } if (op != null) { PartyRole or = getValidatedByRule6(...); } }
  • 17.
    public void placeOrder(Orderorder) { List<Problem> 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 } }
  • 18.
    public void placeOrder(Orderorder) { List<Problem> problems = …; PartyDef ip = getValidatedByRule3(...); PartyDef op = getValidatedByRule4(...); PartyRole ir = getSafeValidatedByRule5(...); PartyRole or = getSafeValidatedByRule6(...); validateRule8(...); }
  • 19.
    public void placeOrder(Orderorder) { List<Problem> problems = …; PartyDef ip = getValidatedByRule3(...); PartyDef op = getValidatedByRule4(...); PartyRole ir = getSafeValidatedByRule5(...); PartyRole or = getSafeValidatedByRule6(...); validateRule8(...); if (ir != null && or != null && (...)) { problems.add(...); // Rule #9 violation } }
  • 20.
    public void placeOrder(Orderorder) { List<Problem> problems = …; PartyDef ip = getValidatedByRule3(...); PartyDef op = getValidatedByRule4(...); PartyRole ir = getSafeValidatedByRule5(...); PartyRole or = getSafeValidatedByRule6(...); validateRule8(...); validateRule9(...); if (problems.isEmpty()) { order.inPartyId = ip.partyId; ... } }
  • 21.
    public void placeOrder(Orderorder) { List<Problem> problems = …; PartyDef ip = getValidatedByRule3(...); PartyDef op = getValidatedByRule4(...); PartyRole ir = getSafeValidatedByRule5(...); PartyRole or = getSafeValidatedByRule6(...); validateRule8(...); validateRule9(...); fillOrderIdentifications(...); // TODO: Rule #7 }
  • 22.
    Clean the Mess Independent Rules
  • 23.
    Rule RuleConfig Context RuleRunner Data
  • 24.
    class RuleRunner... public <T>List<Problem> run(<T> data) { List<Problem> problems = …; Context context = …; RuleConfig config = …; while (config.hasNext(context)) { Rule rule = config.next(context); try { rule.execute(context, data); } catch (…) { problems.add(...); } } }
  • 25.
    class RuleConfig... private finalList<Rule> 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); }
  • 26.
    interface Rule<T> { boolean accepts(Context context); void execute(Context context, T data); }
  • 27.
    class RuleN3 implementsRule<Order> 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; }
  • 28.
    class RuleN8 implementsRule<Order> 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(...); } }
  • 29.
    One More Step Expert System
  • 30.
    Rule RuleConfig Context RuleRunner Data
  • 31.
    KnowledgeBas Rule e WorkingMemor RuleEngine y Facts
  • 33.
    Simple Rule Engine Decision Block 3 1 Rule Decision Block 4 Rule Decision Block 5 Rule Decision Block 6 Rule Result
  • 34.
    Expert System Decision Block 3 1 Rule Decision Block 4 Rule Decision Block 5 Rule Decision Block 6 Rule Result
  • 35.
    Process Order Fix Error Routing ? Fixed End Processing ?
  • 36.
    Rule 1 Fact 1 Rule 2 Fact 2 Rule 3 Fact 3 * * Repeats = ? Rule 4 Fact 4 ... ... Rule N Fact M
  • 37.
    Rule 1 Fact 1 Rule 2 Fact 2 Rule 3 Fact 3 * * Repeats = ? Rule 4 Fact 4 ... ... Rule N Fact M Inefficient
  • 38.
  • 39.
    Rete = Net Charles L. Forgy 1979 1974 1982 © Wikipedia.org
  • 43.
    Root Node Start All Facts Pass Through It
  • 44.
    1-input Nodes Alpha Network IntraElement Conditions
  • 45.
    2-input Nodes Beta Network Two Element Comparison
  • 46.
    Terminal Nodes Stop Rules Have a Full Match
  • 48.
  • 49.
    Drools Rule Pattern rule"Rule example" // Rule unique name ... // Rule attributes: grouping, priority, etc. when ... // Left hand side. Condition. then ... // Right hand side. Consequence. end
  • 50.
    THE <consequence IF <condition> N >
  • 51.
    rule "Rule #3violation" 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
  • 52.
    rule "Rule #3fulfillment" 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
  • 54.
    class RuleN3 implementsRule<Order> 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; }
  • 55.
    If Java IsSimpler Why Use Drools?
  • 56.
    rule "Rule #7violation" 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
  • 57.
    class RuleN7 implementsRule<Order> 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(...); //??? } } }
  • 58.
    Java Solution #1 Complex Rule
  • 59.
    class RuleN7_1 implementsRule<Order> 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 } } }
  • 60.
    Java Solution #2 ComplexRunner and Configuration
  • 61.
    class RuleN7_2 implementsRule<OrderItem> 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 } }
  • 62.
  • 63.
    rule "Rule #3violation" 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
  • 64.
    rule "Rule #7violation" 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
  • 65.
  • 66.
    package com.victor.drools dialect "mvel" importcom.victor.drools.*; // optional global GeneralDao dao; global org.slf4j.Logger log; declare Problem orderId : long @key ruleId : int @key end declare OIProblem extends Problem product : String @key end
  • 67.
    Drools Class Declaration declareExampleClass // Class name [extends ParentExampleClass] // Inheritance @stringMetadata("I am String") // Metadata @dateMetadata(01-Jan-1970) propertyName1 : ValidType, // Properties propertyName2 : AnotherValidType
  • 68.
    rule "Rule #7violation" 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
  • 69.
    Drools Function Declaration functionString hello(String name) { return "Hello "+name+"!"; }
  • 70.
    rule "Function usagein LHS" when eval( hello("Victor")!="Hello Victor!" ) then int 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
  • 71.
    rule "Function usagein RHS" when eval(true) then log.happiness(hello("Victor")); log.worship(hello("Master")); end
  • 72.
    Drools Query Declaration query"Orders with inParty" $o : Order(inParty != null) end query "Orders with inRole equals to" (String role) $o : Order(inRole == role) end
  • 73.
    Drools Templates template header field1...// Template fields template “TemplateName” rule "ExampleRule_@{row.rowNumber}" ... // Usage of declared fields end end template
  • 74.
    Promotional Age Number of Policy type Discount % discount rules Bracket prior applying for claims Rewards for safe 18,24 0 COMPREHENSIVE 1 drivers 18,24 0 FIRE_THEFT 2 25,30 1 COMPREHENSIVE 5 25,30 2 COMPREHENSIVE 1 25,30 0 COMPREHENSIVE 20 © jboss.org
  • 75.
  • 76.
    rule "Rule #3violation" 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
  • 77.
    rule "Rule #3violation" when Every Order Without violations of rule 3 Which violates inParty constraints then Add the violation of the rule 3 end
  • 78.
    [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}));
  • 79.
    rule "Rule #4violation" when Every Order Without violations of rule 4 Which violates outParty constraints then Add the violation of the rule 4 end
  • 80.
    [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}));
  • 81.
    [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}));
  • 82.
  • 83.
    rule "Rule #7violation" 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
  • 84.
    rule "Rule #7violation" 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
  • 85.
    rule "Rule #7violation" 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
  • 86.
    rule "Rule #7violation" 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
  • 87.
    rule "Rule #7violation" 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
  • 88.
    rule "Rule #7violation" when Every Order - which has items And every OrderItem Without violations of order item rule 7 Which violates product constraints then Add the violation of the rule 7 for the order item end
  • 89.
    [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} =
  • 90.
    [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} =
  • 91.
    I Do Believe Am I Alone?
  • 92.
    Meanwhile in theReal World... Requirements Change
  • 94.
    1)Start-stop intervals mustnot overlap. 2)Entity exists only within start-stop interval. 3)Order must have valid and existent in party. 4)Order must have valid and existent out party. 5)Order must have valid and existent in role. 6)Order must have valid and existent out role. 7)Order items must have valid and existent product. 8)Order in and out parties CAN be the same. ONLY IF they have roles (seller, repairer). 9)Order roles must be: (buyer, seller), (buyer, repairer), (repairer, seller), (seller, buyer). OR (seller, repairer) if they are the same.
  • 95.
    rule "Rule #8violation" 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
  • 96.
    rule "Rule #8violation" 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
  • 97.
    rule "Rule #8violation" 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] then Add the violation of the rule 8 end
  • 98.
    rule "Rule #8exceptional case" // salience 100 when $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
  • 99.
    rule "Rule #8violation" 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
  • 100.
    rule "Cleanup skippedrules" 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
  • 101.
    Houston, we've gota problem Performance & Resources
  • 102.
    Rete Adapters/Eval Entry Point Join Object Type Not Alpha Terminal
  • 103.
    Rete Entry Point Entry Point Node Scope 1 EntryPointNode#1 Scope 2 EntryPointNode#2 Scope 3 EntryPointNode#3
  • 104.
    Entry Point Node ObjectType Object Type Node Order ObjectTypeNode#1 PartyDef ObjectTypeNode#2 Problem ObjectTypeNode#3 OIProblem ObjectTypeNode#4
  • 105.
    Object Type Node(Order) Fact Set Order#112 Order#113 Order#114 Order#115 ...
  • 106.
    Object Type Node(Order) Literal Alpha Node inParty == null AlphaNode#1 inParty != null AlphaNode#2 outParty == null AlphaNode#3 outParty != null AlphaNode#4
  • 107.
    Alpha Node Fact Set Order#1 Order#5 Order#6 ...
  • 108.
    Join Node Left Right Order#1, SkipRule#5 Problem#1 Order#5, SkipRule#15 Problem#5 Order#6, SkipRule#11 Problem#6 ... ... Problem#11 Problem#12
  • 109.
    Not Node Left Right Order#1, OrderItem#5 Problem#1 Order#1, OrderItem#1 Problem#5 Order#1, OrderItem#3 Problem#6 ... ... Problem#11 Problem#12
  • 110.
    Eval No Cache No Memory
  • 111.
    rule "Rule #3violation" 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
  • 112.
    rule "Rule #3fulfillment" 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
  • 113.
    Hard to Test Inefficient High Cost of Refactoring Impossible Exception Handling Can Change State Between Invocations Usually Less Readable
  • 114.
    Replace EVAL Prefetch Data
  • 115.
    rule "Rule #3violation" when $o : Order($id:id, $t:time, $pty:inParty) not( Problem(orderId==$id, ruleId==3) ) not( PartyDef(publicCode == $pty, startTime <= $t, stopTime > $t) ) then log.info("Rule #3 violated for the order: " + $id); insert(new Problem($id, 3)); end
  • 116.
    rule "Rule #3fulfillment" when $o : Order(inPartyId==null, $id:id, $t:time, $pty:inParty) not( Problem(orderId==$id, ruleId==3) ) $p : PartyDef(publicCode == $pty, startTime <= $t, stopTime > $t) then log.info("Rule #3 fulfilled for the order: " + $id); modify($o) { inPartyId = $p.getPartyId(); }; end
  • 117.
    rule "Prefetch inPartyPartyDef" salience 100 when Order(inParty!=null, $t:time, $pCode:inParty) not( PartyDef(publicCode == $pCode, startTime <= $t, stopTime > $t) ) then PartyDef pd = dao.findPartyBy($t, $pCode); if (pd != null) { log.info("insert party: " + pd.getPartyId()); insert(pd); } end
  • 118.
    rule "Prefetch inPartyPartyDef" salience 100 when Order(inParty!=null, $t:time, $pCode:inParty) not( PartyDef(publicCode == $pCode, startTime <= $t, stopTime > $t) ) then PartyDef pd = dao.findPartyBy($t, $pCode); log.info("insert party (if exists): " + pd); insert(pd); // null won't be inserted end
  • 119.
    Hard to Test Inefficient High Cost of Refactoring Impossible Exception Handling Can Change State Between Invocations Usually Less Readable Several More Rules to Support
  • 120.
    ??? http://docs.jboss.org/ http://akinator.com/