从 JBPM 5 中的规则任务访问流程实例
简短版本:如何让 JBPM5 规则节点使用读取和更新流程变量的 DRL 文件?
长版本: 我有一个流程定义,在 JBPM5 下运行。这个过程的开始看起来像这样:
[开始] ---> [规则节点] ---> [Gateway (Diverge)] ... 等
网关对名为“isValid”的变量使用约束。
我的规则节点指向 RuleFlowGroup“验证”,其中仅包含一条规则:
rule "Example validation rule"
ruleflow-group "validate"
when
processInstance : WorkflowProcessInstance()
then
processInstance.setVariable("isValid", new Boolean(false));
end
因此,根据我的逻辑,如果正确处理该规则,则网关应始终遵循“错误”路径。
在我的 Java 代码中,我有类似以下内容:
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add(ResourceFactory.newClassPathResource("myProcess.bpmn"), ResourceType.BPMN2);
kbuilder.add(ResourceFactory.newClassPathResource("myRules.drl"), ResourceType.DRL);
KnowledgeBase kbase = kbuilder.newKnowledgeBase();
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
new Thread(new Runnable()
{
public void run()
{
ksession.fireUntilHalt();
}
}).start();
// start a new process instance
Map<String, Object> params = new HashMap<String, Object>();
params.put("isValid", true);
ksession.startProcess("test.processesdefinition.myProcess", params);
我可以确认以下内容:
- drl 文件正在加载到工作内存中,因为当我将语法错误放入文件中时,我会收到错误。
- 如果我在 Java 参数映射中包含“isValid”的值,则该过程仅遵循 Java 指定的路径,显然忽略了 drools 规则。
- 如果我从参数映射中取出“isValid”参数,则会收到运行时错误。
由此,我假设规则中的最后一个“setVariable”行要么没有执行,要么正在更新错误的内容。
我认为我的问题与官方文档中的这一说法有关:
规则约束无法直接访问流程内定义的变量。这是 但是可以通过添加来引用规则约束内的当前流程实例 将流程实例添加到工作内存中并与您的流程实例相匹配 规则约束。我们添加了特殊的逻辑来确保变量 processInstance WorkflowProcessInstance 类型仅匹配当前流程实例,而不匹配其他流程实例 工作内存中的流程实例。但请注意,您有责任自己 将流程实例插入会话中,并可能更新它,例如使用 Java 代码或流程中的进入或退出或显式操作。
但是我不知道如何执行此处描述的操作。如何将流程实例添加到工作内存中,以便第一个规则节点可以访问它?规则节点似乎不支持输入行为,并且我无法将其添加到 Java 代码中,因为在工作内存更新为之前,该进程可以很容易地完成规则节点的执行包括过程。
The short version: How do I get JBPM5 Rule Nodes to use a DRL file which reads and updates process variables?
The long version:
I have a process definition, being run under JBPM5. The start of this process looks something like this:
[Start] ---> [Rule Node] ---> [Gateway (Diverge)] ... etc
The gateway uses constraints on a variable named 'isValid'.
My Rule Node is pointing to the RuleFlowGroup 'validate', which contains only one rule:
rule "Example validation rule"
ruleflow-group "validate"
when
processInstance : WorkflowProcessInstance()
then
processInstance.setVariable("isValid", new Boolean(false));
end
So, by my logic, if this is getting correctly processed then the gateway should always follow the "false" path.
In my Java code, I have something like the following:
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add(ResourceFactory.newClassPathResource("myProcess.bpmn"), ResourceType.BPMN2);
kbuilder.add(ResourceFactory.newClassPathResource("myRules.drl"), ResourceType.DRL);
KnowledgeBase kbase = kbuilder.newKnowledgeBase();
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
new Thread(new Runnable()
{
public void run()
{
ksession.fireUntilHalt();
}
}).start();
// start a new process instance
Map<String, Object> params = new HashMap<String, Object>();
params.put("isValid", true);
ksession.startProcess("test.processesdefinition.myProcess", params);
I can confirm the following:
- The drl file is getting loaded into working memory, because when I put syntax errors in the file then I get errors.
- If I include a value for "isValid" in the Java params map, the process only ever follows the path specified by Java, apparently ignoring the drools rule.
- If I take the "isValid" parameter out of the params map, I get a runtime error.
From this I assume that the final "setVariable" line in the rule is either not executing, or is updating the wrong thing.
I think my issue is related to this statement in the official documentation:
Rule constraints do not have direct access to variables defined inside the process. It is
however possible to refer to the current process instance inside a rule constraint, by adding
the process instance to the Working Memory and matching for the process instance in your
rule constraint. We have added special logic to make sure that a variable processInstance of
type WorkflowProcessInstance will only match to the current process instance and not to other
process instances in the Working Memory. Note that you are however responsible yourself to
insert the process instance into the session and, possibly, to update it, for example, using Java
code or an on-entry or on-exit or explicit action in your process.
However I cannot figure out how to do what is described here. How do I add the process instance into working memory in a way that would make it accessible to this first Rule Node? Rule Nodes do not seem to support on-entry behaviors, and I can't add it to the Java code because the process could very easily complete execution of the rules node before the working memory has been updated to include the process.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
正如您所提到的,有多种选项可以将流程实例插入到工作内存中:
- 在调用startProcess()之后插入它
- 使用操作脚本插入它(使用“insert(kcontext.getProcessInstance()”)
如果调用 startProcess() 可能已经完成了规则任务(这可能是您的示例中的情况),并且您没有规则任务前面的另一个节点,您可以在其中使用进入/退出脚本来执行此操作(因此它是隐藏的),我建议在规则任务之前使用显式脚本任务
Kris来执行此操作。
As you mentioned, there are several options to inserting the process instance into the working memory:
- inserting it after calling startProcess()
- using an action script to insert it (using "insert(kcontext.getProcessInstance()")
If calling startProcess() might already have gone over the rule task (which is probably the case in your example), and you don't have another node in front of your rule task where you could just use an on-entry/exit script to do this (so that's is hidden), I would recommend using an explicit script task before your rule task to do this.
Kris