JBoss 系列六十一:深入理解 jBPM Human Task - I

概述

Human Task 是BPM流程中的节点必需通过人为的手动操作才能够执行。jBPM 5 通过 User Task(jBPM5示例之 User Task) 节点来支持Human Task。Human Task通常要求流程设计者在设计流程时指定流程运行相关的属性,流程类型,流程的执行者,流程运行相关的数据。流程运行时我们根据这些属性运行流程。


Human Task 是BPM核心,为什么可以这样说呢?一位BPM专家曾在某次BPM技术峰会上这样定义BPM:“BPM is a blending of process management/workflow with application integration technology...to support rich human interaction and deep application connectivity”。注意他所表达BPM的目的或价值就是为复杂的企业应用提供广泛的人为操作的可能性。


本文主要目的是通过实验理解jBPM Human Task ,我们所需要的工具包括git,Maven,JBoss等,这些安装可参照软件安装及资料下载。本文主要内容包括:

  • 下载编译jBPM Human Task 代码
  • 部署jBPM Human Task 服务到JBoss
  • jBPM Human Task 数据模型
  • 通过TaskClient与Human Task 服务端交互
  • Human Task的生命周期

下载编译jBPM Human Task 代码

本部分我们下载编译jBPM 5.2.x代码(https://github.com/droolsjbpm/jbpm/tree/5.2.x),具体使用如下git命令克隆:

git clone --branch=5.2.x [email protected]:droolsjbpm/jbpm.git

克隆完成使用如下maven命令编译jBPM 5.2.x代码:

mvn clean install -Dmaven.test.skip=true

如以上步骤没有出现错误则该部分完成,我们需要如下编译生成的包或Maven本地仓库中的包来供我们使用:

  • jbpm-human-task-war-5.2.6-SNAPSHOT-EE6.war - 位于jbpm-human-task-war/target目录下

部署jBPM Human Task 服务到JBoss

本部分我们部署jbpm-human-task-war-5.2.6-SNAPSHOT-EE6.war到JBoss 7。具体参照使用4种方式部署应用到JBoss7/WildFly。

我们需要基于jbpm-human-task-war-5.2.6-SNAPSHOT-EE6.war做如下操作:

1. 重命名

unzip jbpm-human-task-war-5.2.6-SNAPSHOT-EE6.war jbpm-human-task.war

2. 创建数据库

jBPM Human Task执行过程需要存储数据在数据库中,我们本实验使用mysql数据库,我们使用如下SQL语句创建数据库jbpm,jbpm_user用来操作数据库jbpm,jbpm_user对应密码jbpm_pass:

CREATE DATABASE jbpm;  
create user 'jbpm_user'@'localhost' identified by 'jbpm_pass';  
grant all on jbpm.* to jbpm_user@'localhost';  
FLUSH PRIVILEGES;

3. 创建jbpmDS数据源

使用JBoss 7/WildFly中配置使用Mysql数据库中描述的方法创建数据源jbpmDS指向上面步骤2创建的数据库和用户,数据源如下:

<datasource jndi-name="java:jboss/datasources/jbpmDS" pool-name="jbpmPool">  
      <connection-url>jdbc:mysql://localhost:3306/jbpm</connection-url>  
      <driver>mysql</driver>  
      <security>  
         <user-name>jbpm_user</user-name>  
         <password>jbpm_pass</password>  
      </security>  
</datasource> 

4. 修改persistence.xml

修改jbpm-human-task.war/WEB-INF/classes/META-INF/persistence.xml文件,配置hibernate.dialect属性为org.hibernate.dialect.MySQL5Dialect,hibernate.show_sql属性为true。

5. 更新hornetq-core-2.2.10.Final.jar

这一步是可选择的,hornetq-core-2.2.10.Final.jar包存在Socket leak等不稳定问题,我建议升级此包。

6. 启动JBoss

使用JBoss启动脚本./standalone.sh启动JBoss,启动完成后可以看到jbpm-human-task.war部署成功提示。我们会发现如下日志信息:

17:19:07,950 INFO  [stdout] (ServerService Thread Pool -- 52) Task service startup completed successfully !

使用netstat命令,输出所有端口使用情况:

[kylin@localhost lib]$ netstat -antulop | grep 13179
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
tcp        0      0 127.0.0.1:4447              0.0.0.0:*                   LISTEN      13179/java          off (0.00/0/0)
tcp        0      0 127.0.0.1:5153              0.0.0.0:*                   LISTEN      13179/java          off (0.00/0/0)
tcp        0      0 127.0.0.1:9990              0.0.0.0:*                   LISTEN      13179/java          off (0.00/0/0)
tcp        0      0 127.0.0.1:9999              0.0.0.0:*                   LISTEN      13179/java          off (0.00/0/0)
tcp        0      0 127.0.0.1:8080              0.0.0.0:*                   LISTEN      13179/java          off (0.00/0/0)
tcp        0      0 127.0.0.1:44186             127.0.0.1:5153              ESTABLISHED 13179/java          keepalive (5695.77/0/0)
tcp        0      0 127.0.0.1:34368             127.0.0.1:3306              ESTABLISHED 13179/java          keepalive (5695.77/0/0)
tcp        0      0 127.0.0.1:5153              127.0.0.1:44186             ESTABLISHED 13179/java          keepalive (5695.77/0/0)

注意,5153为 Human Task Service在服务器端监听的端口。

jBPM Human Task 数据模型

上面一部分中,我们创建了空白的数据库jbpm,jBPM使用JPA/Hobernate作为数据持久工具,当JBoss启动成功后Hibernate会向数据库jbpm创建表,我们在mysql管理端使用jbpm_user用户登录后查看表创建情况。

show tables输出:

mysql> show tables;
+--------------------------------+
| Tables_in_jbpm                 |
+--------------------------------+
| Attachment                     |
| BooleanExpression              |
| Content                        |
| Deadline                       |
| Delegation_delegates           |
| Escalation                     |
| I18NText                       |
| Notification                   |
| Notification_BAs               |
| Notification_Recipients        |
| Notification_email_header      |
| OrganizationalEntity           |
| PeopleAssignments_BAs          |
| PeopleAssignments_ExclOwners   |
| PeopleAssignments_PotOwners    |
| PeopleAssignments_Recipients   |
| PeopleAssignments_Stakeholders |
| Reassignment                   |
| Reassignment_potentialOwners   |
| SubTasksStrategy               |
| Task                           |
| email_header                   |
| task_comment                   |
+--------------------------------+
23 rows in set (0.00 sec)

即jBPM执行Human Task所需要的表共23个。

我们在jbpm human task 源代码分析 - I的org.jbpm.task.Task部分解释了数据模型类,以上这些表是数据实体模型对应数据库中表的映射。接下来的一个部分我们演示如何使用jBPM Human Task Service提供的接口对数据库中的数据进行操作。

通过TaskClient与Human Task 服务端交互

在之前步骤的基础上,本处我们通过TaskClient与Human Task 服务端交互,创建Task,开始Task,结束Task。

创建Task

org.jbpm.conductor.humantask.TaskAdd演示如何使用TaskClient在客户端执行创建Task的操作,如下为部分代码片段:

	TaskClient client = getTaskClientInstance();
        client.connect();
		
        Task task = newTask();
        ContentData content = new ContentData();
        
        BlockingAddTaskResponseHandler addTaskResponseHandler = new BlockingAddTaskResponseHandler();
        client.addTask(task, content, addTaskResponseHandler );
        long taskId = addTaskResponseHandler.getTaskId();
        System.out.println("Add Task to human task service, taskId: " + taskId);

以Java Application的方式运行org.jbpm.conductor.humantask.TaskAdd输出

Add Task to human task service, taskId: 1

在Mysql数据库端通过SQL语句查询得到如下结果:

mysql> select id, status, actualOwner_id, createdBy_id, activationTime from Task;
+----+----------+----------------+--------------+---------------------+
| id | status   | actualOwner_id | createdBy_id | activationTime      |
+----+----------+----------------+--------------+---------------------+
|  1 | Reserved | kylin          | kylin        | 2013-12-02 16:51:24 |
+----+----------+----------------+--------------+---------------------+

获取Task

org.jbpm.conductor.humantask.Getting演示如何使用TaskClient在客户端执行获取Task的操作,如下为部分代码片段:

        TaskClient client = getTaskClientInstance();
        client.connect();
        
        BlockingTaskSummaryResponseHandler taskSummaryResponseHandler = new BlockingTaskSummaryResponseHandler();
        client.getTasksAssignedAsPotentialOwner("kylin", "en-UK", taskSummaryResponseHandler);
        List<TaskSummary> tasks = taskSummaryResponseHandler.getResults();
        System.out.println("Getting tasks for human task service via user kylin, tasks size: " + tasks.size());

以Java Application的方式运行org.jbpm.conductor.humantask.TaskGetting输出

Getting tasks for human task service via user kylin, tasks size: 1

开始Task

org.jbpm.conductor.humantask.TaskStart演示如何使用TaskClient在客户端执行开始Task的操作,如下为部分代码片段:

        TaskClient client = getTaskClientInstance();
        client.connect();
        
        BlockingTaskOperationResponseHandler responseHandler = new BlockingTaskOperationResponseHandler();
        client.start(1, "kylin", responseHandler);
        responseHandler.waitTillDone(1000);
        System.out.println("kylin starting Task ");

以Java Application的方式运行org.jbpm.conductor.humantask.TaskStart输出

kylin starting Task

在Mysql数据库端通过SQL语句查询得到如下结果:

mysql> select id, status, actualOwner_id, createdBy_id, activationTime from Task;
+----+------------+----------------+--------------+---------------------+
| id | status     | actualOwner_id | createdBy_id | activationTime      |
+----+------------+----------------+--------------+---------------------+
|  1 | InProgress | kylin          | kylin        | 2013-12-02 16:51:24 |
+----+------------+----------------+--------------+---------------------+

完成Task

org.jbpm.conductor.humantask.TaskComplete演示如何使用TaskClient在客户端执行完成Task的操作,如下为部分代码片段:

        TaskClient client = getTaskClientInstance();
        client.connect();
    
        ContentData content = new ContentData();
        
        BlockingTaskOperationResponseHandler responseHandler = new BlockingTaskOperationResponseHandler();
        client.complete(2, "kylin", content, responseHandler);
        responseHandler.waitTillDone(1000);
        System.out.println("kylin completing Task ");

以Java Application的方式运行org.jbpm.conductor.humantask.TaskComplete输出

kylin completing Task

在Mysql数据库端通过SQL语句查询得到如下结果:

mysql> select id, status, actualOwner_id, createdBy_id, activationTime from Task;
+----+-----------+----------------+--------------+---------------------+
| id | status    | actualOwner_id | createdBy_id | activationTime      |
+----+-----------+----------------+--------------+---------------------+
|  1 | Completed | kylin          | kylin        | 2013-12-02 16:51:24 |
+----+-----------+----------------+--------------+---------------------+

另外我们还可以使用如下SQL在Mysql管理端进行管理查询:

select DTYPE, id from OrganizationalEntity;
select id, language, text from I18NText;

Human Task的生命周期

当一个 Human Task 节点在流程执行过程中被激活,一个人为参与的工作产生,流程只有在该人为参与的工作完成或取消后才离开该节点。

Human Task 的生命周期如下:
  1. Task被创建,一开始状态为'created'
  2. Task状态通常会自动转变为'Ready',该状态的Task会在Task列表中,可以被用户请求
  3. Task被用户请求,状态变为'Reserved'
  4. Task被用户开始,状态变为'InProgress'
  5. Task被用户结束,状态变成'Completed',如果用户不能够结束Task,会返回一个错误的结果,这样Task状态变成'Failed'

Next


你可能感兴趣的:(jboss,jbpm,企业应用,task,BPM,human)