[rules-users] Question about the Nature of Ruleflows

Wolfgang Laun wolfgang.laun at gmail.com
Wed Aug 22 02:13:54 EDT 2012


@Benjamin:

Esteban just confirms what I was trying to explain in my previous answer.
Ruleflow decisions aren't made on a per-fact basis - all facts in
Working Memory participate in their evaluation.

To activate one or other set of rules, an agenda group might be sufficient;
your "full-fledged example" doesn't really look as if a rule flow is
required.

-W


On 22/08/2012, Esteban Aliverti <esteban.aliverti at gmail.com> wrote:
> Drools Flow (aka JBPM5) will look for all the Persons and Dogs you have in
> your session.
> Since the conditions in an XOR gateway are evaluated in order, the first
> one being true is going to be selected.
> In your case, after you insert the Persons, both rules are activated, but
> the gateway is always going to pick the first one.
> I would suggest to use different process instances for different scenarios.
>
> Best Regards,
>
> XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
>
> Esteban Aliverti
> - Blog @ http://ilesteban.wordpress.com
>
>
> On Tue, Aug 21, 2012 at 11:14 PM, BenjaminWolfe
> <benjamin.e.wolfe at gmail.com>wrote:
>
>> Thanks Wolfgang.
>>
>> My original post was a conceptual analogy.  But this still isn't working
>> right for me, so I've written out a full-fledged example to see if you or
>> anyone else can help.  The full example is behaving exactly the way my
>> real
>> (important) code is -- which is the wrong way for the business
>> application.
>> :-/  I should add that in real life, the ruleflow groups each have
>> multiple
>> rules within them.
>>
>> So without further ado, here's my code -- two POJOs, a bpmn file, a rule
>> resource, and a test class -- along with the expected output and actual
>> output.
>>
>> *User.java*
>>
>> package com.examples.ruleflow;
>>
>> public class User {
>>
>>         private int id;
>>
>>         public User() {}
>>         public User(int id) {
>>                 this.id = id;
>>         }
>>
>>         public int getId() {
>>                 return id;
>>         }
>>
>>         public void setId(int id) {
>>                 this.id = id;
>>         }
>> }
>>
>> *Dog.java*
>>
>> package com.examples.ruleflow;
>>
>> public class Dog {
>>
>>         private int id;
>>         private int ownerId;
>>         private boolean hasDogTag;
>>
>>         public Dog() {}
>>         public Dog(int id) {
>>                 this.id = id;
>>         }
>>
>>         public int getId() {
>>                 return id;
>>         }
>>         public int getOwnerId() {
>>                 return ownerId;
>>         }
>>         public boolean isHasDogTag() {
>>                 return hasDogTag;
>>         }
>>         public void setId(int id) {
>>                 this.id = id;
>>         }
>>         public void setOwnerId(int ownerId) {
>>                 this.ownerId = ownerId;
>>         }
>>         public void setHasDogTag(boolean hasDogTag) {
>>                 this.hasDogTag = hasDogTag;
>>         }
>>
>> }
>>
>> *dog_owner_flow.bpmn*
>>
>> <?xml version="1.0" encoding="UTF-8"?>
>> <definitions id="Definition"
>>              targetNamespace="http://www.jboss.org/drools"
>>              typeLanguage="http://www.java.com/javaTypes"
>>              expressionLanguage="http://www.mvel.org/2.0"
>>              xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
>>              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>>              xsi:schemaLocation="
>> http://www.omg.org/spec/BPMN/20100524/MODEL
>> BPMN20.xsd"
>>              xmlns:g="http://www.jboss.org/drools/flow/gpd"
>>              xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
>>              xmlns:dc="http://www.omg.org/spec/DD/20100524/DC"
>>              xmlns:di="http://www.omg.org/spec/DD/20100524/DI"
>>              xmlns:tns="http://www.jboss.org/drools">
>>
>>   <process processType="Private" isExecutable="true"
>> id="com.examples.ruleflow.dogProcess" name="Dog Owner Process"
>> tns:packageName="com.examples.ruleflow" tns:version="1" >
>>
>>
>>     <startEvent id="_1" name="StartProcess" />
>>     <exclusiveGateway id="_2" name="Gateway" gatewayDirection="Diverging"
>> />
>>     <businessRuleTask id="_3" name="Branch A" g:ruleFlowGroup="flowA"
>> ></businessRuleTask>
>>     <businessRuleTask id="_4" name="Branch B" g:ruleFlowGroup="flowB"
>> ></businessRuleTask>
>>     <exclusiveGateway id="_5" name="Gateway"
>> gatewayDirection="Converging"
>> />
>>     <endEvent id="_6" name="End" ><terminateEventDefinition/></endEvent>
>>
>>
>>     <sequenceFlow id="_1-_2" sourceRef="_1" targetRef="_2" />
>>     <sequenceFlow id="_2-_3" sourceRef="_2" targetRef="_3" name="dog tags
>> OK" tns:priority="1" >
>>       <conditionExpression xsi:type="tFormalExpression"
>> language="http://www.jboss.org/drools/rule" >
>>         /$u : User()
>>         not ( Dog( ownerId == $u.id, hasDogTag == false ) )/
>>       </conditionExpression>
>>     </sequenceFlow>
>>     <sequenceFlow id="_2-_4" sourceRef="_2" targetRef="_4" name="dog tag
>> issue" tns:priority="1" >
>>       <conditionExpression xsi:type="tFormalExpression"
>> language="http://www.jboss.org/drools/rule" >
>>         /$u : User()
>>         exists ( Dog( ownerId == $u.id, hasDogTag == false ) )/
>>       </conditionExpression>
>>     </sequenceFlow>
>>     <sequenceFlow id="_3-_5" sourceRef="_3" targetRef="_5" />
>>     <sequenceFlow id="_4-_5" sourceRef="_4" targetRef="_5" />
>>     <sequenceFlow id="_5-_6" sourceRef="_5" targetRef="_6" />
>>   </process>
>>
>>   <bpmndi:BPMNDiagram>
>>     <bpmndi:BPMNPlane bpmnElement="com.examples.ruleflow.dogProcess" >
>>       <bpmndi:BPMNShape bpmnElement="_1" >
>>         <dc:Bounds x="16" y="16" width="48" height="48" />
>>       </bpmndi:BPMNShape>
>>       <bpmndi:BPMNShape bpmnElement="_2" >
>>         <dc:Bounds x="180" y="15" width="48" height="48" />
>>       </bpmndi:BPMNShape>
>>       <bpmndi:BPMNShape bpmnElement="_3" >
>>         <dc:Bounds x="42" y="162" width="80" height="48" />
>>       </bpmndi:BPMNShape>
>>       <bpmndi:BPMNShape bpmnElement="_4" >
>>         <dc:Bounds x="296" y="162" width="80" height="48" />
>>       </bpmndi:BPMNShape>
>>       <bpmndi:BPMNShape bpmnElement="_5" >
>>         <dc:Bounds x="180" y="306" width="48" height="48" />
>>       </bpmndi:BPMNShape>
>>       <bpmndi:BPMNShape bpmnElement="_6" >
>>         <dc:Bounds x="188" y="384" width="48" height="48" />
>>       </bpmndi:BPMNShape>
>>       <bpmndi:BPMNEdge bpmnElement="_1-_2" >
>>         <di:waypoint x="40" y="40" />
>>         <di:waypoint x="204" y="39" />
>>       </bpmndi:BPMNEdge>
>>       <bpmndi:BPMNEdge bpmnElement="_2-_3" >
>>         <di:waypoint x="204" y="39" />
>>         <di:waypoint x="82" y="186" />
>>       </bpmndi:BPMNEdge>
>>       <bpmndi:BPMNEdge bpmnElement="_2-_4" >
>>         <di:waypoint x="204" y="39" />
>>         <di:waypoint x="336" y="186" />
>>       </bpmndi:BPMNEdge>
>>       <bpmndi:BPMNEdge bpmnElement="_3-_5" >
>>         <di:waypoint x="82" y="186" />
>>         <di:waypoint x="204" y="330" />
>>       </bpmndi:BPMNEdge>
>>       <bpmndi:BPMNEdge bpmnElement="_4-_5" >
>>         <di:waypoint x="336" y="186" />
>>         <di:waypoint x="204" y="330" />
>>       </bpmndi:BPMNEdge>
>>       <bpmndi:BPMNEdge bpmnElement="_5-_6" >
>>         <di:waypoint x="204" y="330" />
>>         <di:waypoint x="212" y="408" />
>>       </bpmndi:BPMNEdge>
>>     </bpmndi:BPMNPlane>
>>   </bpmndi:BPMNDiagram>
>> </definitions>
>>
>> *dog_owners.drl*
>>
>> package com.examples.ruleflow
>>
>> rule "sample A"
>>         ruleflow-group "flowA"
>>         no-loop true
>>         dialect "mvel"
>>         when
>>                 $u : User()
>>         then
>>                 System.out.println("User " + $u.id + " took branch A.");
>> end
>>
>> rule "sample B"
>>         ruleflow-group "flowB"
>>         no-loop true
>>         dialect "mvel"
>>         when
>>                 $u : User()
>>         then
>>                 System.out.println("User " + $u.id + " took branch B.");
>> end
>>
>> *DogTest.java*
>>
>> package com.examples.ruleflow;
>>
>> import org.drools.KnowledgeBase;
>> import org.drools.builder.KnowledgeBuilder;
>> import org.drools.builder.KnowledgeBuilderFactory;
>> import org.drools.builder.ResourceType;
>> import org.drools.io.ResourceFactory;
>> import org.drools.logger.KnowledgeRuntimeLogger;
>> import org.drools.logger.KnowledgeRuntimeLoggerFactory;
>> import org.drools.runtime.StatefulKnowledgeSession;
>> /import java.util.List;
>> import java.util.ArrayList;/
>>
>> public class DogTest {
>>
>>     public static final void main(String[] args) {
>>         try {
>>             // load up the knowledge base
>>             KnowledgeBase kbase = readKnowledgeBase();
>>             StatefulKnowledgeSession ksession =
>> kbase.newStatefulKnowledgeSession();
>>             KnowledgeRuntimeLogger logger =
>> KnowledgeRuntimeLoggerFactory.newFileLogger(ksession, "test");
>>             /// create and insert facts
>>             List<User> users = new ArrayList<User>();
>>             List<Dog> dogs = new ArrayList<Dog>();
>>
>>             users.add(new User(0));
>>             dogs.add(new Dog(0));
>>             dogs.get(0).setOwnerId(1);
>>             dogs.get(0).setHasDogTag(true);
>>             dogs.add(new Dog(1));
>>             dogs.get(1).setOwnerId(0);
>>             dogs.get(1).setHasDogTag(true);
>>
>>             users.add(new User(1));
>>             dogs.add(new Dog(2));
>>             dogs.get(2).setOwnerId(1);
>>             dogs.get(2).setHasDogTag(true);
>>             dogs.add(new Dog(3));
>>             dogs.get(3).setOwnerId(1);
>>             dogs.get(3).setHasDogTag(true);
>>             dogs.add(new Dog(4));
>>             dogs.get(4).setOwnerId(1);
>>             dogs.get(4).setHasDogTag(false);
>>
>>             for (User u:users) {
>>                 ksession.insert(u);
>>             }
>>             for (Dog d:dogs) {
>>                 ksession.insert(d);
>>             }/
>>
>>             // start a new process instance
>>             /ksession.startProcess("com.examples.ruleflow.dogProcess");
>>             ksession.fireAllRules();/
>>             logger.close();
>>         } catch (Throwable t) {
>>             t.printStackTrace();
>>         }
>>     }
>>
>>     private static KnowledgeBase readKnowledgeBase() throws Exception {
>>         KnowledgeBuilder kbuilder =
>> KnowledgeBuilderFactory.newKnowledgeBuilder();
>>
>> /kbuilder.add(ResourceFactory.newClassPathResource("dog_owners.drl"),
>> ResourceType.DRL);
>>
>> kbuilder.add(ResourceFactory.newClassPathResource("dog_owner_flow.bpmn"),
>> ResourceType.BPMN2);/
>>         return kbuilder.newKnowledgeBase();
>>     }
>> }
>>
>> */Expected/ Console Output...*
>>
>> User /0/ took branch /A/.
>> User /1/ took branch /B/.
>>
>> */Actual/ Console Output...*
>>
>> User /1/ took branch /A/.
>> User /0/ took branch /A/.
>>
>>
>> laune wrote
>> >
>> > On 21/08/2012, BenjaminWolfe &lt;benjamin.e.wolfe@&gt; wrote:
>> >> I'm trying to wrap my mind around the nature of ruleflows -- and I
>> >> think
>> >> this
>> >> question sums up a bit of my confusion.
>> >>
>> >> I have a stateful knowledge session.  The stateful knowledge session
>> >> has
>> >> a
>> >> ruleflow associated with it.  That ruleflow diverges into two branches
>> --
>> >> branch A and branch B -- based on a rule constraint.  It's an XOR, and
>> >> the
>> >> mvel rule constraints are something like this:
>> >>
>> >> to branch A
>> >> $u : User( $i : userId )
>> >> exists ( Dog( owner == $i, hasDogTag == false) )
>> >>
>> >> to branch B
>> >> $u : User( $i : userId )
>> >> not ( Dog( owner == $i, hasDogTag == false) )
>> >>
>> >> Then the two branches converge again.  I insert two facts: user 1,
>> >> whose
>> >> dogs all have dog tags, and user 2 whose third dog is missing a tag.
>> >> Then,
>> >> after I insert both facts, I fire all rules.
>> >
>> > If you don't insert any Dogs, only the condition for branch B is true,
>> > since there no Dogs at all, tag or no tag.
>> >
>> > If you insert Dogs according to your statement, both conditions are
>> > true, A for user 2 and B for user 1 (which is not what you describe
>> > below, but I think this is an oversight).
>> >
>> > Anyway, a "flow" will not cycle automatically if there are several
>> > fact groups, with some of them requiring this or that processing. To
>> > notify Users with untagged dogs, a simple rule with the conditions
>> > you've posted and with a consequence notifying the user would be
>> > sufficient.
>> >
>> > For an overall decision between "there are tagless dogs" and "all dogs
>> > are tagged" you'd need conditions like these:
>> >
>> > exists( Dog( hasDogTag == false) )
>> >
>> > not( Dog( hasDogTag == false) )
>> >
>> > -W
>> >
>> >
>> >>
>> >> Should the flow be like this?
>> >>
>> >> user 1: start --> diverge --> branch A (tell him to buy dog tags) -->
>> >> converge --> end
>> >> user 2: start --> diverge --> branch B (leave him alone) --> converge
>> -->
>> >> end
>> >>
>> >> Or does a ruleflow look at the whole session rather than each fact --
>> >> in
>> >> which case either both users would pass through branch A, or both
>> >> would
>> >> pass
>> >> through branch B?
>> >>
>> >> If I want the first case to happen, is there something I'm missing in
>> the
>> >> implementation?  And are there any more details I can add to make my
>> post
>> >> more specific?  Thank you for your help.
>> >>
>> >>
>> >>
>> >> --
>> >> View this message in context:
>> >>
>> http://drools.46999.n3.nabble.com/Question-about-the-Nature-of-Ruleflows-tp4019292.html
>> >> Sent from the Drools: User forum mailing list archive at Nabble.com.
>> >> _______________________________________________
>> >> rules-users mailing list
>> >> rules-users at .jboss
>> >> https://lists.jboss.org/mailman/listinfo/rules-users
>> >>
>> > _______________________________________________
>> > rules-users mailing list
>> > rules-users at .jboss
>> > https://lists.jboss.org/mailman/listinfo/rules-users
>> >
>>
>>
>>
>> --
>> View this message in context:
>> http://drools.46999.n3.nabble.com/Question-about-the-Nature-of-Ruleflows-tp4019292p4019325.html
>> Sent from the Drools: User forum mailing list archive at Nabble.com.
>> _______________________________________________
>> rules-users mailing list
>> rules-users at lists.jboss.org
>> https://lists.jboss.org/mailman/listinfo/rules-users
>>
>


More information about the rules-users mailing list