Drools 5.1.1_DOC (54)

本文介绍了Drools 5.1版本中人类任务管理的实现细节,包括任务节点属性、泳道支持、任务生命周期管理、任务服务组件集成及用户界面等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Drools 5.1.1_DOC_Drools Flow

 

第10章  人类任务( Human Tasks)

 

工 作流和BPM (business process management)的一个重要方面是人类任务管理。 虽然某些在流程中执行的工作可以自动执行,某些任务则需要与人类参与者交互执行。

Drools流支持人类任务的使用,在流程内使用特殊人类任务节点——表 示这种交互。这些节点允许流程设计者定义任务类型、参与者、与任务关联的数据等等。我们还实现

了一个任务服务,可以使用它来管理这些人类任务。然而如果用 户需要,可以打开集成任何其他的解决方案,因为它完成是可插式的。

要在你的流程内开始使用人类任务,你首先需要(1)在你的任务中包括人类任务节点,(2)集成你选择的一个任务管理组件(例如,我们提供的WS-HT实现),

(3)使用某种用户界面,让终端用户与人类任务管理组件交互。在下面章节会详细讨论这些元素。

 

10.1.  流程内部的人类任务

Drools 5.1.1_DOC (54) - *工* - 要有光,于是就有了光

Drools 流支持在流程内部使用人类任务,通过使用一个特殊的人类任务节点(如上图所示)。人类任务节点表示需要由人类参与者执行的原子任务。

尽管Drools流有一个特殊的人类节点,用于在一个流程内部包括人类任务,但是人类任务被简单地视为需要被调用的其他类型的外部服务,

所以能作为一个特 殊类型的工作项(work item)被简单地实现。有关人类任务唯一特殊的事情是我们必须增加对泳道( swimlanes)的支持,

让它轻松地分配任务给用户(见后)。一个人类任务包含了以下属性:

  • Id:  节点的id(在一个节点容器内是唯一的)。
  • Name:  节点的显示名字。
  • TaskName:  人类任务的名字。
  • Priority: 一个整数,指示人类任务的优先权。
  • Comment:  与人类任务关联的注释。
  • ActorId:   负责执行人类任务的参与者id。可以使用逗号作为分隔符指定参与者的一个列表。
  • Skippable:   指定人类任务是否可以被跳过(例如,让参与者决定不执行该人类任务)。
  • Content: 与这个任务关联的数据。
  • Swimlane:  这个人类任务是泳道的一部分。泳道让分配多个人类任务给相同的参与者变得容易。详情请看如何使用泳道。
  • Wait for completion:  如果这个属性为 true,只有人类任务已经被终止,人类任务节点才会继续(即,完成或任务其他的终止状态);否则,在创建该人类任务后,它会立即继续。
  • On-entry and on-exit actions:  进入或退出这个节点时执行的动作。
  • Parameter mapping:  允许复制流程变量的值给该人类任务的参数。当创建人类任务时,值会被复制。
  • Result mapping:  允许复制人类任务的结果参数的值到一个流程变量。当人类任务完成时,值会被复制。注意,只有当"Wait for completion"设置为true时,才可以使用结果映射。人类任务有一个结果变量"Result",它包含了由人类参与者返回的数据。变 量"ActorId" 包含了实际执行该任务的参与者id。
  • Timers:  连接到这个节点的计时器(详情请看'timers'章节).
  • ParentId:  允许指定父任务id,在这个任务是另外一个任务的子任务的情况下(详情请看'sub task'章节)。

在选择人类任务节点时,你可以在属性视图中编辑这些变量,或者通过双击人类任务节点,在那个定制人类任务编辑器被打开后,也可以编辑最重要的属性,如下所示。


Drools 5.1.1_DOC (54) - *工* - 要有光,于是就有了光
Drools 5.1.1_DOC (54) - *工* - 要有光,于是就有了光

