[rules-users] Question about the Nature of Ruleflows

BenjaminWolfe benjamin.e.wolfe at gmail.com
Tue Aug 21 17:14:14 EDT 2012


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.


More information about the rules-users mailing list