[rules-users] Question about the Nature of Ruleflows

Esteban Aliverti esteban.aliverti at gmail.com
Tue Aug 21 18:21:46 EDT 2012


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
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.jboss.org/pipermail/rules-users/attachments/20120822/dc92e299/attachment-0001.html 


More information about the rules-users mailing list