注 意,你可以直接指定不同参数的值(actorId, priority, content, 等等)(在这种情况下,此流程的每次执行,它们都将是相同的),

或者根据在该流程实例内部的数据,使它们成为特殊上下文(context- specific)。例如,String类型的参数可以使用 #{expression}

嵌入一个值在字符串中。在创建工作项时会检索该值,并且 #{...} 会被变量的 toString()值替换。表达式可以是简单的变量名字(在这种情况下,它会被解析为该变量的值)

,但是也可能是更高级的MVEL表达式,如# {person.name.firstname}。例如,在发送一个邮件时,

邮件的主体可以包含诸如此类 "Dear #{customer.name}, ..."。对于其他类型的变量,使用参数映射,也可以映射变量的值为一个参数。

10.1.1.  泳道(Swimlanes)

人 类任务节点可以与泳道组合使用,分配多个人类任务给类似的参与者。在同一个泳道中的任务会被指派给相同的参与者。

只要在泳道中创建第一个任务时,给那个任 务指定 一个actorId,那么这个actorId将也会被分配给泳道。在那个泳道中创建的所有其他任务也将会使用这个 actorId,即使该任务已经被指定了一个actorId。

当作为一个泳道的 一部分的一个人类任务被完成时,泳道的actorId被设置为那个执行的人类任务的 actorId 。例如,

这允许分配一个人类任务给一组用户,以及分配泳道将来的任务给第一个任务声明的用户。如果在某个时刻一个任务被重新分配给另外的用户,这也会自动 改变任务的分配。

要添加一个人类任务到一个泳道,简单地指定泳道的名字作为人类任务节点的"Swimlane"参数的值。要做它,通过点击该流程的背景,打开流程属性, 并点击 "Swimlanes"属性。在那儿你可以添加新的泳道。

 

10.2.   人类任务管理组件

就 被关注的 Drools流引擎而言,人类任务是相似于任何其他需要被调用的外部服务,并且作为普通工作项的一个扩展被实现。

因此,流程本身只包含需要被执行的人类任 务的一个抽象描述,并且由一个工作项处理程序负责绑定这个抽象任务到一个特殊的实现。

使用我们的可插式工作项处理程序的方法(详情请看特殊域流程章节), 用户可以插入任何后端( back-end)实现。

 然而,我们提供了这样一个 基于WS-HumanTask规范的人类任务管理组件的实现。如果你不要求集成你自己的一个特殊人类任务组件,

你可以使用这个服务。它管理任务的生命周期 (创建,声明,完成,等等),并且持久化存储任务的状态。它也支持诸如国际化、 日历集成、不同类型的作业(assignments)、代理、期限等等功能。

因 为我们不希望在一个标准可用时实现一个定制解决方案,所以我们选择根据WS-HumanTask (WS-HT)规则实现我们的服务。

