alartin's profileWindows Live 共享空间PhotosBlogListsMore Tools Help

Blog


    January 22

    JBPM: 任务的管理 Task Management

    概述

    JBPM的核心就是持久化流程。持久化流程中最重要的特性就是管理人们的任务和任务列表。JBPM允许我们设定程序为人工参与进入等待状态。

    任务

    任务是流程定义的一部分。任务负责定义流程执行中任务实例task instance如何必须被创建和指派。所以任务也就是任务定义。任务可以在任务节点中定义,也可以在流程定义中定义。不过通常的方法是在任务节点中定义一个或者多个任务。这意味着任务节点task node代表着一个用户的人工任务,流程执行必须等待直到参与者actor(也就是用户)完成这项人工任务。当参与者actor完成人工任务后,流程执行将继续。如果一个任务节点中指定了多个任务,默认的行为是必须流程执行必须等待所有任务都完成

    流程定义中也能定义任务。在流程定义中的任务能够通过名字查找,在任务节点中被引用,或者内部动作inside actions中使用。事实上,无论任务在流程定义中定义还是在任务节点中定义,只要任务有名字,都能够在流程定义中查找。需要注意的是:任务的名字在整个流程定义中必须唯一的。

    任务可以有优先级。优先级在这个任务的每个任务实例中作为初始优先级。任务实例task instance能够在日后修改这个优先级。

    任务实例 task instance

    一个任务实例能够被指派给一个参与者ID, actorId(一个字符串)。所有的任务实例都在JBPM的JBPM_TASKINSTANCE表中存储。我们可以通过这张表查询给定actorId的所有任务实例,通过这种方法你可以获得特定用户的任务列表。JBPM任务列表机制能够将JBPM任务和其他任务结合起来,甚至能够结合那些和流程执行不相关的任务。通过这种方式,JBPM的开发者能够容易的将JBPM流程任务和其他系统的任务在一个同一的任务列表仓库同一管理。

    任务实例的生命周期

    任务实例的生命周期非常直观:创建后,任务实例就可以开始了,然后,可以被结束,这意味着任务实例被标记为完成。注意:为了灵活性,任务的指派并不是任务实例生命周期的一部分。所以任务实例可以被指派了,也可以尚未指派,这丝毫不影响任务实例的生命周期。任务实例通常是在流程执行进入任务节点的时候被创建。创建的方法是TaskMgmtInstance.createTaskInstance()。然后,用户界面组件可以通过TaskMgmtInstance.findTaskInstanceByActorId()方法查询任务列表。用户界面组件可以调用TaskInstance.assign(String), TaskInstance.start(), TaskInstance.end()等方法。

    任务实例通过日期属性来维护它的状态:create, start, end. 可以通过TaskInstance相应getter方法访问。目前完成了的任务实例将会通过结束日期被标记为完成,因此对于后续查询任务列表的时候,完成了的任务实例不会被包含在任务列表中,不过它们仍旧在JBPM_TASKINSTANCE表中

    任务实例和图的执行

    从某种意义上说,任务实例是参与者actor任务列表上的项目。任务实例可以信号化,信号化的任务实例可以在任务结束的时候向token发出signal,让流程执行继续下去。任务实例也可以拦截化/阻止化,这意味着相关的token在任务未完成前不能离开任务节点。任务实例默认是信号化的

    在一个任务节点中有多个任务实例的情况下,流程的开发者可以指定任务实例的完成将如何影响流程执行的继续。通过任务节点的signal属性的各种值来控制这一点:

    • last: 这是默认的。当最后一个任务完成时,流程执行将继续。当节点的入口处没有任务被创建的时候,流程执行将继续。
    • last-wait:当最后一个任务完成时,流程执行将继续。当节点的入口处没有任务被创建的时候,流程执行将在任务节点中等待直到任务被创建为止。
    • first:当第一个任务完成时,流程执行将继续。当节点的入口处没有任务被创建的时候,流程执行将继续。
    • first-wait:当第一个任务完成时,流程执行将继续。当节点的入口处没有任务被创建的时候,流程执行将在任务节点中等待直到任务被创建为止。
    • unsynchronized: 流程执行将永远继续下去,无论任务是否被创建或者仍未完成。
    • never: 流程执行将不再继续,无论任务是否被创建或者仍未完成,和unsynchronized相对。

    任务实例也可以通过运行时计算而创建。在这种情况下,在任务节点的进入节点事件中添加一个ActionHandler,并且将属性create-task设为false(意味着进入任务节点并不创建任务,而是让动作监听进入节点事件,在动作中运行时计算), 下面是个例子:

    public class CreateTasks implements ActionHandler {
      public void execute(ExecutionContext executionContext) throws Exception {
        Token token = executionContext.getToken();
        TaskMgmtInstance tmi = executionContext.getTaskMgmtInstance();
          
        TaskNode taskNode = (TaskNode) executionContext.getNode();
        Task changeNappy = taskNode.getTask("change nappy");
    
        // now, 2 task instances are created for the same task.
        tmi.createTaskInstance(changeNappy, token);
        tmi.createTaskInstance(changeNappy, token);
      }
    }
    我们提到过,任务可以在任务节点中定义,也可以在流程定义中定义。如果在流程定义中定义,我们可以通过TaskMgmtDefinition获取。
    TaskMgmtDefinition继承了ProcessDefinition, 提供了任务管理信息
    完成一个任务实例很简单,调用TaskInstance.end()方法就可以了。你也可以在这个方法中指定一个转移transition,这样的话,任务实例完成
    后将触发流程执行继续下去,离开任务节点,走向指定的转移。
    任务指派
    流程定义中包含了任务节点。一个任务节点可以包含零个或多个任务。什么是任务呢?任务其实就是流程定义中静态描述的一部分(是说任务仅仅是个描述而已)。在运行时,任务实例
    将根据任务这个描述创建。而一个任务实例可以说就是一个人的任务列表中的一项。任务实例总是要被指派的。
    JBPM的任务指派模型分为PULL和PUSH.
    任务指派的数据模型
    image 
    任务实例或泳道实例的参与者ID actorId负责这个任务。而其中的PooledActors, 参与者候选池维护一系列任务的候选者,每个候选者都有可能负责这个任务,当候选者获得这个任务
    后,他就为这个任务负责。需要注意的是:参与者ID和参与者候选池是可选的,也可以组合在一起使用。
    个人的任务列表
    个人任务列表负责维护指派给特定个人的任务,通过任务实例的参与者ID就可以看出。所以要想将任务实例放入个人任务列表中,只需下列方法的一种:
    • 在流程定义中的task元素的actor-id属性中指定表达式
    • 也可以在代码的任何地方设置TaskInstance.setActorId(String)方法
    • 也可以在一个AssignmentHandler中调用Assignable.setActorId(String)方法

    我们可以通过TaskMgmtSession.findTaskInstances(String actorId)来获取特定人的任务列表。

    组的任务列表

    参与者候选池指的是任务实例的候选者。这意味着这个任务可以提供给多个用户,其中一个候选者可以被设置接受这个任务。候选池中的参与者可以看作是同一个组的,如果这个任务是提供给候选池的,用户必须先将任务拿到个人的任务列表中,才能执行任务。

    TODO

    背后的动机是我们希望将Identity组件从JBPM的任务指派中剥离。JBPM应该只关注actorId这些String类型的对象,而不应该关注用户,组或者其他识别信息之间的关系。

    actorId总是覆盖参与者候选池中的actor(pooled actor)。所以如果任务实例既有actorId,也有参与者候选池的话,那么这个任务实例只出现在个人任务列表中。不过,参与者候选池有重要作用,一个用户可以将任务实例放回到组中重新供参与者候选人获取,这些只需要将任务实例的actorId属性去掉即可。

    任务实例变量

    任务实例可以拥有自己的一套变量,并且任务实例能够“看见”流程变量。任务实例是在一条执行路径token中创建的。需要注意的是:token和在这个token中创建的任务实例之间也是父子关系,这和token和其子token是父子关系是一样的。任务实例的变量和token相关的流程变量之间的范围规则同样适用。这意味着一个任务实例能够看到自己的一套变量,加上和它相关的token的所有变量。

    任务控制器能够用来在任务实例范围和流程范围变量之间传递和提交变量。

    任务控制器

     image

    任务控制器本质上是流程变量和用户界面程序的桥梁。从这张图片可以看出,任务是以任务实例的方式赋给特定的用户的,任务控制器任务实例负责流程变量和任务变量之间的传递。用户只能通过任务实例中的变量和流程打交道,因此用户界面接口中的输入输出都是流程变量<->任务控制器<->任务实例<->用户界面。因此实际上用户在界面中输入的都是以任务变量的形式保存,当任务结束后通过任务控制器来将任务变量转化为流程变量。

    最简单的情况下,流程变量和用户的表单参数是一对一的。任务控制器在任务元素中指定。JBPM提供一个默认的任务控制器,它维护一个变量元素列表。变量元素指示如何将流程变量拷贝到任务变量。

    <task name="clean ceiling">
      <controller>
        // name属性指的是流程变量的名字,mapped-name属性指的是任务变量的名字,如果没有设定mapped-name,则任务变量名和流程变量名一致
        // 需要注意的是:mapped-name任务变量名就是任务实例表单中字段的标签
        // access属性指定变量传递的形式,read指的是任务实例创建时,从流程变量中拷贝到任务变量
        // write指的是任务实例完成时,从任务变量中拷回到流程变量中,默认的是read,write
        <variable name="a" access="read" mapped-name="x" />
        <variable name="b" access="read,write,required" mapped-name="y" />
        <variable name="c" access="read,write" />
      </controller>
    </task>
    需要注意的是:一个任务节点可以有多个任务,而一个开始状态start-state只能有一个任务
    如果你觉得流程变量和表单参数一对一的关系无法满足需求的话,你也可以实现自己的任务控制器TaskControllerHandler。
    public interface TaskControllerHandler extends Serializable {
      void initializeTaskVariables(TaskInstance taskInstance, ContextInstance contextInstance, Token token);
      void submitTaskVariables(TaskInstance taskInstance, ContextInstance contextInstance, Token token);
    }
    <task name="clean ceiling">
      <controller class="com.yourcom.CleanCeilingTaskControllerHandler">
        // 此处配置实现的任务控制器
      </controller>
    </task>

    Comments

    Please wait...
    Sorry, the comment you entered is too long. Please shorten it.
    You didn't enter anything. Please try again.
    Sorry, we can't add your comment right now. Please try again later.
    To add a comment, you need permission from your parent. Ask for permission
    Your parent has turned off comments.
    Sorry, we can't delete your comment right now. Please try again later.
    You've exceeded the maximum number of comments that can be left in one day. Please try again in 24 hours.
    Your account has had the ability to leave comments disabled because our systems indicate that you may be spamming other users. If you believe that your account has been disabled in error please contact Windows Live support.
    Complete the security check below to finish leaving your comment.
    The characters you type in the security check must match the characters in the picture or audio.

    To add a comment, sign in with your Windows Live ID (if you use Hotmail, Messenger, or Xbox LIVE, you have a Windows Live ID). Sign in


    Don't have a Windows Live ID? Sign up

    Trackbacks

    The trackback URL for this entry is:
    http://alarnan.spaces.live.com/blog/cns!819CBC613DE169EF!177.trak
    Weblogs that reference this entry
    • None