jBPM 是一个非常优秀的开源工作流引擎
虽然他不是一个一站式的工作流平台
不过它已经为我们提供了比较丰富的底层操作
为了满足特定的项目需求
我们一般需要对其进行二次开发
才能适用于具体的业务需求
其中一个主要的扩展点是针对 TaskNode 进行的用户的分配TaskNode 是 jBPM 中一个非常重要的概念一个任务节点可以包含若干个任务不同的任务可以由不同的人来完成任务实例被分配给 actorId 来完成其中指定到人的分配工作就是 Assignment 要处理的这也是我们需要定制的功能为了实现用户的分配我们需要实现 AssignmentHandler 接口接口原型如下
public interface AssignmentHandler extends Serializable {
void assign(Assignable assignable ExecutionContext executionContext) throws Exception;
}
通常用代码实现的话我们可以让一个类实现这个接口并在 swimlane 或者 tasknode 中的 assignment 指定该类但是这样的灵活性是显然不够的在系统的使用过程中分配策略会不断的进行调整因此我们需要更为灵活的解决方案jBPM 本身可以使用基于 Bean Shell 的脚本来写分配策略但是 Bean Shell 不是那么强大我们需要更为强大的解决方案因此我们选用了已经被 JBoss 收为旗下的 JBoss Drools 规则引擎 (在 的时候曾经改名为 JBoss Rules 又改回来了)
jBPM 和 Drools 虽然同在 JBoss 旗下不过他们目前并没有很好的进行整合所以我们还是要利用它们系统系统的一些功能来做整合同样也是实现 AssignmentHandler 接口不过另外我们利用了 jBPM 里面的一个小小的技巧看一下这段配置
AgentAssignmentRule
红色标注的这段配置我们可以理解为在 RulesAssignmentHandler 这个类里有一个 ruleName 这样的属性在初始化这个类的时候jBPM 会把配置中 ruleName 的值 set 给 RulesAssignmentHandler 中 ruleName 的属性
public class RulesAssignmentHandler implements AssignmentHandler {
protected String ruleName;
public String getRuleName() {
return ruleName;
}
public void setRuleName(String ruleName) {
thisruleName = ruleName;
}
protected RuleBase readRule(String ruleName) throws Exception {
// 到 classes 下的 /rules 下加载相应的文件
String rulePath = /rules/ + ruleName + drl;
Resource resource = new ClassPathResource(rulePath);
Reader reader = new InputStreamReader(resourcegetInputStream());
PackageBuilder builder = new PackageBuilder();
builderaddPackageFromDrl(reader);
Package pkg = buildergetPackage();
RuleBase ruleBase = RuleBaseFactorynewRuleBase();
ruleBaseaddPackage(pkg);
return ruleBase;
}
protected void initRuleContextData(ExecutionContext executionContext WorkingMemory workingMemory) {
ContextInstance ci = executionContextgetContextInstance();
Map vars = cigetVariables();
workingMemoryinsert(ci);
workingMemoryinsert(vars);
}
public void assign(Assignable assignable ExecutionContext executionContext) throws Exception {
RuleBase ruleBase = readRule(ruleName);
WorkingMemory workingMemory = ruleBasenewStatefulSession();
// 为了简便操作我只是拿了放入 ExecuteContext 中的 variable 进行逻辑处理
initRuleContextData(executionContext workingMemory);
workingMemoryinsert(assignable);
workingMemoryfireAllRules();
}
}
对应的 AgentAssignmentRuledrl 文件内容如下假定 ExecutionContext 中有 price 这个 variable我们判定当这个值 > 的时候我们将此任务分配给 senior_agent 来处理
package orgagilejavaworkflow
import javautilMap
import orgjbpmtaskmgmtexeAssignable
rule Assign Agent
when
a : Assignable()
Map(this[price] >= )
then
asetActorId(senior_agent);
end
就这样我们就完成了最为简单的 jBPM 和 Drools 的整合当然这种方式只是简单的利用了 jBPM 的一些特性来做的我们每次都得指定这个 RulesAssignmentHandler还是很麻烦的更好的方式就是我们改写 ProcessDefinitionxml 的 parser让 Drools 的规则定义成为和 swimlane actorid expression 这样的分配方式同样级别的让 Drools 成为 jBPM 的一等公民这个以后研究好了再来和大家分享