这个规范详细定义了任务的模式、生命周期和许多其他上面提及的功能。它是相当全面的,能够在这里 [http://download.boulder.ibm.com/ibmdl/pub/software/dw/specs/ws- bpel4people/WS-HumanTask_v1.pdf]找到。

10.2.1.  任务的生命周期

从 流程的角度看,在一个流程实现执行期间,只要触发一个人类任务节点,则一个人类任务被创建。当那个人类任务已经被完成或终止

(当然,除非你设置 了"Wait for completion"属性为 true,指定了流程不需要等待人类任务的完成)时,流程才会从那点继续。然而,

人类任务自身通常有一个独立的生命周期。现在我们快速介绍这个生命周期, 如下图所示。详情请查看WS-HumanTask规范。
Drools 5.1.1_DOC (54) - *工* - 要有光,于是就有了光

当 创建一个任务时,它从 "Created"阶段开始。它通常自动移交到 "Ready"状态,在这个时刻,任务将显示在允许执行任务的所有参与者的任务列表中。

在这里,等待这些参与者之一主张任务,指明他或她会执行任务。一旦 一个用户主张了一个任务,状态被改到"Reserved"阶段。注意,

只有一个潜在参与者的任务会自动被分配给那个任务创建时的参与者。在主张任务后,那个用户在稍后某个时刻决定启动执行任务,在这种情况下,

任务状态改 为"InProgress"。最后,一旦该任务被执行,用户必须完成任务(并且可以指定与该任务相关的结果数据),在这种情况下,

状态被改 为"Completed"。如果该任务不能被完成,用户也能够使用一个故障响应(可以利用关联的故障数据)指出它,在这种情况下,状态被改 为"Failed"。

上面解释的生命周期是正常的生命周期。该服务也允许很多其他的生命周期方法,如:

  • 委托或转发一个任务,在这种情况下,它被分配给另外一个参与者。
  • 撤销一个任务,所以它不再被一个特定参与者主张,而且重新显示在所有潜在参与者的任务列表中。
  • 暂时挂起和恢复一个任务。
  • 停止正在进行的一个任务。
  • 跳过一个任务(如果该任务被标记为可跳过),在这种情况下,该任务将不被执行。

10.2.2.  连接任务组件到Drools流引擎

任 务管理组件就象任何其他外部服务一样,需要通过注册一个工作项处理程序——负责转换抽象的工作项(在这种情况下是一个人类任务)

为一个特定的调用——与 Drools流引擎集成。我们实现了这样一个工作项处理程序 (org.drools.process.workitem.wsht.WSHumanTaskHandler,在drools-process- task模块中),

所以你可以轻松地连接这个工作项,象这样:

  StatefulKnowledgeSession session = ...;

    session.getWorkItemManager().registerWorkItemHandler("Human Task", new WSHumanTaskHandler());

默认时,这个处理程序将在本地机器的9123端口上连接到人类任务管理组件,然而你可以通过在WSHumanTaskHandler上调用setConnection(ipAddress, port) 方法轻松地改变它。

现在,WSHumanTaskHandler使用Mina (http://mina.apache.org/) 测试在一个C/S体系结构中的行为。Mina在客户端和服务器之间使用消息,

使客户端与服务器之间进行通信。这就是为什么WSHumanTaskHandler有一个MinaTaskClient——创建不同消息给用户不同的由服务器执行的动作。

在该客户端中(在这个实现中的MinaTaskClient),我们应该了解以下与人类任务交互的方法的实现:

public void start( long taskId, String userId, TaskOperationResponseHandler responseHandler )

public void stop( long taskId, String userId, TaskOperationResponseHandler responseHandler ) 

public void release( long taskId, String userId, TaskOperationResponseHandler responseHandler ) 

public void suspend( long taskId, String userId, TaskOperationResponseHandler responseHandler ) 

public void resume( long taskId, String userId, TaskOperationResponseHandler responseHandler ) 

public void skip( long taskId, String userId, TaskOperationResponseHandler responseHandler ) 

public void delegate( long taskId, String userId, String targetUserId,   TaskOperationResponseHandler responseHandler ) 

public void complete( long taskId, String userId, ContentData outputData,  TaskOperationResponseHandler responseHandler )  ...

使用这些方法,我们将实现任何类型的GUI——终端用户将用它来做他们下达的任务。如果你查看了这些方法的签名,你会注意到几乎所有这些方法都获取了以下参数:

    • taskId:  我们操作的任务id。你可以从UI(用户界面)的用户任务列表中拾取它。
    • userId:  执行动作的用户id。可以在应用程序中签署的用户id。
    • responseHandler:  这是一个处理程序,负责捕获响应和得到结果,或者只让我们知道该任务已经完成。

正如你所想的一样,所有方法都将创建一条发送到服务器的消息,并且该服务器将执行实现正确动作的逻辑。 一个创建的消息之一可能是这样的:

public void complete(long taskId,

                       String userId,

                       ContentData outputData,

                       TaskOperationResponseHandler responseHandler) {

    List<Object> args = new ArrayList<Object>( 5 );

    args.add( Operation.Complete );

    args.add( taskId );

    args.add( userId );

    args.add( null );

    args.add( outputData );

    Command cmd = new Command( counter.getAndIncrement(),

                               CommandName.OperationRequest,

                               args );

      handler.addResponseHandler( cmd.getId(),

                                responseHandler );

    session.write( cmd );

 }

在这儿我们可以看到,创建了一个命令,并把方法的参数——带有我们想执行的操作类型——插入到命令的内部,然后这个命令利用 session.write( cmd ) 方法发送到服务器。

如 果我们看服务器实现,当命令被收到时,我们发现被执行的逻辑是取决于操作的类型(这量是Operation.Complete)。

如果我们查看在 messageReceived方法中的类 TaskServerHandler,在任务被创建和用户没有与它们交互时,使用负责得到、持久化和管理人类任务信息 taskServiceSession执行taskOperation。

10.2.3.  启动任务管理组件

任务管理组件是一个与流程引擎通信的完全独立的服务。因此我们建议最好以独立服务启动它。要启动任务服务器,你可以使用下面的代码片断:

  EntityManagerFactory emf = Persistence.createEntityManagerFactory("org.drools.task");

  taskService = new TaskService(emf);

  MinaTaskServer server = new MinaTaskServer( taskService );

  Thread thread = new Thread( server );

  thread.start();

任 务管理组件使用Java Persistence API (JPA) ,以一个持久化的方式存储所有任务信息。要配置该持久化,你需要相应地修改 persistence.xml配置文件。

如何做它我们参考了JPA文档。 下面的例子的片断显示了如何使用任务管理组件与hibernate 和内存数据库H2 :

  <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  <persistence
      version="1.0"
      xsi:schemaLocation=
        "http://java.sun.com/xml/ns/persistence
         http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd
         http://java.sun.com/xml/ns/persistence/orm
         http://java.sun.com/xml/ns/persistence/orm_1_0.xsd"
      xmlns:orm="http://java.sun.com/xml/ns/persistence/orm"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns="http://java.sun.com/xml/ns/persistence">
  <persistence-unit name="org.drools.task">
      <provider>org.hibernate.ejb.HibernatePersistence</provider>
      <class>org.drools.task.Attachment</class>
      <class>org.drools.task.Content</class>
      <class>org.drools.task.BooleanExpression</class>
      <class>org.drools.task.Comment</class>
      <class>org.drools.task.Deadline</class>
      <class>org.drools.task.Comment</class>
      <class>org.drools.task.Deadline</class>
      <class>org.drools.task.Delegation</class>
      <class>org.drools.task.Escalation</class>
      <class>org.drools.task.Group</class>
      <class>org.drools.task.I18NText</class>
      <class>org.drools.task.Notification</class>
      <class>org.drools.task.EmailNotification</class>
      <class>org.drools.task.EmailNotificationHeader</class>
      <class>org.drools.task.PeopleAssignments</class>
      <class>org.drools.task.Reassignment</class>
      <class>org.drools.task.Status</class>
      <class>org.drools.task.Task</class>
      <class>org.drools.task.TaskData</class>
      <class>org.drools.task.SubTasksStrategy</class>
      <class>org.drools.task.OnParentAbortAllSubTasksEndStrategy</class>
      <class>org.drools.task.OnAllSubTasksEndParentEndStrategy</class>
      <class>org.drools.task.User</class>
    <properties>
        <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
        <property name="hibernate.connection.driver_class" value="org.h2.Driver"/>
        <property name="hibernate.connection.url" value="jdbc:h2:mem:mydb" />
        <property name="hibernate.connection.username" value="sa"/>
        <property name="hibernate.connection.password" value="sasa"/>
        <property name="hibernate.connection.autocommit" value="false" />
        <property name="hibernate.max_fetch_depth" value="3"/>
        <property name="hibernate.hbm2ddl.auto" value="create" />
        <property name="hibernate.show_sql" value="true" />
      </properties>
    </persistence-unit>
  </persistence>
   第一次你启动任务管理组件,你需要确保所有必要的用户和组被添加到了该数据库。在试图分配一个任务给用户和组之前,我们的实现要求所有用户和组被预定义。所以,
你需要确保使用taskSession.addUser(user)和taskSession.addGroup(group)方法添加必要的用户和组到该数据库。注意,你至少需要一个"Administrator" 用户,因为所有任务被自动分配给这个作为管理角色的用户。
   drools-process-task模块,在src/test/java源文件夹中包含了一个org.drools.task.RunTaskService类,可以被用来启动一个任务服务器。 
它自动添加在LoadUsers.mvel和LoadGroups.mvel配置文件中定义的用户和组。
10.2.4.  与任务管理组件交互
   任务管理组件通过一个Java API暴露了管理任务的生命周期的各种方法。这允许客户端集成(在一个低层次)任务管理组件。注意,终端用户可能不应该直接与这种低层次交互,
而是使用任务列表的客户端之一。这些客户端使用这些API与任务管理组件交互。
   用下面的图片描述这种交互:

Drools 5.1.1_DOC (54) - *工* - 要有光,于是就有了光

正如我们在该图片中所见一样,我们有MinaTaskClient和MinaTaskServer。它们相互通信,发送消息查询和操作人类任务。一步一步的交互将是这样的: 

  • 某些客户端需要完成某些任务。所以他/她需要创建一个MinaTaskClient 的实例,并且连接它到MinaTaskServer,利用一个会话相互交谈。这是图片中的第一步。  
  • 然 后,客户端带着相应的参数调用在MinaTaskClient中有complete() 方法。这将产生一个.新的消息(或命令),并把它插入到在客户端连接服务器时打开的会话中 。
  • 这个消息必须指定一个类型,以便于服务器识别和知道在收到信息时做什么的。这是图片中的第二步。  
  • 此 时,TaskServerHandler注意到在该会话中有一条新消息,所以会发生一个有关消息的类型是什么的分析。在这种情况下,是 Operation.Complete的类型,
  • 因为客户端正成功地完成某些任务。所以我们需要完成用户想完成的任务。这是通过 TaskServiceSession实现,它将引发一个特殊类型的事件,由TaskEventListener的一个特殊子类来处理它。 这是图片中的第三步。
  • 在收到事件时,TaskEventListener会知道如修改该任务的状态。 这是通过EntityManager检索和修改来自该数据库的一个特定任务的状态。在这种情况下,
  • 因为我们正完成一个任务, 所以状态将被更新为Completed。 这是图片中的第四步。
  • 现在,当改变被做了时,我们需要通知客户端该任务被成功结束,这通过创建一个响应消息来实现,TaskClientHandler 会收到该消息并告之MinaTaskClient 。这是图片中的第五步。

 

10.3.  人类任务管理界面

10.3.1.  Eclipse集成

Drools IDE包含了一个org.drools.eclipse.task 插件,它允许你测试和调试使用了人类任务的流程。在包含的一个人类任务视图中,

可以连接到一个正在运行的任务管理组件,请求特定用户的相关任务(即,任务 的用户是一个潜在雇主,或者任务已经被用户主张,且正被运行)。

然后,这些任务的生命周期可以被执行,即,主张或释放一个任务,启动或停止一个任务的执 行,完成一个任务,等等。下面显示了一个人类任务视图的截屏。

你可以在Drools Task preference 页面中配置连接到的任务管理组件(选择Window -> Preferences and select Drools Task)。在这里,你可以指定url 和端口(默认= 127.0.0.1:9123)


Drools 5.1.1_DOC (54) - *工* - 要有光,于是就有了光

10.3.2.  基于网页的任务视图。

我们的目标是增加一个基于网页的视图,终端用户可以使用它来管理他们的 Drools 5.1任务。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值