jBPM 支持在 流程 内使用一个指定的 用户 任务节点(如上面图所示)表示人工任务。
一个用户任务节点代表一个原子性的任务,需要通过一个人角色来执行。
虽然 jBPM 流程中的人工任务包含有指定用户节点,但人工任务可以简单的看做是任何类型的外部服务,需要调用时作为工作任务项的一种特殊类型的简单实现。
唯一要指出的是用户任务节点,我们添加了对泳道的支持,从而更容易将任务分配给用户(见下文)。
一个用户任务节点包含下列属性:
- Id
:节点的 ID (
在一个节点容器内他是唯一的)。 - Name
:该节点显示的名称。 - Task Name
:人工任务的名称。 - Priority
:一个整数,表示人工任务的优先级。 - Comment :人工任务关联的注释。
- ActorId
:执行者 ID 是负责执行任务的人。
多个 的执行者 ID 可以使用逗号作为分隔 (',') 。 - Skippable
:指定人工任务是否可以跳过(即执行者决定不执行人工任务)。 - Contend :任务关联数据。
- Swimlane :泳道是人工任务节点的一部分。
泳道可以很容易地分配多个人工任务到同一个执行者。
请参阅下面详细的泳道使用。 - Wait for completion
:如果此属性为 true ,人类任务终止了(即完成或任何其他终止状态)人工任务节点才能继续,否则它会创造人工任务后立即继续任务。 - On-entry and on-exit action s
:进入和退出节点后执行此 Actions 。 - Parameter mapping
:允许复制的流程变量值到人工任务参数中。
当人工任务创造后,这些值将被复制。 - Result mapping :允许复制人工任务的结果参数到流程变量。
人工 任务完成后,这些值将被复制。
请注意, “Wait for completion” 设置为 true 时只能使用结果映射。
一个人工任务有一个结果变量的 “Result” ,它包含返回的数据通过人工执行者。
变量 “actorId 来 ” 包含了实际任务执行执行者的 ID 。 - Timers
: Timers 关联到这个节点 。 - ParentId
:允许指定的父任务 Id ,这是表示这个任务做为另外一个的子任务。
二、人工任务生命周期
从这个流程透视来看,每当一个流程实例的执行时用户任务节点将触发,创建一个人工任务。
这个流程想该点继续只有当人工任务已经完成或中止(当然,除非你指定该过程不需要等待人工任务完成,通过设置 “Wait for completion” 属性设置为 true )。
然而,人工任务本身通常有一个单独的生命周期。
现在,我们将很快介绍这个生命周期,如下面的图所示。
每当一个任务被创建时,它进入 “Created” 状态。
它通常会自动转移换到 “Ready” 状态,此时任务会显示允许执行任务的所有执行者 (actors) 。
在这里,它将等待一个执行者认领任务,这表明他或她将要执行这个任务。
一旦用户认领了一个任务,状态更改为 “Reserved” 。
请注意,在任务创建时任务只有一个潜在的执行者将自动分配给执行者,
获取任务后,该用户可以决定在某个时候开始执行任务,在这种情况下,任务的状态更改为 “InProgress” 。
最后,一
旦任务已经执行,用户必须完成任务(并且可以指定相关的任务的结果数据),在这种情况下,状态更改为 “Completed” 。
如果任务无法完成,用户还可以指明为响应故障(可能的相关故障数据),在这种情况下,状态更改为 “Failed” 。
以上是正常生命周期的解释。
该服务还允许其他生命周期的方法,如:
o
委派或转发任务,在这种情况下,它被分配给另一个执行者
o
撤销任务,这样它不再指派给一个指定的执行者,所有潜在的执行者将重新出现的任务列表
o
暂停和恢复任务
o
停止进行中的任务
o
跳过一个任务(如果该任务已被列为 skippable 标记),在这种情况下,任务将不会执行
三、示例实现
人工任务节点在JBPM5中是一个异步WorItem,JBPM5中已经带有一个WorkItemHandler的人工任务的实现类是WSHumanTaskHandler,这个handler能同一个Task Service通信(由jBPM5提供),并在其中创建一个新的任务。然后,它将等待别人(使用人工客户端API)来完成/取消该任务。
在jbpm5中你可以实现WorkItemHandler接口, 不使用默认实现,根据你需要进行。
如:
class MyNonAutomaticHumanSimulatorWorkItemHandler implements WorkItemHandler {
private WorkItemManager workItemManager;
private long workItemId;
public void executeWorkItem(WorkItem workItem, WorkItemManager workItemManager) {
this.workItemId = workItem.getId();
this.workItemManager = workItemManager;
System.out.println("Map of Parameters = " + workItem.getParameters());
}
public void abortWorkItem(WorkItem workItem, WorkItemManager workItemManager) {
}
public void completeWorkItem(Map<String, Object> parameters) {
this.workItemManager.completeWorkItem(this.workItemId, parameters);
}
那在注册的时候你就可以注册自已的实现:
MyHumanChangingValuesSimulatorWorkItemHandler humanActivitiesSimHandler = new MyHumanChangingValuesSimulatorWorkItemHandler();
ksession.getWorkItemManager().registerWorkItemHandler("Human Task", humanActivitiesSimHandler);
在实现在我们需要实现一个服务端和一个客户端,jBPM5的安装包中提供一个示例,它服务端采用ant启动, 数据库 使用h2。下面将依据这个示例做一个类似的例示,数据据使用MYSQL5,学习它们之间的交互。
o
服务端实现
1、继承UserInfo,方便添加用户与组相关信息;
2、添加一个最小的服务监听实现;
public void startServer() {
if(isRunning())
throw new IllegalStateException("Server is already started");
this.running = true;
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("org.drools.task");
TaskService taskService = new TaskService(entityManagerFactory, SystemEventListenerFactory.getSystemEventListener());
TaskServiceSession taskSession = taskService.createSession() ;
UserInfoDomain userInfo = new UserInfoDomain();
taskService.setUserinfo( userInfo);
for (String userName : getDefaultUsers()) {
taskSession.addUser(new User(userName));
}
taskServer = new MinaTaskServer(taskService);
Thread thread = new Thread(taskServer);
thread.start();
}
3、配置数据库连接
人工任务有相关的数据实体,包含在jbpm-human-task.5.0.0.jar中,在示例代码中我将提供。
o
客户端实现
通过jbpm提供连接方法实现。如下:
/**
* 创建客户端连接
*
*/
public HumanTaskClient() {
client = new TaskClient(new MinaTaskClientConnector("client 1",
new MinaTaskClientHandler(SystemEventListenerFactory.getSystemEventListener())));
client.connect("127.0.0.1", 9123);
}
/**
* 加载流程模板和注册人工任务
* @throws RuntimeException
*/
public void start() throws RuntimeException {
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add(new ClassPathResource("rules/humanTask.bpmn"), ResourceType.BPMN2);
System.out.println("Compiling resources");
if (kbuilder.hasErrors()) {
if (kbuilder.getErrors().size() > 0) {
for (KnowledgeBuilderError error : kbuilder.getErrors()) {
System.out.println("Error building kbase: "+error.getMessage());
}
}
throw new RuntimeException("Error building kbase!");
}
KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
kbase.addKnowledgePackages(kbuilder.getKnowledgePackages());
ksession = kbase.newStatefulKnowledgeSession();
logger = KnowledgeRuntimeLoggerFactory.newConsoleLogger(ksession);
ksession.getWorkItemManager().registerWorkItemHandler("Human Task", new WSHumanTaskHandler());
}
/**
* 启动流程
* @throws RuntimeException
*/
public void startProcess() throws RuntimeException {
try {
ksession.startProcess( "com.zt.jbpm.humantask.client", null );
}
catch (IllegalArgumentException ex) {
throw new RuntimeException(ex.getMessage());
}
}
四、运行
1、启动 服务器 监听:
直接在eclipse里面运行StartHumanTaskServer类的 main方法
运行客户端:直接在eclipse里面运行Application类的main方法