第11章 任務(wù)管理
Jbpm的核心業(yè)務(wù)是持久化流程執(zhí)行的能力,對(duì)于管理任務(wù)和個(gè)人任務(wù)清單來說這是一個(gè)非常重要的特性,Jbpm允許指定一段軟件描述所有人的任務(wù)中處于等待狀態(tài)的流程。
11.1 任務(wù)
任務(wù)是流程定義的一部分,它們定義了在流程執(zhí)行期間任務(wù)實(shí)例怎樣被創(chuàng)建和分配。
任務(wù)可以在task-node和process-definition中定義,通常使用的方式是在一個(gè)task-node里定義一個(gè)或多個(gè)任務(wù),這種情況下,task-node代表一個(gè)將由用戶完成的任務(wù),并且流程執(zhí)行將一直等待直到參與者完成這個(gè)任務(wù),當(dāng)參與者完成任務(wù)時(shí),流程執(zhí)行將繼續(xù)。當(dāng)在一個(gè)task-node中指定多個(gè)任務(wù)時(shí),默認(rèn)的行為是等待所有任務(wù)完成。
任務(wù)也可以被指定在process-definition。指定在process-definition的任務(wù)可以通過名稱查找到并且在task-node里引用或者在內(nèi)部動(dòng)作中使用。事實(shí)上,所有給定名稱的任務(wù)(包括在task-node中定義的任務(wù))都可以在流程定義(process-definition)中通過名字查找到。
任務(wù)名稱在整個(gè)流程定義中必須是唯一的。任務(wù)可以被指定一個(gè)優(yōu)先級(jí),這個(gè)優(yōu)先級(jí)在任務(wù)的實(shí)例創(chuàng)建時(shí)將被作為每個(gè)任務(wù)實(shí)例的初始優(yōu)先級(jí),任務(wù)實(shí)例的初始優(yōu)先級(jí)可以在以后被修改。
11.2 任務(wù)實(shí)例
任務(wù)實(shí)例可以被分配一個(gè)actorId(java.lang.String)。所有的任務(wù)實(shí)例被存儲(chǔ)在數(shù)據(jù)庫中的一張表里面(JBPM_TASKINSTANCE),通過查詢這張表可以得到給定actorId的所有任務(wù)實(shí)例,進(jìn)而獲取特定用戶的任務(wù)清單。
Jbpm的任務(wù)清單機(jī)制可以組合Jbpm任務(wù)和其他任務(wù),甚至那些任務(wù)與流程執(zhí)行毫不相干,這樣,Jbpm開發(fā)者可以很方便的組合Jbpm流程任務(wù)和其他應(yīng)用的任務(wù)到一個(gè)集中的任務(wù)清單倉庫中。
11.2.1 任務(wù)實(shí)例生命周期
任務(wù)實(shí)例的生命周期是很直觀的:創(chuàng)建后,任務(wù)實(shí)例可以被隨意地開始,然后任務(wù)實(shí)例可以被結(jié)束,這意味著任務(wù)實(shí)例被標(biāo)記為完成。
注意,為了靈活性,分配不是生命周期的一部分,所以任務(wù)實(shí)例可以被分配也可以不被分配,任務(wù)實(shí)例的分配不會(huì)影響任務(wù)實(shí)例的生命周期。
任務(wù)實(shí)例典型的創(chuàng)建是通過流程執(zhí)行進(jìn)入一個(gè)task-node(使用方法TaskMgmtInstance.createTaskInstance(…)),然后,用戶接口組件會(huì)使用TaskMgmtSession.findTaskInstancesByActorId(…)查詢數(shù)據(jù)庫獲取任務(wù)列表,然后,在收集了用戶輸入后,UI組件調(diào)用TaskInstance.assign(String)、TaskInstance.start()或者TaskInstance.end(…)。
任務(wù)實(shí)例依靠日期屬性維護(hù)它的狀態(tài):創(chuàng)建、開始和結(jié)束。這些屬性可以通過任務(wù)實(shí)例上它們各自的getter方法訪問。
通常,完成的任務(wù)實(shí)例用一個(gè)結(jié)束日期做了標(biāo)記,所以它們不能被以后的任務(wù)列表查詢獲取,但是它們?nèi)匀淮嬖谟贘BPM_TASKINSTANCE表中。
11.2.2 任務(wù)實(shí)例和圖執(zhí)行
任務(wù)實(shí)例是參與者任務(wù)清單(tasklist)中的項(xiàng)目,任務(wù)實(shí)例可以作為信號(hào),當(dāng)一個(gè)信號(hào)任務(wù)實(shí)例完成時(shí),可以發(fā)送一個(gè)信號(hào)到它的令牌繼續(xù)流程執(zhí)行。任務(wù)實(shí)例可以被阻塞,這意味著在任務(wù)實(shí)例完成之前相關(guān)令牌(=執(zhí)行路徑)不允許離開任務(wù)節(jié)點(diǎn)。默認(rèn)情況下,任務(wù)實(shí)例是信號(hào)非阻塞的。
如果多于一個(gè)任務(wù)實(shí)例與一個(gè)任務(wù)節(jié)點(diǎn)關(guān)聯(lián),流程開發(fā)者可以指定任務(wù)實(shí)例的完成怎樣影響流程的繼續(xù)。下面是可以給任務(wù)節(jié)點(diǎn)的signal屬性設(shè)置的值:
l last:這是默認(rèn)值。當(dāng)最后一個(gè)任務(wù)實(shí)例完成時(shí)繼續(xù)執(zhí)行;當(dāng)在節(jié)點(diǎn)入口處沒有任務(wù)創(chuàng)建時(shí),繼續(xù)執(zhí)行。
l last-wait:當(dāng)最后一個(gè)任務(wù)實(shí)例完成時(shí)繼續(xù)執(zhí)行;當(dāng)在節(jié)點(diǎn)入口處沒有任務(wù)創(chuàng)建時(shí),執(zhí)行在任務(wù)節(jié)點(diǎn)等待,直到任務(wù)被創(chuàng)建。
l first:當(dāng)?shù)谝粋€(gè)任務(wù)實(shí)例完成時(shí)繼續(xù)執(zhí)行;當(dāng)在節(jié)點(diǎn)入口處沒有任務(wù)創(chuàng)建時(shí),繼續(xù)執(zhí)行。
l first-wait:當(dāng)?shù)谝粋€(gè)任務(wù)實(shí)例完成時(shí)繼續(xù)執(zhí)行;當(dāng)在節(jié)點(diǎn)入口處沒有任務(wù)創(chuàng)建時(shí),執(zhí)行在任務(wù)節(jié)點(diǎn)等待,直到任務(wù)被創(chuàng)建。
l unsynchronized:總是繼續(xù)執(zhí)行,不管任務(wù)是否創(chuàng)建和完成。
l never:執(zhí)行不再繼續(xù),不管任務(wù)是否創(chuàng)建和完成。
任務(wù)實(shí)例可以基于運(yùn)行時(shí)的計(jì)算創(chuàng)建,如果那樣的話,需要添加一個(gè)ActionHandler到任務(wù)節(jié)點(diǎn)的node-enter事件,并且設(shè)置屬性create-tasks=“false”。下面是這樣一個(gè)動(dòng)作的實(shí)現(xiàn)例子:
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");
// 現(xiàn)在, 相同任務(wù)的兩個(gè)任務(wù)實(shí)例被創(chuàng)建
tmi.createTaskInstance(changeNappy, token);
tmi.createTaskInstance(changeNappy, token);
}
}
如示例所展示,任務(wù)可以在指定的任務(wù)節(jié)點(diǎn)中創(chuàng)建,它們也可以被指定到process-definition,并且從TaskMgmtDefinition獲取。TaskMgmtDefinition用任務(wù)管理信息擴(kuò)展了ProcessDefinition。
標(biāo)識(shí)任務(wù)示例完成的API是TaskInstance.end(),你可以在end方法中指定一個(gè)轉(zhuǎn)換,如果這個(gè)任務(wù)的完成會(huì)觸發(fā)繼續(xù)執(zhí)行,則會(huì)通過指定的轉(zhuǎn)換離開任務(wù)節(jié)點(diǎn)。
11.3 分配
流程定義包含任務(wù)節(jié)點(diǎn),任務(wù)節(jié)點(diǎn)(task-node)包含一個(gè)或多個(gè)任務(wù),任務(wù)作為流程定義的一部分是靜態(tài)描述。在運(yùn)行時(shí),任務(wù)導(dǎo)致任務(wù)實(shí)例的創(chuàng)建,一個(gè)任務(wù)實(shí)例對(duì)應(yīng)某人任務(wù)列表中的一個(gè)入口。
11.3.1 分配接口
通過接口AssignmentHandler進(jìn)行任務(wù)實(shí)例分配:
public interface AssignmentHandler extends Serializable {
void assign( Assignable assignable, ExecutionContext executionContext );
}
當(dāng)任務(wù)實(shí)例被創(chuàng)建時(shí)分配處理的實(shí)現(xiàn)被調(diào)用,在那時(shí),任務(wù)實(shí)例可以被分配到一個(gè)或多個(gè)參與者。AssignmentHandler實(shí)現(xiàn)將調(diào)用分配方法(setActorId或setPooledActors)分配任務(wù),可以分配一個(gè)任務(wù)實(shí)例或者一個(gè)泳道實(shí)例swimlaneInstance(=流程角色)。
public interface Assignable {
public void setActorId(String actorId);
public void setPooledActors(String[] pooledActors);
}
任務(wù)實(shí)例和泳道實(shí)例都可以被分配到一個(gè)用戶或者共享參與者。分配任務(wù)實(shí)例到一個(gè)用戶,調(diào)用Assignable.setActorId(String actorId);分配任務(wù)實(shí)例到候選的共享參與者,調(diào)用Assignable.setPooledActors(String[] actorIds)。
流程定義中的每個(gè)任務(wù)都可以與一個(gè)分配處理實(shí)現(xiàn)相關(guān)聯(lián),用來完成運(yùn)行時(shí)的任務(wù)分配。
當(dāng)流程中的多個(gè)任務(wù)將要分配給相同的人或者參與者組時(shí),考慮使用
泳道。考慮到AssignmentHandler的重用,每個(gè)AssignmentHandler的使用可以在processdefinition.xml中配置。請(qǐng)參考“16.2 委托”了解怎樣添加分配處理配置的更多信息。
11.3.2 分配數(shù)據(jù)模型
下面是管理分配任務(wù)實(shí)例和泳道實(shí)例到參與者的數(shù)據(jù)模型,每個(gè)任務(wù)實(shí)例擁有一個(gè)actorId或一組被共享的參與者。
圖 11.1 分配模型類圖
actorId對(duì)任務(wù)負(fù)責(zé),而共享的參與者表示候選者集合,如果它們獲取任務(wù),則可以負(fù)責(zé)任務(wù)。actorId和共享參與者具體使用哪個(gè)是可選的,兩者也可以結(jié)合使用。
11.3.3 推模式
任務(wù)實(shí)例的actorId表明對(duì)給定任務(wù)負(fù)責(zé),而任務(wù)實(shí)例的共享參與者是任務(wù)的候選參與者。典型情況下,任務(wù)實(shí)例的actorId指向一個(gè)用戶,共享參與者可以指向多個(gè)用戶和/或用戶組。
用戶的任務(wù)清單是所有以用戶作為actorId的任務(wù)實(shí)例,這個(gè)清單可以使用TaskMgmtSession.findTaskInstances(String actorId)獲得。
11.3.4 拉模式
另一方面,共享的任務(wù)(譯者注:共享任務(wù)即不僅是由一個(gè)用戶負(fù)責(zé)的)是提供給共享參與者中所引用的用戶的。獲取共享任務(wù)一般需要兩步操作:1)從身份組件中獲取給定用戶的所有組2)為結(jié)合了用戶的actorId和指向用戶組的actorId獲取所有共享任務(wù)清單(譯者注:這段話不太好理解,解釋如下――任務(wù)指向一個(gè)actorId,在Jbpm中并沒有強(qiáng)制限制該actorId必須為單個(gè)用戶或者用戶組,所以我們?cè)趯?shí)際應(yīng)用中也可以把a(bǔ)ctorId作為一個(gè)用戶組。假如有一個(gè)用戶為user1,他屬于用戶組group1,在流程中有些任務(wù)分配到了user1,而其它又有些任務(wù)分配到了group1,如果我們要取user1的所有共享任務(wù),則即需要獲取分配到user1的共享任務(wù),也需要獲取分配到group1的共享任務(wù))??梢允褂梅椒═askMgmtSesion.findPooledTaskInstances(String actorId)或TaskMgmtSession.findPooledTaskInstances(List actorIds)獲取提供給指定用戶的共享任務(wù)清單,這些方法會(huì)返回actorId為空(null)以及共享參與者中某個(gè)與給定的actorIds中的某個(gè)相匹配的任務(wù)實(shí)例。
為了防止多個(gè)用戶在同一個(gè)共享任務(wù)上工作,使用用戶的actorId修改任務(wù)實(shí)例的actorId就可以了。這樣,任務(wù)實(shí)例將不會(huì)出現(xiàn)在共享任務(wù)清單中,而只會(huì)存在于用戶個(gè)人的任務(wù)清單里。設(shè)置任務(wù)實(shí)例的actorId為空(null),則會(huì)把任務(wù)實(shí)例放回共享任務(wù)里。
11.4 任務(wù)實(shí)例變量
任務(wù)實(shí)例可以擁有它自己的變量,并且也可以“看到”流程變量。任務(wù)實(shí)例通常是在執(zhí)行路徑(=令牌)中創(chuàng)建,與令牌之間的父子關(guān)系相似,這會(huì)在令牌和任務(wù)實(shí)例之間創(chuàng)建一個(gè)父子關(guān)系。正常的范圍規(guī)則適用于相關(guān)令牌的任務(wù)實(shí)例變量和流程變量之間,有關(guān)范圍的更多信息可以在“
10.4 變量范圍”找到。這意味著任務(wù)實(shí)例可以“看到”它自己的變量,另外還有它所關(guān)聯(lián)令牌的所有變量。
控制器可以用來在任務(wù)實(shí)例范圍和流程范圍的變量間創(chuàng)建、組裝和提交變量。
11.5 任務(wù)控制器
在任務(wù)實(shí)例創(chuàng)建時(shí),任務(wù)控制器可以組裝任務(wù)實(shí)例變量,并且當(dāng)任務(wù)實(shí)例完成時(shí),任務(wù)控制器可以提交任務(wù)實(shí)例的數(shù)據(jù)到流程變量。
注意,任務(wù)控制器不是強(qiáng)制使用的,即使不使用任務(wù)控制器,任務(wù)實(shí)例也能夠“看到”與它的令牌相關(guān)的流程變量,當(dāng)你想要做如下事情時(shí)使用任務(wù)控制器:
l 在任務(wù)實(shí)例中創(chuàng)建變量的拷貝,這樣任務(wù)變量的中間更新不會(huì)影響到流程變量,而是直到處理完成后拷貝才被提交回流程變量。
l 任務(wù)實(shí)例變量與流程變量不是一一對(duì)應(yīng)的。例如,假設(shè)流程有變量“sales in januari”“sales in februari”和“sales in march”,而任務(wù)實(shí)例所使用表單可能需要顯示的是三個(gè)月的平均銷售量。
任務(wù)用來收集用戶輸入,但是目前有很多可以向用戶展示任務(wù)的用戶接口,例如web應(yīng)用、swing應(yīng)用、及時(shí)消息、電子郵件表單…因此任務(wù)控制器在流程變量(=流程上下文)和用戶接口應(yīng)用之間起到了橋的作用,任務(wù)控制器為用戶接口應(yīng)用提供流程變量的視圖。
任務(wù)控制器在流程變量到任務(wù)變量之間進(jìn)行轉(zhuǎn)換(如果需要)。當(dāng)任務(wù)實(shí)例被創(chuàng)建時(shí),任務(wù)實(shí)例負(fù)責(zé)從流程變量提取信息,并且創(chuàng)建任務(wù)變量,任務(wù)變量作為用戶接口表單是輸入,并且用戶輸入可以存儲(chǔ)在任務(wù)變量里;當(dāng)用戶結(jié)束任務(wù)時(shí),任務(wù)控制器負(fù)責(zé)基于任務(wù)實(shí)例數(shù)據(jù)更新流程變量。
圖 11.2 任務(wù)控制器
簡單的情形是,在流程變量和表單參數(shù)之間是一對(duì)一的映射,任務(wù)控制器在task元素中指定,這種情況下,默認(rèn)的Jbpm任務(wù)管理器可以被使用,它包含一個(gè)variable元素列表,variable元素表示流程變量怎樣被拷貝到任務(wù)變量。
下面的例子展示了怎樣基于流程變量的拷貝創(chuàng)建任務(wù)實(shí)例變量:
<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屬性是任意的,用來指向任務(wù)實(shí)例變量的名稱。如果忽略mapped-name屬性,則mapped-name默認(rèn)與name屬性相同。注意,mapped-name也被用來在web應(yīng)用中作為任務(wù)實(shí)例表單的域標(biāo)簽。
access屬性指定了如果在任務(wù)實(shí)例創(chuàng)建時(shí)變量被拷貝,是否需要在任務(wù)結(jié)束時(shí)把它寫回流程變量。這個(gè)信息可以被用戶接口所使用,進(jìn)行適當(dāng)?shù)谋韱慰刂?。access屬性是可選的,默認(rèn)值是“read,write”。
任務(wù)節(jié)點(diǎn)(task-node)可以擁有多個(gè)任務(wù),而開始狀態(tài)(start-state)只能有一個(gè)任務(wù)。
如果在流程變量和表單參數(shù)之間簡單的一對(duì)一映射太過約束,你也可以編寫你自己的TaskControllerHandler實(shí)現(xiàn),下面是TaskControllerHandler接口:
public interface TaskControllerHandler extends Serializable {
void initializeTaskVariables(TaskInstance taskInstance, ContextInstance contextInstance, Token token);
void submitTaskVariables(TaskInstance taskInstance, ContextInstance contextInstance, Token token);
}
下面展示了怎樣在任務(wù)中配置你自己定制的任務(wù)控制器:
<task name="clean ceiling">
<controller class="com.yourcom.CleanCeilingTaskControllerHandler">
-- here goes your task controller handler configuration --
</controller>
</task>
11.6 泳道(swimlane)
泳道是流程角色,它是定義流程中的多個(gè)任務(wù)由相同參與者完成的一種機(jī)制。在第一個(gè)任務(wù)實(shí)例為指定泳道創(chuàng)建后,參與者將被流程記住,以被在同一泳道中的后續(xù)任務(wù)所使用。泳道有一個(gè)
分配,因此所有引用泳道的任務(wù)不需要再指定分配。當(dāng)給定泳道的第一個(gè)任務(wù)被創(chuàng)建時(shí),泳道的AssignmentHandler被調(diào)用,Assignable被傳遞到AssignmentHandler,將會(huì)成為泳道實(shí)例(SwimlaneInstance)。需要知道的是,給定泳道中的所有任務(wù)實(shí)例的分配都被傳播到泳道實(shí)例,這個(gè)行為是被作為默認(rèn)實(shí)現(xiàn)的,因?yàn)楂@取任務(wù)進(jìn)行處理的人在履行某個(gè)流程角色(譯者注:也就是說在某個(gè)泳道內(nèi)),因此所有后續(xù)對(duì)泳道的任務(wù)實(shí)例的分配會(huì)自動(dòng)轉(zhuǎn)到用戶。
泳道是從UML活動(dòng)圖中借來的術(shù)語。
11.7 開始任務(wù)中的泳道
泳道可以與開始任務(wù)關(guān)聯(lián),用以捕獲流程的發(fā)起者。
任務(wù)可以在start-state中指定,該任務(wù)與泳道關(guān)聯(lián),當(dāng)這個(gè)任務(wù)的一個(gè)新的任務(wù)實(shí)例被創(chuàng)建時(shí),當(dāng)前已經(jīng)過鑒定的參與者可以使用Authentication.getAuthenticatedActorId()(參考17.2 鑒定)獲?。ㄗg者注:這時(shí)創(chuàng)建開始任務(wù)時(shí),自動(dòng)進(jìn)行的),并且該參與者存儲(chǔ)在開始任務(wù)的泳道里。
例如:
<process-definition>
<swimlane name=‘initiator‘ />
<start-state>
<task swimlane=‘initiator‘ />
<transition to=‘...‘ />
</start-state>
...
</process-definition>
象其它任何任務(wù)一樣,也可以向開始任務(wù)添加變量用來定義與任務(wù)關(guān)聯(lián)的表單。請(qǐng)參考“
11.5 任務(wù)控制器”。11.8 任務(wù)事件
任務(wù)可以擁有所關(guān)聯(lián)的動(dòng)作。任務(wù)有四個(gè)標(biāo)準(zhǔn)的事件類型定義:task-create,task-assign,task-start,和task-end。
當(dāng)一個(gè)任務(wù)實(shí)例被創(chuàng)建時(shí)task-create事件被激活。
當(dāng)一個(gè)任務(wù)實(shí)例被分配時(shí)task-assign事件被激活。注意:在這個(gè)事件中執(zhí)行的動(dòng)作里,你可以用executionContext.getTaskInstance().getPreviousActorId()訪問前一個(gè)參與者。
當(dāng)TaskInstance.start()被調(diào)用時(shí)task-start事件被激活。這可以被用來標(biāo)識(shí)用戶在這個(gè)任務(wù)實(shí)例上已經(jīng)開始工作。是否開始一個(gè)任務(wù)是可選的。
當(dāng)TaskInstance.end()被調(diào)用時(shí)task-end事件被激活。這標(biāo)志了任務(wù)的完成,如果任務(wù)與流程執(zhí)行相關(guān),這個(gè)調(diào)用會(huì)觸發(fā)流程繼續(xù)執(zhí)行。
因?yàn)槿蝿?wù)可以擁有事件以及相關(guān)聯(lián)的動(dòng)作,所以異常處理也可以在任務(wù)上被指定。有關(guān)異常處理的更多信息,請(qǐng)參考“
9.7 異常處理”。11.9 任務(wù)定時(shí)器
在節(jié)點(diǎn)上,定時(shí)器可以在任務(wù)上被指定。請(qǐng)參考“12.1 定時(shí)器”。
對(duì)于任務(wù)的定時(shí)器需要指明的是:任務(wù)定時(shí)器的cancel-event可以被定制。默認(rèn)情況下,當(dāng)任務(wù)被結(jié)束時(shí)(=完成)任務(wù)上的定時(shí)器將被取消,在是通過在定時(shí)器上使用cancel-event屬性,流程開發(fā)者可以定制諸如task-assign或task-start。cancel-event支持多個(gè)事件,通過在屬性中指定一個(gè)用逗號(hào)分割的列表,可以組合cancel-event的類型。
11.10 定制任務(wù)實(shí)例
任務(wù)實(shí)例可以被定制。最簡單的方式就是創(chuàng)建TaskInstance的子類,然后創(chuàng)建一個(gè)org.jbpm.taskmgmt.TaskInstanceFactory的實(shí)現(xiàn),并在jbpm.cfg.xml中設(shè)置配置屬性jbpm.task.instance.factory為該實(shí)現(xiàn)的完整類名。如果你使用一個(gè)TaskInstance的子類,還需要為該子類創(chuàng)建一個(gè)hibernate映射文件(使用hibernate的extends=”org.jbpm.taskmgmt.exe.TaskInstance”),然后在hibernate.cfg.xml中添加該映射文件到映射文件列表。
11.11 身份組件
用戶、組和權(quán)限管理一般都被稱為身份管理。Jbpm包含了一個(gè)可選的身份組件,它可以很容易的被企業(yè)自己的身份數(shù)據(jù)存儲(chǔ)所替換。
Jbpm的身份管理組件包含了組織知識(shí)模型。任務(wù)分配典型的需要由組織知識(shí)來完成,因此,這意味著組織知識(shí)模型描述了用戶、組、系統(tǒng)以及它們之間的關(guān)系。作為可選的,權(quán)限和角色也可以被包含進(jìn)組織模型。數(shù)個(gè)學(xué)術(shù)研究嘗試的失敗表明,沒有一個(gè)通用的組織模型可以適用于所有組織。
Jbpm的作法是定義一個(gè)參與者作為流程的實(shí)際參與者,參與者通過它的ID進(jìn)行標(biāo)識(shí),稱為actorId,Jbpm只知道actorId并且為了靈活性用java.lang.String表示,因此任何組織模型知識(shí)及其數(shù)據(jù)結(jié)構(gòu)都在Jbpm核心引擎之外。
作為對(duì)Jbpm的擴(kuò)展,我們將提供(以后)管理簡單的“用戶-角色”模型的組件,用戶和角色之間的多對(duì)多關(guān)系與J2EE和servlet規(guī)范中定義的模型是一致的,這可以作為一個(gè)新的開發(fā)起點(diǎn),感興趣的話可以查看jboss jbpm jira中的問題跟蹤來獲取更多詳細(xì)資料。
注意,實(shí)際被用在servlet、ejb和portlet規(guī)范中的“用戶-角色”模型不足以滿足任務(wù)的分配處理,該模型在用戶和角色之間是一個(gè)多對(duì)多的關(guān)系,不包括流程中用戶有關(guān)的組和組織結(jié)構(gòu)信息。
11.11.1 身份模型
圖 11.3身份模型類圖
黃色的類是下面將要討論的有關(guān)表達(dá)式分配處理的相關(guān)類。
User表示用戶或服務(wù)。Group是任何類型的用戶組,Group可以被嵌套,用來建模一個(gè)團(tuán)隊(duì)、一個(gè)業(yè)務(wù)單元、以及整個(gè)公司的關(guān)系,組有類型,用來在不同等級(jí)的組之間進(jìn)行區(qū)分,例如haircolor組。Membership表示用戶和組之間的多對(duì)多關(guān)系,membership可以被用來表示公司中的一個(gè)職位,membership的名字可被用來表示用戶在組中的角色。
11.11.2 分配表達(dá)式
隨同身份組件提供了一種實(shí)現(xiàn),即在進(jìn)行任務(wù)分配期間通過表達(dá)式計(jì)算參與者。這里有一個(gè)在流程定義中使用分配表達(dá)式的例子:
<process-definition>
...
<task-node name=‘a‘>
<task name=‘laundry‘>
<assignment expression=‘previous --> group(hierarchy) --> member(boss)‘ />
</task>
<transition to=‘b‘ />
</task-node>
...
分配表達(dá)式的語法如下:
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第一術(shù)語first-term
表達(dá)式以從左到右的順序被分解,first-term指定了身份模型中的一個(gè)用戶或組,后續(xù)的術(shù)語的計(jì)算基于這個(gè)中間的用戶或組。
privious的意思是任務(wù)被分配到當(dāng)前已被鑒定的參與者,這意味著參與者完成了流程中的前一個(gè)步驟。
swimlane(swimlane-name)的意思是用戶或組從指定的泳道實(shí)例中取得。
variable(variable-name)的意思是用戶或組從指定變量實(shí)例中取得。變量實(shí)例可以包含一個(gè)java.lang.String,這種情況下,用戶或組從身份組件獲取;或者變量實(shí)例包含一個(gè)用戶或組對(duì)象。
user(user-name)的意思是給定的用戶從身份組件中取得。
group(group-name)的意思是給定的組從身份組件中取得。
11.11.2.2第二術(shù)語next-term
group(group-type)獲取用戶的組,這意味著前一個(gè)術(shù)語必須結(jié)果為一個(gè)用戶,這個(gè)術(shù)語會(huì)使用給定的group-type在所有的membership中為用戶搜索組。
member(role-name)從組里得到用戶所履行的角色,前一個(gè)術(shù)語必須結(jié)果為一個(gè)組,這個(gè)術(shù)語在組中為用戶搜索與給頂?shù)膔ole-name相匹配的membership。
11.11.3 移除身份組件
當(dāng)你想要為組織信息使用自己的數(shù)據(jù)源時(shí),例如你們公司的用戶數(shù)據(jù)庫或者ldap系統(tǒng),你可以拔除身份組件,你唯一要做的就是在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并且綁定它到你自己的用戶數(shù)據(jù)存儲(chǔ),你可以從ExpressionAssignmentHandler繼承并且重寫getExpressiontSession方法。
protected ExpressionSession getExpressionSession(AssignmentContext assignmentContext);