Terry.Li-彬

          虛其心,可解天下之問;專其心,可治天下之學;靜其心,可悟天下之理;恒其心,可成天下之業。

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            143 隨筆 :: 344 文章 :: 130 評論 :: 0 Trackbacks

          標題:JBPM的一些資料
          出處:汐憶時空::CHIRS::蝶衣人生
          時間:Tue, 20 Jun 2006 09:53:24 +0000
          作者:chirs@zhoujin.com
          地址:www.zhoujin.com/read.php/18.htm

          內容:
          jPDL的流程定義元素
          第一層級:GraphElement

          這個容易理解,因為在畫流程定義時,每個拖拉的對象都是一個graph的元素.

          GraphElement有四個屬性:1)processDefine 表示當前元素屬于哪個流程定義

          2)events 表示可以接收哪些event

          3)name 名字

          4)exceptionHandlers 異常處理類集合(List)

          第二層級:node;processDefinition;Transition;Task 它們都inherited from GraphElement

          1)processDefinition表示流程定義(implements NodeCollection),它有下面的屬性:name,version,nodes,startState nodes表示流程中所有的node,startState用于啟動流程時找到首節點

          2)Transition表示轉移,它有三個屬性:from(Node),to(Node),supportedEventTypes表示支持的event類型

          3)node表示節點,它有四個屬性:leaving transitions;arriving transitions;action;superState

          4)Task 定義任務

          第三層級:各種不同的node,它們都inherited from node decision;EndState;Fork;Join;Merge;Milestone; InterleaveEnd;InterleaveStart;ProcessState;State 這些都是見名知義,和xpdl差不多.
          jbpm的Token
          jbpm中最重要的概念,應該是令牌(Token)和信令(Signal)

          在整個流程實例運行過程中,我們可以迅速的利用token得到其當前的current state。在解決“并行”等(比如Fork)問題時,jBpm讓Token對象維護了父子關系,這種關系在涉及到Fork的時候會產生。 jBpm讓Token這個對象身兼了多種使命:(1)快速定位current state (2)用于fork,join算法 (3)用于告知任務執行者的任務索引。

          如下代碼:

          //pd是process definition,pi是process instance ProcessInstance

          pi = new ProcessInstance( pd );

          //得到根令牌

          Token token = pi.getRootToken();

          //發信令

          token.signal();

          Token的signal方法也可以傳入transition參數,這個方法把信令發送給Token,這樣,令牌將被激活,并沿指定的transition離開當前的狀態(如果沒有指定transition,將沿缺省的transition 離開當前狀態).

          jbpm是怎么實現的呢?其實很簡單:

          1)Token記錄了當前的狀態(current state),只有當前的狀態(或稱節點)擁有該令牌

          2)向TOKEN發signal后,當前狀態收到該signal

          3)當前狀態把令牌傳給signal中指定的transition

          4)transition收到令牌后,不強占,馬上把令牌傳給下個狀態.

          5)根據令牌的位置,流程的狀態已經發生改變.


          1、process definition
          一個process definition代表了一個正式的業務流程,它以一個流程圖為基礎。這個流程圖由 許多node和transition組成。每個node在這個流程圖里都有著各自特殊的類型,這些不同的類型決定了node在運行時的不同行為。一個process definition只有一個start state 。
          2、token
          一個token代表了一條執行路徑,它包含了這條執行路徑的當前的執行狀態(current state)。
          3、process instance
          一個process instance(流程實例)即一個process definition(流程定義)的流程執行實例。一個process definition可以對應多個process instance。當一個process instance被創建的時候,一個主執行路徑token同時被創建,這個token叫做root token,它指向流程定義的start state(processDefinition.getStartState()==token.getNode())。
          4、signal
          一個signal 發送給token通知token 繼續流程的執行。如果signal 沒有指定transition,token將沿缺省的transition離開當前狀態,如果signal 指定transition,token將沿指定的transition離開當前的狀態。看源代碼可以看到發給process instance的signal 其實都是發送給了root token。
          5、Actions
          jbpm提供了靈活的action ,當流程執行,token 進入node和transition時,會觸發相應的一些event(事件)。在這些event上附上我們自己寫的action,就會帶動action 的執行。action里是我們自己的相關java操作代碼,非常方便。注意的是event(事件)是內置的,無法擴展。另外,action也可以直接掛在node上,而不依賴于event(事件)的觸發,這個很重要!
          Node


          一個流程圖由許多node和transition組成。每個node都有一種類型,這個類型決定了當流程執行到這個node時的不同行為。jbpm有一組node type可以供你選擇,當然你可以定制自己node 。
          node的作用
          node有兩個主要的作用:
          1)執行java代碼,比如說創建task instance(任務實例)、發出通知、更新數據庫等等。很典型的就是在node 上掛上我們的action
          2) 控制流程的執行:
          A、等待狀態
          流程進入到這個node時將處于等待狀態,直到一個signal 的發出
          B、流程將沿著一個leaving transition越過這個node
          這種情況特殊一點,需要有個action掛在這個node上(注意這個action不是event觸發的!),action中將會調用到API里
          executionContext.leaveNode(String transitionName),transitionName即這里的leaving transition名字。
          C、創建新的執行路徑
          很典型的就是fork node。流程在這里會分叉,產生新的執行路徑。這樣就創建了新的token,每個新的token代表一個新的執行路徑。注意的是,這些新的token和產生前的token是父子關系!
          D、結束執行路徑
          一個node可以結束一條執行路徑,這同樣意味著相應的token的結束和流程的結束。

          流程圖中的node type


          1、task-node
          一個task-node可以包含一個或多個task,這些task分配給特定的user。當流程執行到task-node時,task instance將會被創建,一個task對應一個task instance。task instances 創建后,task-node就處于等待狀態。當所有的task instances被特定的user執行完畢后,將會發出一個新的signal 到token,即流程繼續執行。
          2、state
          state是一個純粹的wait state(等待狀態)。它和task-node的區別就是它不會創建task instances。很典型的用法是,當進入這個節點時(通過綁定一個action到node-enter event),發送一條消息到外部的系統,然后流程就處于等待狀態。外部系統完成一些操作后返回一條消息,這個消息觸發一個signal 到token,然后流程繼續執行。(不常用)
          3、decision
          當需要在流程中根據不同條件來判斷執行不同路徑時,就可以用decision節點。兩種方法:最簡單的是在transitions里增加condition elements(條件),condition是beanshell script寫的,它返回一個boolean。當運行的時候,decision節點將會在它的 leaving transitions里循環,同時比較 leaving transitions里的condition,最先返回'true'的condition,那個leaving transitions將會被執行;作為選擇,你可以實現DecisionHandler接口,它有一個decide()方法,該方法返回一個String(leaving transition的名字)。
          4、fork
          fork節點把一條執行路徑分離成多條同時進行(并發)的執行路徑,每條離開fork節點的路徑產生一個子token。
          5、join
          默認情況下,join節點會認為所有到達該節點的token都有著相同的父token。join 節點會結束每一個到達該節點的token,當所有的子token都到達該節點后,父token會激活。當仍然有子token處于活動狀態時,join 節點是wait state(等待狀態)。
          6、node
          node節點就是讓你掛自己的action用的(注意:不是event觸發!!),當流程到達該節點時,action會被執行。你的action要實現ActionHandler接口。同樣,在你的action里要控制流程!

          Actions的說明


          存在兩種action,一種是 event觸發的action,一種是掛在node 節點的action。要注意它們的區別,event觸發的action無法控制流程,也就是說它無法決定流程經過這個節點后下一步將到哪一個leaving transition;而掛在node 節點的action就不同,它可以控制流程。不管是哪一種action都要實現ActionHandler接口。
          variable的管理


          流程實例中,存有contextInstance來管理token和variable.
          contextInstance是通過一個map來進行管理的,這個map的key是token,value是一個TokenVariableMap的對象.

          TokenVariableMap本身并不是個map,而是一個普通的Object

          TokenVariableMap有三個屬性,一個是contextInstance,一個是Token對象本身,還有一個是
          一個Map,用來放variableInstance,這個Map的名稱為variableInstances.

          variableInstances是一個map,它的key是variable的名稱,如"a",value是一個VariableInstance對象,VariableInstance對象放了四個屬性,一個是token對象本身,一個是variable的名稱,一個是TokenVariableMap對象,還有一個是processInsance,你可能會奇怪:variable的value放到哪里呢?實際上VariableInstance是一個抽象類,具體的實現是它根據value的class類型選擇它的子類,子類中有個屬性叫value。這個variable的value,如 new Integer(3).

          一個流程實例可以有多個Token,Token間是有父子關系的:
          Token tokenAB=new Token(tokenA,"ab");
          上行代碼的意思是在tokenA下面建立一個TokenAB,該新建的
          Token的名字是"ab".

          ci.createVariable(tokenA, "a", new Integer(3));
          表示在tokenA范圍內建立一個variable,它的名稱為"a",
          值為new Integer(3)
          建立這個variable后,tokenA下面的token都可以看到該
          variable,而上面的token則看不到.

          只有createVariable可以在某個token上建立variable,其它的
          方法只可以在rootToken上建立variable.
          如:ci.setVariable(tokenA, "a", new Integer(3));
          其實是在rootToken上建立了一個名稱為"a"的variable
          Map variables = new HashMap();
          variables.put("a", new Integer(3));
          variables.put("b", new Integer(4));
          ci.addVariables(variables);
          上面四行代碼在rootToken上建立了兩個variable.
          實際上在ExecutionContext中只有兩個方法:
          public void setVariable(String name, Object value) {
          getContextInstance().setVariable(name, value, token);
          }
          public Object getVariable(String name) {
          return getContextInstance().getVariable(name, token);
          }
          可以在子token中修改父token中建立的variable.

          Task(任務)


          jbpm一個相當重要的功能就是對任務進行管理。
          Task(任務)是流程定義里的一部分,它決定了task instance的創建和分配。
          Task(任務)可以在task-node節點下定義,也可以掛在process-definition節點下。最普遍的方式是在task-node節點下定義一個或多個任務。默認情況下,流程在task-node節點會處于等待狀態,直到所有的任務被執行完畢。任務的名稱在整個流程中必須是唯一的。

          一個TaskNode對應多個Task
          對于這樣的流程定義:
           
           
           
           
           
           
          只有當節點中的三個任務都完成后,流程才進入后面的節點

          對于這樣的流程定義:
          >
           
           
           
           
           
          當第一個任務完成后,token就指向后面的節點

          對于這樣的流程定義:
          >
           
           
           
           
           
          三個任務都完成后,token仍然不會指向后面的節點;需要自己手動調用

          processInstance.signal()才會驅動流程到下面的節點

          對于這樣的流程定義:
          >
           
           
           
           
           
          token不會在本節點停留,而是直接到后面的節點

          jbpm的任務管理實現
          一個Task instance(任務實例)可以被分配給一個actorId (java.lang.String)。所有的Task instance都被保存在數據庫中的表jbpm_taskinstance里。當你想得到特定用戶的任務清單時,你就可以通過一個與用戶關聯的actorId來查詢這張表。

          一個流程定義有一個TaskMgmtDefinition;一個TaskMgmtDefinition對應多個swimlane,同時對應多個task;一個swimlane有多個task,可以從TaskMgmtDefinition中通過task的名稱直接獲取相應的task;

          swimlane對象有四個屬性,分別是name(名字)、assignmentDelegation(分配代理類)、taskMgmtDefinition、tasks(Set 對應多個task),可以增加task

          task對象主要的屬性:taskMgmtDefinition、swimlane、assignmentDelegation、taskNode,需要注意的是swimlane和assignmentDelegation中間只是可以一個屬性有值,因為它們都和任務的分配有關系。

          一個流程實例有一個TaskMgmtInstance;一個TaskMgmtInstance對應多個swimlaneInstance,同時對應多個taskInstance;一個swimlaneInstance有多個taskInstance,可以從TaskMgmtInstance中直接獲取相應的taskInstance;

          swimlaneInstance對象主要有五個屬性,分別是name、actorId、pooledActors(Set)、swimlane、taskMgmtInstance。
          taskInstance對象的主要屬性:name、actorId、task、swimlaneInstance、taskMgmtInstance、pooledActors。

          當對任務進行分配時,一般需要實現AssignmentHandler這個接口,這個接口的方法只有一個:
          void assign( Assignable assignable, ExecutionContext executionContext ) throws Exception;
          一個典型的實現(把名字是'change nappy'的任務交給NappyAssignmentHandler這個類來分配)
           
           
           
          NappyAssignmentHandler類:
          public void assign(Assignable assignable, ExecutionContext executionContext) {
          assignable.setActorId("papa");
          }
          同樣,Assignable只是一個接口,它有兩個方法:setActorId()和setPooledActors(),Assignable的具體實現類也是兩個
          swimlaneInstancehe和taskInstance。這樣就不不難理解整個任務分配流程了:
          1、流程進入TaskNode節點,執行TaskNode類的execute()方法,該方法首先獲得TaskMgmtInstance實例,然后通過它來創建TaskInstance。taskMgmtInstance.createTaskInstance(task, executionContext);
          2、在上面的createTaskInstance(task, executionContext)里,該方法調用了taskInstance.assign(executionContext)對taskInstance進行分配。
          3、在assign(executionContext)方法里,首先會判斷task屬性里是否存在swimlane,如果有的話,這個taskInstance就會分配給swimlane指定的ActorId或 PooledActors;如果不存在,再去找task屬性里 assignmentDelegation(分配代理類)通過代理類(即我們自己寫的實現AssignmentHandler這個接口的類)指定ActorId或 PooledActors。
          jbpm的用戶角色管理


          jbpm在用戶角色管理上共設計了四個類:Entity、 Membership、 Group、 User
          Entity類是其他三個類的父類,它包含了兩個屬性:name(String)、 permissions(Set)
          User類繼承Entity類,包含三個屬性:password(String)、 email(String)、 memberships(Set)
          Group類繼承Entity類,包含四個屬性: type(String) 、parent(Group)、 children(Set)、 memberships(Set)
          Membership類繼承Entity類,包含三個屬性:role(String)、 user(User)、 group(Group)
          很明顯,一個user對應一個用戶,一個group對應一個用戶組,它們之間通過membership關聯,并且一個user可以屬于多個不同類型(type)的group,user和 group之間是多對多的關系。
          Membership類的role屬性個人感覺用途不大,反倒是name屬性代表了user在group里的role(角色)!


          Generated by Bo-blog 2.0.2 RC 1

          posted on 2007-09-06 18:11 禮物 閱讀(943) 評論(0)  編輯  收藏 所屬分類: Jbpm
          主站蜘蛛池模板: 清镇市| 长汀县| 微博| 卢龙县| 安宁市| 山东省| 贡嘎县| 惠州市| 桐庐县| 荃湾区| 静宁县| 道孚县| 黑龙江省| 溧阳市| 田林县| 宁安市| 临湘市| 靖边县| 隆化县| 武城县| 桂东县| 凯里市| 庆城县| 石泉县| 类乌齐县| 五家渠市| 穆棱市| 杭锦旗| 塘沽区| 怀柔区| 鄂温| 昌都县| 西畴县| 沂源县| 城步| 衡山县| 旌德县| 楚雄市| 泽州县| 英吉沙县| 万宁市|