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 <benjamin.e.wolfe@> 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-...
> Sent from the Drools: User forum mailing list archive at
Nabble.com.
> _______________________________________________
> rules-users mailing list
> rules-users@.jboss
>
https://lists.jboss.org/mailman/listinfo/rules-users
>
_______________________________________________
rules-users mailing list
rules-users@.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-...
Sent from the Drools: User forum mailing list archive at
Nabble.com.