Jbpm的核心业务是持久化流程执行的能力,对于管理任务和个人任务清单来说这是一个非常重要的特性,Jbpm允许指定一段软件描述所有人的任务中处于等待状态的流程。
11.1 任务
任务是流程定义的一部分,它们定义了在流程执行期间任务实例怎样被创建和分配。
任务可以在task-node和 process-definition中定义,通常使用的方式是在一个task-node里定义一个或多个任务,这种情况下,task-node代表一个 将由用户完成的任务,并且流程执行将一直等待直到参与者完成这个任务,当参与者完成任务时,流程执行将继续。当在一个task-node中指定多个任务 时,默认的行为是等待所有任务完成。
任务也可以被指定在process- definition。指定在process-definition的任务可以通过名称查找到并且在task-node里引用或者在内部动作中使用。事实 上,所有给定名称的任务(包括在task-node中定义的任务)都可以在流程定义(process-definition)中通过名字查找到。
任务名称在整个流程定义中必须是唯一的。任务可以被指定一个优先级,这个优先级在任务的实例创建时将被作为每个任务实例的初始优先级,任务实例的初始优先级可以在以后被修改。
11.2 任务实例
任务实例可以被分配一个actorId(java.lang.String)。所有的任务实例被存储在数据库中的一张表里面(JBPM_TASKINSTANCE),通过查询这张表可以得到给定actorId的所有任务实例,进而获取特定用户的任务清单。
Jbpm的任务清单机制可以组合Jbpm任务和其他任务,甚至那些任务与流程执行毫不相干,这样,Jbpm开发者可以很方便的组合Jbpm流程任务和其他应用的任务到一个集中的任务清单仓库中。
11.2.1 任务实例生命周期
任务实例的生命周期是很直观的:创建后,任务实例可以被随意地开始,然后任务实例可以被结束,这意味着任务实例被标记为完成。
注意,为了灵活性,分配不是生命周期的一部分,所以任务实例可以被分配也可以不被分配,任务实例的分配不会影响任务实例的生命周期。
任务实例典型的创建是通过流程执行进入一个 task-node(使用方法TaskMgmtInstance.createTaskInstance(…)),然后,用户接口组件会使用 TaskMgmtSession.findTaskInstancesByActorId(…)查询数据库获取任务列表,然后,在收集了用户输入后,UI 组件调用TaskInstance.assign(String)、TaskInstance.start()或者TaskInstance.end (…)。
任务实例依靠日期属性维护它的状态:创建、开始和结束。这些属性可以通过任务实例上它们各自的getter方法访问。
通常,完成的任务实例用一个结束日期做了标记,所以它们不能被以后的任务列表查询获取,但是它们仍然存在于JBPM_TASKINSTANCE表中。
11.2.2 任务实例和图执行
任务实例是参与者任务清单 (tasklist)中的项目,任务实例可以作为信号,当一个信号任务实例完成时,可以发送一个信号到它的令牌继续流程执行。任务实例可以被阻塞,这意味 着在任务实例完成之前相关令牌(=执行路径)不允许离开任务节点。默认情况下,任务实例是信号非阻塞的。
如果多于一个任务实例与一个任务节点关联,流程开发者可以指定任务实例的完成怎样影响流程的继续。下面是可以给任务节点的signal属性设置的值:
l last:这是默认值。当最后一个任务实例完成时继续执行;当在节点入口处没有任务创建时,继续执行。
l last-wait:当最后一个任务实例完成时继续执行;当在节点入口处没有任务创建时,执行在任务节点等待,直到任务被创建。
l first:当第一个任务实例完成时继续执行;当在节点入口处没有任务创建时,继续执行。
l first-wait:当第一个任务实例完成时继续执行;当在节点入口处没有任务创建时,执行在任务节点等待,直到任务被创建。
l unsynchronized:总是继续执行,不管任务是否创建和完成。
l never:执行不再继续,不管任务是否创建和完成。
任务实例可以基于运行时的计算创建,如果那样的话,需要添加一个ActionHandler到任务节点的node-enter事件,并且设置属性create-tasks=“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");
// 现在, 相同任务的两个任务实例被创建
tmi.createTaskInstance(changeNappy, token);
tmi.createTaskInstance(changeNappy, token);
}
}
如示例所展示,任务可以在指定的任务节点中创建,它们也可以被指定到process-definition,并且从TaskMgmtDefinition获取。TaskMgmtDefinition用任务管理信息扩展了ProcessDefinition。
标识任务示例完成的API是TaskInstance.end(),你可以在end方法中指定一个转换,如果这个任务的完成会触发继续执行,则会通过指定的转换离开任务节点。
11.3 分配
流程定义包含任务节点,任务节点(task-node)包含一个或多个任务,任务作为流程定义的一部分是静态描述。在运行时,任务导致任务实例的创建,一个任务实例对应某人任务列表中的一个入口。
在Jbpm中,可以结合使用推模式和拉模式(见下文)的任务分配。流程可以计算任务的责任人,并把它推到他/她的任务清单里;或者,任务可以被分配到参与者池,这种情况下,池中的每个参与者都可以拉出任务并把它放入参与者的个人任务清单。
11.3.1 分配接口
通过接口AssignmentHandler进行任务实例分配:
public interface AssignmentHandler extends Serializable {
void assign( Assignable assignable, ExecutionContext executionContext );
}
当任务实例被创建时分配处理的实现被调用,在 那时,任务实例可以被分配到一个或多个参与者。AssignmentHandler实现将调用分配方法(setActorId或 setPooledActors)分配任务,可以分配一个任务实例或者一个泳道实例swimlaneInstance(=流程角色)。
public interface Assignable {
public void setActorId(String actorId);
public void setPooledActors(String[] pooledActors);
}
任务实例和泳道实例都可以被分配到一个用户或 者共享参与者。分配任务实例到一个用户,调用Assignable.setActorId(String actorId);分配任务实例到候选的共享参与者,调用Assignable.setPooledActors(String[] actorIds)。
流程定义中的每个任务都可以与一个分配处理实现相关联,用来完成运行时的任务分配。
当流程中的多个任务将要分配给相同的人或者参与者组时,考虑使用泳道。
考虑到AssignmentHandler的重用,每个AssignmentHandler的使用可以在processdefinition.xml中配置。请参考“16.2 委托”了解怎样添加分配处理配置的更多信息。
11.3.2 分配数据模型
下面是管理分配任务实例和泳道实例到参与者的数据模型,每个任务实例拥有一个actorId或一组被共享的参与者。
图 11.1 分配模型类图
actorId对任务负责,而共享的参与者表示候选者集合,如果它们获取任务,则可以负责任务。actorId和共享参与者具体使用哪个是可选的,两者也可以结合使用。
11.3.3 推模式
任务实例的actorId表明对给定任务负责,而任务实例的共享参与者是任务的候选参与者。典型情况下,任务实例的actorId指向一个用户,共享参与者可以指向多个用户和/或用户组。
用户的任务清单是所有以用户作为actorId的任务实例,这个清单可以使用TaskMgmtSession.findTaskInstances(String actorId)获得。
11.3.4 拉模式
另一方面,共享的任务(译者注:共享任务即不 仅是由一个用户负责的)是提供给共享参与者中所引用的用户的。获取共享任务一般需要两步操作:1)从身份组件中获取给定用户的所有组2)为结合了用户的 actorId和指向用户组的actorId获取所有共享任务清单(译者注:这段话不太好理解,解释如下――任务指向一个actorId,在Jbpm中并 没有强制限制该actorId必须为单个用户或者用户组,所以我们在实际应用中也可以把actorId作为一个用户组。假如有一个用户为user1,他属 于用户组group1,在流程中有些任务分配到了user1,而其它又有些任务分配到了group1,如果我们要取user1的所有共享任务,则即需要获 取分配到user1的共享任务,也需要获取分配到group1的共享任务)。可以使用方法 TaskMgmtSesion.findPooledTaskInstances(String actorId)或TaskMgmtSession.findPooledTaskInstances(List actorIds)获取提供给指定用户的共享任务清单,这些方法会返回actorId为空(null)以及共享参与者中某个与给定的actorIds中的 某个相匹配的任务实例。
为了防止多个用户在同一个共享任务上工作,使用用户的actorId修改任务实例的actorId就可以了。这样,任务实例将不会出现在共享任务清单中,而只会存在于用户个人的任务清单里。设置任务实例的actorId为空(null),则会把任务实例放回共享任务里。
11.4 任务实例变量
任务实例可以拥有它自己的变量,并且也可以“看到”流程变量。任务实例通常是在执行路径(=令牌)中创建,与令牌之间的父子关系相似,这会在令牌和任务实例之间创建一个父子关系。正常的范围规则适用于相关令牌的任务实例变量和流程变量之间,有关范围的更多信息可以在“10.4 变量范围”找到。
这意味着任务实例可以“看到”它自己的变量,另外还有它所关联令牌的所有变量。
控制器可以用来在任务实例范围和流程范围的变量间创建、组装和提交变量。
11.5 任务控制器
在任务实例创建时,任务控制器可以组装任务实例变量,并且当任务实例完成时,任务控制器可以提交任务实例的数据到流程变量。
注意,任务控制器不是强制使用的,即使不使用任务控制器,任务实例也能够“看到”与它的令牌相关的流程变量,当你想要做如下事情时使用任务控制器:
l 在任务实例中创建变量的拷贝,这样任务变量的中间更新不会影响到流程变量,而是直到处理完成后拷贝才被提交回流程变量。
l 任务实例变量与流程变量不是一一对应的。例如,假设流程有变量“sales in januari”“sales in februari”和“sales in march”,而任务实例所使用表单可能需要显示的是三个月的平均销售量。
任务用来收集用户输入,但是目前有很多可以向用户展示任务的用户接口,例如web应用、swing应用、及时消息、电子邮件表单…因此任务控制器在流程变量(=流程上下文)和用户接口应用之间起到了桥的作用,任务控制器为用户接口应用提供流程变量的视图。
任务控制器在流程变量到任务变量之间进行转换(如果需要)。当任务实例被创建时,任务实例负责从流程变量提取信息,并且创建任务变量,任务变量作为用户接口表单是输入,并且用户输入可以存储在任务变量里;当用户结束任务时,任务控制器负责基于任务实例数据更新流程变量。
图 11.2 任务控制器
简单的情形是,在流程变量和表单参数之间是一对一的映射,任务控制器在task元素中指定,这种情况下,默认的Jbpm任务管理器可以被使用,它包含一个variable元素列表,variable元素表示流程变量怎样被拷贝到任务变量。
下面的例子展示了怎样基于流程变量的拷贝创建任务实例变量:
<task name="clean ceiling">
<controller>
<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>
name属性指向流程变量的名称,mapped-name属性是任意的,用来指向任务实例变量的名称。如果忽略mapped-name属性,则mapped-name默认与name属性相同。注意,mapped-name也被用来在web应用中作为任务实例表单的域标签。
access属性指定了如果在任务实例创建时变量被拷贝,是否需要在任务结束时把它写回流程变量。这个信息可以被用户接口所使用,进行适当的表单控制。access属性是可选的,默认值是“read,write”。
任务节点(task-node)可以拥有多个任务,而开始状态(start-state)只能有一个任务。
如果在流程变量和表单参数之间简单的一对一映射太过约束,你也可以编写你自己的TaskControllerHandler实现,下面是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">
-- here goes your task controller handler configuration --
</controller>
</task>
11.6 泳道(swimlane)
泳道是流程角色,它是定义流程中的多个任务由相同参与者完成的一种机制。在第一个任务实例为指定泳道创建后,参与者将被流程记住,以被在同一泳道中的后续任务所使用。泳道有一个分配,因此所有引用泳道的任务不需要再指定分配。
当给定泳道的第一个任务被创建时,泳道的 AssignmentHandler被调用,Assignable被传递到AssignmentHandler,将会成为泳道实例 (SwimlaneInstance)。需要知道的是,给定泳道中的所有任务实例的分配都被传播到泳道实例,这个行为是被作为默认实现的,因为获取任务进 行处理的人在履行某个流程角色(译者注:也就是说在某个泳道内),因此所有后续对泳道的任务实例的分配会自动转到用户。
泳道是从UML活动图中借来的术语。
11.7 开始任务中的泳道
泳道可以与开始任务关联,用以捕获流程的发起者。
任务可以在start-state中指定,该 任务与泳道关联,当这个任务的一个新的任务实例被创建时,当前已经过鉴定的参与者可以使用 Authentication.getAuthenticatedActorId()(参考17.2 鉴定)获取(译者注:这时创建开始任务时,自动进行的),并且该参与者存储在开始任务的泳道里。
例如:
<process-definition>
<swimlane name='initiator' />
<start-state>
<task swimlane='initiator' />
<transition to='...' />
</start-state>
...
</process-definition>
象其它任何任务一样,也可以向开始任务添加变量用来定义与任务关联的表单。请参考“11.5 任务控制器”。
11.8 任务事件
任务可以拥有所关联的动作。任务有四个标准的事件类型定义:task-create,task-assign,task-start,和task-end。
当一个任务实例被创建时task-create事件被激活。
当一个任务实例被分配时task-assign事件被激活。注意:在这个事件中执行的动作里,你可以用executionContext.getTaskInstance().getPreviousActorId()访问前一个参与者。
当TaskInstance.start()被调用时task-start事件被激活。这可以被用来标识用户在这个任务实例上已经开始工作。是否开始一个任务是可选的。
当TaskInstance.end()被调用时task-end事件被激活。这标志了任务的完成,如果任务与流程执行相关,这个调用会触发流程继续执行。
因为任务可以拥有事件以及相关联的动作,所以异常处理也可以在任务上被指定。有关异常处理的更多信息,请参考“9.7 异常处理”。
11.9 任务定时器
在节点上,定时器可以在任务上被指定。请参考“12.1 定时器”。
对于任务的定时器需要指明的是:任务定时器的 cancel-event可以被定制。默认情况下,当任务被结束时(=完成)任务上的定时器将被取消,在是通过在定时器上使用cancel-event属 性,流程开发者可以定制诸如task-assign或task-start。cancel-event支持多个事件,通过在属性中指定一个用逗号分割的列 表,可以组合cancel-event的类型。
11.10 定制任务实例
任务实例可以被定制。最简单的方式就是创建 TaskInstance的子类,然后创建一个org.jbpm.taskmgmt.TaskInstanceFactory的实现,并在 jbpm.cfg.xml中设置配置属性jbpm.task.instance.factory为该实现的完整类名。如果你使用一个 TaskInstance的子类,还需要为该子类创建一个hibernate映射文件(使用hibernate的extends=” org.jbpm.taskmgmt.exe.TaskInstance”),然后在hibernate.cfg.xml中添加该映射文件到映射文件列 表。
11.11 身份组件
用户、组和权限管理一般都被称为身份管理。Jbpm包含了一个可选的身份组件,它可以很容易的被企业自己的身份数据存储所替换。
Jbpm的身份管理组件包含了组织知识模型。 任务分配典型的需要由组织知识来完成,因此,这意味着组织知识模型描述了用户、组、系统以及它们之间的关系。作为可选的,权限和角色也可以被包含进组织模 型。数个学术研究尝试的失败表明,没有一个通用的组织模型可以适用于所有组织。
Jbpm的作法是定义一个参与者作为流程的实际参与者,参与者通过它的ID进行标识,称为actorId,Jbpm只知道actorId并且为了灵活性用java.lang.String表示,因此任何组织模型知识及其数据结构都在Jbpm核心引擎之外。
作为对Jbpm的扩展,我们将提供(以后)管 理简单的“用户-角色”模型的组件,用户和角色之间的多对多关系与J2EE和servlet规范中定义的模型是一致的,这可以作为一个新的开发起点,感兴 趣的话可以查看jboss jbpm jira中的问题跟踪来获取更多详细资料。
注意,实际被用在servlet、ejb和portlet规范中的“用户-角色”模型不足以满足任务的分配处理,该模型在用户和角色之间是一个多对多的关系,不包括流程中用户有关的组和组织结构信息。
11.11.1 身份模型
图 11.3身份模型类图
黄色的类是下面将要讨论的有关表达式分配处理的相关类。
User表示用户或服务。Group是任何类 型的用户组,Group可以被嵌套,用来建模一个团队、一个业务单元、以及整个公司的关系,组有类型,用来在不同等级的组之间进行区分,例如 haircolor组。Membership表示用户和组之间的多对多关系,membership可以被用来表示公司中的一个职位,membership 的名字可被用来表示用户在组中的角色。
11.11.2 分配表达式
随同身份组件提供了一种实现,即在进行任务分配期间通过表达式计算参与者。这里有一个在流程定义中使用分配表达式的例子:
<process-definition>
...
<task-node name='a'>
<task name='laundry'>
<assignment expression='previous --> group(hierarchy) --> member(boss)' />
</task>
<transition to='b' />
</task-node>
...
分配表达式的语法如下:
first-term --> next-term --> next-term --> ... --> next-term
where
first-term ::= previous |
swimlane(swimlane-name) |
variable(variable-name) |
user(user-name) |
group(group-name)
and
next-term ::= group(group-type) |
member(role-name)
11.11.2.1第一术语first-term
表达式以从左到右的顺序被分解,first-term指定了身份模型中的一个用户或组,后续的术语的计算基于这个中间的用户或组。
privious的意思是任务被分配到当前已被鉴定的参与者,这意味着参与者完成了流程中的前一个步骤。
swimlane(swimlane-name)的意思是用户或组从指定的泳道实例中取得。
variable(variable-name)的意思是用户或组从指定变量实例中取得。变量实例可以包含一个java.lang.String,这种情况下,用户或组从身份组件获取;或者变量实例包含一个用户或组对象。
user(user-name)的意思是给定的用户从身份组件中取得。
group(group-name)的意思是给定的组从身份组件中取得。
11.11.2.2第二术语next-term
group(group-type)获取用户的组,这意味着前一个术语必须结果为一个用户,这个术语会使用给定的group-type在所有的membership中为用户搜索组。
member(role-name)从组里得到用户所履行的角色,前一个术语必须结果为一个组,这个术语在组中为用户搜索与给顶的role-name相匹配的membership。
11.11.3 移除身份组件
当你想要为组织信息使用自己的数据源时,例如你们公司的用户数据库或者ldap系统,你可以拔除身份组件,你唯一要做的就是在hibernate.cfg.xml中删除下面的行…
<mapping resource="org/jbpm/identity/User.hbm.xml"/>
<mapping resource="org/jbpm/identity/Group.hbm.xml"/>
<mapping resource="org/jbpm/identity/Membership.hbm.xml"/>
ExpressionAssignmentHandler 依赖于身份组件,因此你将不能使用它。万一你想重新使用ExpressionAssignmentHandler并且绑定它到你自己的用户数据存储,你可 以从ExpressionAssignmentHandler继承并且重写getExpressiontSession方法。
protected ExpressionSession getExpressionSession(AssignmentContext assignmentContext);
分享到:
相关推荐
Java在线任务管理系统源码 Java在线任务管理系统源码 Java在线任务管理系统源码 Java在线任务管理系统源码 Java在线任务管理系统源码 Java在线任务管理系统源码 Java在线任务管理系统源码 Java在线...
《任务管理系统原型——Java实现详解》 在编程领域,任务管理系统的开发是常见的实践项目,尤其对于初学者来说,它提供了理解基础概念和应用技术的良好平台。本项目以Java为编程语言,构建了一个简单易懂的任务管理...
《任务管理系统操作手册》 任务管理系统是企业日常工作中不可或缺的一部分,它主要负责组织、跟踪和管理各类工作任务,确保工作的高效执行。本手册将详细介绍任务管理系统的各项功能,以帮助用户更好地理解和使用...
"Java 读取任务管理器信息" 本文主要讨论了如何在 Java 中读取任务管理器信息,包括物理内存、剩余物理内存、已使用物理内存、内存使用率、cpu 占有率等信息。 java 中读取任务管理器信息的必要性: 在实际开发中...
在嵌入式系统开发中,任务管理是操作系统(OS)的核心组成部分,特别是在基于Arm架构的处理器上。本文将深入探讨Arm任务管理的概念、原理以及基于特定开发板的源码实现。 1. Arm 任务管理基础 Arm处理器以其高效能...
《Windows任务管理器增强版——全面解析与应用》 Windows任务管理器是我们日常操作电脑时不可或缺的工具,它能提供系统性能监控、进程管理、启动项管理等多种功能。然而,微软自带的任务管理器在某些高级功能上可能...
在本项目中,"基于C++的任务管理器代码.zip" 提供了一个用C++语言编写的任务管理器的实现。任务管理器是一个用于监控、控制和管理计算机系统中运行任务的软件工具。C++是一种通用的、面向对象的编程语言,具有高效、...
网吧、学校等公共场合的计算机,我们不希望用户使用任务管理器乱杀进程,但是我们又不能不让用户使用任务管理器,这个程序就是专为解决这个问题而编写的。 程序比较简单,所以没有提供卸载程序,如果安装后不想用了...
在IT领域,任务管理器是操作系统中的一个核心组件,它允许用户查看并控制正在运行的进程、应用程序和服务,以及管理系统的性能和资源。在Windows操作系统中,任务管理器是最常用的工具之一,它提供了丰富的信息,...
资源名:公司工作任务管理系统asp源码+access数据库 资源类型:程序源代码 源码说明: 1、添加管理企业员工; 2、针对某个员工下达工作任务,支持上传各种常见文件。 3、任务下达后,发送提醒至员工邮箱。 4、员工...
**基于MFC实现的Windows任务管理器** 在Windows操作系统中,任务管理器是一个不可或缺的工具,它提供了查看和控制正在运行的应用程序、进程、服务、性能监控以及启动和关闭计算机的功能。本文将深入探讨如何利用...
《全面解析:如何使用任务管理器查看程序位置》 任务管理器是Windows操作系统中的一个核心组件,它为我们提供了监控和管理计算机系统资源的能力,包括进程、性能、启动项、用户和详细信息等。在日常使用电脑的过程...
在Windows操作系统中,任务管理器是一个非常重要的工具,它允许用户查看系统性能、管理正在运行的应用程序、结束不响应的任务、启动或关闭服务等。有时为了保护系统安全或避免未经授权的用户修改系统设置,可能会...
在任务管理中,OA功能可以帮助协调团队成员的工作,实现工作任务的流转和审批,提高协同办公的效率。 3. **核心功能** - **任务创建与分配**:用户可以创建新的任务,并将其分配给团队成员。系统应提供便捷的创建...
项目概述:基于Python的Django框架开发的任务管理平台开源项目,融合了前端与后端的多种技术。该项目包含总共80个文件,其中主要编码语言为Python,同时涵盖了CSS、JavaScript和HTML等。文件类型分布如下:Python...
【C# 管理系统源码:任务管理】是一个基于C#编程语言开发的完整应用程序,用于管理和调度各种任务。这个系统的核心功能是提供一个用户友好的界面,让用户能够创建、修改、删除以及监控任务的执行状态。下面将详细...
在Windows操作系统中,任务管理器是用于监控和控制进程、应用程序及系统服务的重要工具,有时为了系统安全或特定需求,我们需要防止用户通过任务管理器关闭或查看某些程序。 首先,我们要理解如何在易语言中操作...
在C#编程中,有时我们需要确保我们的应用程序能够在不受外部因素如任务管理器干扰的情况下持续运行。标题提到的“防止C#应用程序被任务管理器结束”实际上涉及到的是进程保护技术,尤其是针对用户尝试通过任务管理器...
综合任务管理系统是一种高效的工作流程自动化工具,旨在整合各种任务,优化资源分配,提高工作效率,并确保项目的顺利进行。这种系统通常包含一系列功能模块,如任务创建、分配、跟踪、报告和协作,以支持组织内的...
基于Python Django框架搭建的任务管理Saas平台源码 基于Python Django框架搭建的任务管理Saas平台源码 基于Python Django框架搭建的任务管理Saas平台源码 基于Python Django框架搭建的任务管理Saas平台源码 ...