??xml version="1.0" encoding="utf-8" standalone="yes"?> 9.1. Tasks d Tasks can be defined in task-nodes and in the process-definition. The most common way is to define one or more tasks in a task-node. In that case the task-node represents a task to be done by the user and the process execution should wait until the actor completes the task. When the actor completes the task, process execution should continue. When more tasks are specified in a task-node, the default behaviour is to wait for all the tasks to complete. Tasks can also be specified on the process-definition. Tasks specified on the process definition can be looked up by name and referenced from within task-nodes or used from inside actions. In fact, all tasks (also in task-nodes) that are given a name can be looked up by name in the process-definition. Task names must be unique in the whole process definition. Tasks can be given a priority. This priority will be used as the initial priority for each task instance that is created for this task. TaskInstances can change this initial priority afterwards. 9.2. Task instances The jBPM task list mechanism can combine jBPM tasks with other tasks, even when those tasks are unrelated to a process execution. That way jBPM developers can easily combine jBPM-process-tasks with tasks of other applications in one centralized task-list-repository. q个jBPMd列表机制可以l合jBPMd和其他Q务,甚至当这些Q务于程执行无关。U方法jBPM开发者可以很Ҏ的在一个集中的d列表仓库中组合jBPM程d和其他应用程序?/P>
9.2.1. Task instance life cycle Note that for flexibility, assignment is not part of the life cycle. So task instances can be assigned or not assigned. Task instance assignment does not have an influence on the task instance life cycle. 注意寚w应性、委z不是生命周期的l成部分。所以Q务实例可以被委派或者不委派。Q务实例委z֜生命周期d实例中没有媄响?/P>
Task instances are typically created by the process execution entering a task-node (with the method TaskMgmtInstance.createTaskInstance(...)). Then, a user interface component will query the database for the tasklists using the TaskMgmtSession.findTaskInstancesByActorId(...). Then, after collecting input from the user, the UI component calls TaskInstance.assign(String), TaskInstance.start() or TaskInstance.end(...). TaskMgmtInstance.createTaskInstance(...) Currently, completed task instances are marked with an end date so that they are not fetched with subsequentQ随后) queries for tasks lists. But they remain in the JBPM_TASKINSTANCE table. JBPM_TASKINSTANCE. 9.2.2. Task instances and graph execution d实例和图形执?BR>Task instances are the items in an actor's tasklist. Task instances can be signalling. A signalling task instance is a task instance that, when completed, can send a signal to its token to continue the process execution. Task instances can be blocking, meaning that the related token (=path of execution) is not allowed to leave the task-node before the task instance is completed. By default task instances are signalling and non-blocking. In caseQ以Ԍ more than one task instance are associated with a task-node, the process developer can specify how completion of the task instances affects continuation of the process. Following is the list of values that can be given to the signal-property of a task-node. last: This is the default. Proceeds execution when the last task instance is completed. When no tasks are created on entrance of this node, execution is continued. public class CreateTasks implements ActionHandler { // now, 2 task instances are created for the same task. The API method for marking task instances as completed is TaskInstance.end(). Optionally, you can specify a transition in the end method. In case the completion of this task instance triggers continuation of the execution, the task-node is left overQgq) the specified transition.
name="className" //子类的全?BR> discriminator-value="discriminator-value" //辨别标识Q一个用于区分每个独立的子类的?BR> proxy="proxyInterface" //指定一个类或接口,在gq加载时作ؓ代理使用
lazy="true|false"
dynamic-update="true|false"
dynamic-insert="true|false"
entity-name="entityName"
node="element-name">
<property ..../>
......
</subclass>
2.每个子类都应该定义它自己的持久化属性和子类?lt;version>?lt;id>属性可以从根父cȝ承下厅R在一늑承树上的每个子类都必d义一个唯一的discriminator-value。如果没有指定,׃使用Javacȝ全限定名?BR> 3.必须在子cȝ影射中指定extends属性来指定已媄的类?BR>
(?在jBPM中的使用
1.在jBPM的definitionl的cL构中采用上q的技术。其中ModuleDefinition是作为抽象父cd在的Q而ContextDefinition、FileDefinition、LoggingDefinition、SchedulerDefinition、MgmtDefinitioncL做ؓsubclass存在的?BR> 2.在父cM使用了discriminator鉴别器的技术:在承策略中的?STRONG>一个对象承树应对应一个表”的{略中,<discriminator>元素是必ȝ。鉴别器字段包含标志|用于告知持久层应该ؓ某个特定的行创徏哪一个类别的实例。例如:
父类的媄片D:
<discriminator type="char" column="CLASS_"/>
<!-- M : org.jbpm.module.def.ModuleDefinition -->
<!-- C : org.jbpm.context.def.ContextDefinition -->
<!-- F : org.jbpm.file.def.FileDefinition -->
<!-- L : org.jbpm.logging.def.LoggingDefinition -->
<!-- I : org.jbpm.scheduler.def.SchedulerDefinition -->
<!-- T : org.jbpm.taskmgmt.def.TaskMgmtDefinition -->
<!-- : -->
<!-- : -->
3.鉴别器字D늚实际值是Ҏ<class>?lt;subclass>元素中的discriminator-value属性得来的?BR> 例如Q?BR> 父媄文Ӟ
<class name="org.jbpm.module.def.ModuleDefinition"
table="JBPM_MODULEDEFINITION"
abstract="true"
discriminator-value="M"
lazy="false">
子媄文Ӟ
<subclass name="org.jbpm.context.def.ContextDefinition"
extends="org.jbpm.module.def.ModuleDefinition"
discriminator-value="C"
lazy="false">
</subclass>
]]>
JbpmConfigurationQ从名字上就知道是获取jBPM的相关配|信息。不q这里写的是一个公q获取properties的方法?BR> 首先声明了一个static propertiesQ静态属性)的实例properties,然后使用静态方法getPropertiesQ)Qؓproperties获得具体的|取org.jbpm.jbpm.propertiesQ?BR> 然后是N多获取方法:
public static String getString(String key)
public static String getString( String key, String defaultValue ) //如果没有q个|默认q回的是defaultValue
public static long getLong( String key, long defaultValue )
public static boolean getBoolean(String key, boolean defaultValue)
public static Object getObject(String key)
public static Object getObject(String key, Object defaultValue)
q些取String、long、boolean、Object提供基础的支持,Z后的操作提供了很多的方便?/P>
]]>
The core business of jBPM is the ability to persist the execution of a process. A situation in which this feature is extremely useful is the management of tasks and tasklists for people. jBPM allows to specify a piece of software describing an overall process which can have wait states for human tasks.
jBPM的核心逻辑是有能力持久化流E的执行。一个ؓZ用来理d和Q务列表的特征的情形是非常有用的。jBPM允许指定一些Y件描qC个全面的程Q它可以Zhd拥有{待状态?/P>
Tasks are part of the process definition and they define how task instances must be created and assigned during process executions.
d是流E定义的一部分Qƈ且他们定义了d实例如何在流E执行中必须被创建ƈ且委z?/P>
d可以在task-nodes和process-definition中被定义。最常用的方式是在task-node中定义一个或多个d。如果是那样的话Qtask-node表现一个Q务被用户执行q且程执行应该{待知道actor完成q个d。当q个actor完成q个dQ流E定义应该l。当更多d在task-node被定义,~省的行为是{待所有Q务的完成?/P>
d也被定义在process-definition中。指定在程定义上的d可以通过名称查询q且参考从内部的task-nodes或者从内部actions中用。事实上Q所有的l定名称dQ也在task-nodesQ可以在程定义中通过名字查询?/P>
d名称在整个流E定义中是非重复。Q务可以被指定一个优先权。这个优先权被使用在初始化优先权ؓ每个ZQ务创建的程实例。Q务实例然后可以修改初始化优先?/P>
A task instance can be assigned to an actorId (java.lang.String). All task instances are stored in one table of the database (JBPM_TASKINSTANCE). By querying this table for all task instances for a given actorId, you get the task list for that perticular user.
一个Q务实例可以被委派l一个actorId(java.lang.String).所有Q务实例被储存在数据库的一个表?JBPM_TASKINGSTANCE)。通过l定的actorId来对所有的d实例查询q个表,你ؓ特定用户得到d列表?/P>
The task instance lifecycle is straightforward: After creation, task instances can optionally be started. Then, task instances can be ended, which means that the task instance is marked as completed.
d实例生命周期是简单的Q创Z后,d实例可以随意地开始。接着QQ务实例可以被l结Q这意味着d实例内标志ؓ完成?/P>
TaskMgmtSession.findTaskInstancesByActorId(...)
TaskInstance.assign(String)
TaskInstance.start()
TaskInstance.end()
A task instance maintains it's state by means of date-properties : create, start and end. Those properties can be accessed by their respective getters on the TaskInstance.
一个Q务实例维护它的状态借助于日期属性:create,start 和end. q些属性可以在d实例中通过他们分别的getter获得通道?/P>
last-wait: Proceeds execution when the last task instance is completed. When no tasks are created on entrance of this node, execution waits in the task node till tasks are created.
first: Proceeds execution when the first task instance is completed. When no tasks are created on entrance of this node, execution is continued.
first-wait: Proceeds execution when the first task instance is completed. When no tasks are created on entrance of this node, execution waits in the task node till tasks are created.
unsynchronized: Execution always continues, regardless wether tasks are created or still unfinished.
never: Execution never continues, regardless wether tasks are created or still unfinished.
Task instance creation might be based upon a runtime calculation. In that case, add an ActionHandler on the node-enter event of the task-node and set the attribute create-tasks="false". Here is an example of such an action handler implementation:
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);
}
}
As shown in the example the tasks to be created can be specified in the task-node. They could also be specified in the process-definition and fetched from the TaskMgmtDefinition. TaskMgmtDefinition extends the ProcessDefinition with task management information.
]]>
token
node
task
taskInstance
<process-definition>
<event type="node-enter">
<script>
System.out.println("this script is enering node"+node);
</script>
</event>
...
</process-definition>
为定制缺省加载行为ƈ且储存变量进scriptQ变量元素可以被用来作ؓscript的子元素。那P脚本表达式不得不被放入一个脚本的子元?expression
<prcession-definition>
<event type="process-end">
<expression>
a = b+c;
</expression>
<variable name="XXX" access="write" mapped-name="a"/>
<variable name="YYY" access="read" mapped-name="b"/>
<variable name="ZZZ" access="read" mapped-name="c"/>
</event>
</prcession-definition>
在脚本开始之前,q个程变量YYY和ZZZ分别作本变量b和c使其合法。所有脚本完成之后,脚本变量值a被存储进程变量XXX.
如果access变量属性包?read"Q这个流E变量在脚本赋g前将被加载作Z个脚本变量。如果access变量属性包?write"Q这个流E变量在脚本赋g后将被加载作Z个脚本变量?/P>
7.3.3. Nodetype state 节点cd 状?BR>A state is a bare-bones wait state. The difference with a task node is that no task instances will be created in any task list. This can be usefull if the process should wait for an external system. E.g. upon entry of the node (via an action on the node-enter event), a message could be sent to the external system. After that, the process will go into a wait state. When the external system send a response message, this can lead to a token.signal(), which triggers resuming of the process execution.
一个状态是裔R{待状态。这个不同一个Q务节点的是没有Q务实例将被创建在dd列表中。这可以是有用的Q如果流E应当ؓ外部pȝ{待。例如,在节点实体之上(依靠在节点进入事件的一个动作)Q一个消息将被发送到外部pȝ。毕竟,q个程进入等待状态。当外部pȝ发送一个返回信息,q可以导致token.signal(),q将触发一个流E执行的恢复?/P>
7.3.4. Nodetype decision 节点cd 军_
Actually there are 2 ways to model a decision. The distinction between the two is based on *who* is making the decision. Should the decision made by the process (read: specified in the process definition). Or should an external entity provide the result of the decision.
实际上这里有两种Ҏ来创Z个决定。两者的区别是基谁在做这个决定。 应该被流E来军_。(限定在流E定义中Q或者应该一个外部实体支持决定的l果?/P>
When the decision is to be taken by the process, a decision node should be used. There are basically 2 ways to specify the decision criteria. Simplest is by adding condition elements on the transitions. Conditions are beanshell script expressions that return a boolean. At runtime the decision node will loop over its leaving transitions (in the order as specified in the xml), and evaluate each condition. The first transition for which the conditions resolves to 'true' will be taken. Alternatively, an implementation of the DecisionHandler can be specified. Then the decision is calculated in a java class and the selected leaving transition is returned by the decide-method of the DecisionHandler implementation.
当这个决定被程执行Q一个决定节点应该被使用。这里有两个基本Ҏ来限定决定标准。最单是在跃q上增加条g因素。条件是Beanshell脚本表达式返回一个boolean倹{在q行时这个决定节点将循环d跃迁Q顺序和xml定义的一P。一个DecisionHandler的实现被定义是可选择的。那么,军_被计在javacMq且选择d跃迁被DecisionHandler实现的决定方法返回?/P>
When the decision is taken by an external party (meaning: not part of the process definition), you should use multiple transitions leaving a state or wait state node. Then the leaving transition can be provided in the external trigger that resumes execution after the wait state is finished. E.g. Token.signal(String transitionName) and TaskInstance.end(String transitionName).
当这个决定被外部执行Q意味着Q不是流E定义部分)Q你应该使用多跃q离开一个状态或{待节点。那么这个离开跃迁在外部的除法器可以被支持恢复执行Q在{待状态完成后。例如,Token.signal(String transitionName) 和TaskInstance.end(String transitionName).
7.3.5. Nodetype fork 节点cd ?BR>A fork splits one path of execution into multiple concurrent paths of execution. The default fork behaviour is to create a child token for each transition that leaves the fork, creating a parent-child relation between the token that arrives in the fork.
一个叉分离一个\径执行到多个q行的执行\径。这个缺省的叉行为是为每个离开叉跃q创Z个子tokenQ创Z个到辑֏中父Q子关系?/P>
7.3.6. Nodetype join 节点cd 合ƈ
The default join assumes that all tokens that arrive in the join are children of the same parent. This situation is created when using the fork as mentioned above and when all tokens created by a fork arrive in the same join. A join will end every token that enters the join. Then the join will examine the parent-child relation of the token that enters the join. When all sibling tokens have arrived in the join, the parent token will be propagated over the (unique!) leaving transition. When there are still sibling tokens active, the join will behave as a wait state.
~省的合q假设所有的token到达合ƈ点,q些都都是相同父的子。这个情形被创徏如我们以上提到的使用叉ƈ且当所有被fork创徏的所有token到达相同的join. 一个join结束每个进入join的token. 那么q个join检查进入join的tokenӞ子关pR当所有的兄弟姐们tokensȀz,q个d的跃qjoin传播。当q里q有兄弟tokensȀz,q个join作Z个等待状态?/P>
7.3.7. Nodetype node 节点cd 节点
The type node serves the situation where you want to write your own code in a node. The nodetype node expects one subelement action. The action is executed when the execution arrives in the node. The code you write in the actionhandler can do anything you want but it is also responsible for propagating the execution.
节点cd服务在你惛_你自q代码在节点中。这个节点类型节Ҏ待一个子元素行ؓ。这个行执行当所有执行到达这个节炏V在actionHandler中你写的代码可以做你惛_的Q何事情,当时它是也是一个责Mؓ执行传播?/P>
This node can be used if you want to use a JavaAPI to implement some functional logic that is important for the business analyst. By using a node, the node is visible in the graphical representation of the process. For comparison, actions --covered next-- will allow you to add code that is invisible in the graphical representation of the process, in case that logic is not important for the business analyst.
q个节点可以被用,如果你将使用JavaAPI来实C些功能逻辑Q对逻辑分析是重要的. 作ؓ使用一个node,node 是可以视的在程囑Ş表现中。ؓҎQactions-convered next--允许在程囑Ş表现中增加不可见的代码,万一对你逻辑分析是不重要?/P>
signal()
provides a signal to the token. this method activates this token and leaves the current state over the default transition.
准备一个信L标记。这个方法激z这个标记ƈ且离开当前的状态越q缺省的跃迁?BR>------------------------------------
Class ProcessInstance
is one execution of a ProcessDefinition. To create a new process execution of a process definition, just use the ProcessInstance(ProcessDefinition).
是一个流E定义的执行?BR>ProcessInstance(ProcessDefinition)
---------------------------------------
Class ProcssDefinition
创徏一个ProcessDefinition
parseParResource(String parResource)
parseParZipInputStream(ZipInputStream zipInputStream)
parseXmlInputStream(InputStream inputStream)
parseXmlReader(Reader reader)
parseXmlResource(String resource)
parseXmlString(String string)
-----------------------------
Class ContextInstance
maintains all the key-variable pairs for a process instance. You can obtain a ContextInstance from a processInstance from a process instance like this :
ProcessInstance processInstance = ...;
ContextInstance contextInstance = processInstance.getContextInstance();
为流E实例维持所有的key-variable寏V?/P>
ContextInstance contextInstance = ProcessInstance.getContextInstance();
contextInstance.setVariable("amount",new Integer(500));
contextInstance.setVariable("reason","I met my deadline");
--------------------------
d节点Q?BR><task-node name="t">
<task name="change nappy">
<assignment class="org.jbpm.tutorial.taskmgmt.NappyAssignmentHandler"/>
</task>
<transition to="end">
</task-node>
TaskInstance taskInstance = (TaskInstance)processInstance.getTaskMgmtInstance().getTaskInstances().iterator().next();
taskInstance.end(); //标志q个d已经l束
--------------------------------------------