posts - 26,  comments - 7,  trackbacks - 0

          作者: JeffreyHsu


          盡管jbpm非常強大,是目前最適合商業化的開源工作流引擎,可以開發出復雜的流程,但是特別遺憾的是并不支持并發子流程(multiple-subprocess)
          有一次我需要做一個復雜的流程,主流程里要求同時啟動多個并發執行的子流程,并且子流程的數目和啟動的時間都不確定,當所有子流程都結束以后,主流程才繼續執行。我們知道jbpm里有子流程的設定,有專門的節點ProcessState來處理,但是后來發現無論如何也實現不了多子流程并發執行,后來看其源碼知道因為subprocess是作為ProcessState的一個屬性,也就是說ProcessState只能包含一個subprocess的定義,并且最重要的是processInstance.getRootToken()和子流程相關的只有createSubProcessInstance, getSubProcessInstance, setSubProcessInstance三個方法,這意味著主流程的rootToken只能設置一個子流程,jbpm并不直接支持多子流程。
          那么我們就必須用一個變通的方法來實現,“并發”很自然的讓我們想到了fork,但是這里的fork不能搭配join來使用,具體原因,將在后面討論。
          下面先給出流程圖:

          state節點用來啟動子流程(實際應用可以換成Task-Node),state進入fork后同時進入兩個分支,一條去啟動子流程,另一條回到自己,這樣表面看來state沒有動,而同時你又可以啟動第2個,第3個……子流程,需要注意的是第2條子流程和第1個子流程并不處于同一級上,而比第一個子流程低一級,具體請看后面一張圖就明白了,分解后的:

          從圖中我們可以看到后一個子流程的整棵樹是前一個子流程的兄弟,但是在業務級上是并發的效果,已經實現我們前面的需求。

          現在來說說為什么不能用join而直接用end,因為會產生一個問題,state3和sub process 2都到達了join以后,state2下面的fork就結束了,就會立刻越過join到達end,而sub process 1即使執行完畢到達了join卻仍然在傻傻等待著他的兄弟分支也到達join(而實際上它已經自跑到end去了)一同結束,這樣sub process 1就會永遠停在join動彈不得,業務無法進行。

          這是我的一個解決方案,但還有一個問題,雖然全部的子流程都能結束,主流程也能結束,但因為沒有join,主流程的rootToken仍然停留在fork節點上。目前我尚不知如何解決,希望各位大家能提出其他更好的解決辦法。
          初學jbpm,水平有限,有不當之處還請高手斧正

          最后附上demo代碼供參考:

          代碼
          1.   
          2. import static org.junit.Assert.*;   
          3.   
          4. import org.jbpm.graph.def.ProcessDefinition;   
          5. import org.jbpm.graph.exe.ProcessInstance;   
          6. import org.jbpm.graph.exe.Token;   
          7. import org.jbpm.graph.node.ProcessState;   
          8. import org.junit.Before;   
          9. import org.junit.Test;   
          10.   
          11. public class MultiProcessTest {   
          12.     private ProcessDefinition superProcessDefinition;   
          13.   
          14.     private ProcessDefinition subProcessDefinition;   
          15.   
          16.     @Before   
          17.     public void setUp() throws Exception {   
          18.         superProcessDefinition = ProcessDefinition.parseXmlString(   
          19.                 "<process-definition name='super'>" +                
          20.                 "  <start-state name='start'>" +   
          21.                 "    <transition to='state' />" +   
          22.                 "  start-state>" +   
          23.                 "  <state name='state'>" +   
          24.                 "    <transition name='create sub' to='fork' />" +   
          25.                 "    <transition name='end' to='end' />" +   
          26.                 "  state>" +   
          27.                 "  <fork name='fork'>" +   
          28.                 "    <transition name='back' to='state' />" +   
          29.                 "    <transition name='go to sub' to='sub process' />" +   
          30.                 "  fork>" +   
          31.                 "  <process-state name='sub process'>" +   
          32.                 "    <sub-process name='sub' />" +   
          33.                 "    <transition to='end' />" +   
          34.                 "  process-state>" +   
          35.                 "  <end-state name='end' />" +   
          36.                 "process-definition>");   
          37.            
          38.         subProcessDefinition = ProcessDefinition.parseXmlString(   
          39.                 "<process-definition name='sub'>" +                          
          40.                 "  <start-state name='start'>"  +   
          41.                 "    <transition to='wait' />" +   
          42.                 "  start-state>" +                         
          43.                 "  <state name='wait'>" +   
          44.                 "    <transition to='end' />" +   
          45.                 "  state>" +              
          46.                 "  <end-state name='end' />" +   
          47.                 "process-definition>");   
          48.         ProcessState processState = (ProcessState) superProcessDefinition   
          49.                 .getNode("sub process");   
          50.         processState.setSubProcessDefinition(subProcessDefinition);   
          51.     }   
          52.   
          53.     @Test   
          54.     public void testMultiProcesses() {   
          55.         ProcessInstance pi = new ProcessInstance(superProcessDefinition);   
          56.   
          57.         // 啟動一個主流程   
          58.         pi.signal();   
          59.         assertEquals("state", pi.getRootToken().getNode().getName());   
          60.   
          61.         // 進入分支,此處將進入子流程   
          62.         pi.signal("create sub");   
          63.         // 主流程token將停留在fork節點上   
          64.         assertEquals("fork", pi.getRootToken().getNode().getName());   
          65.   
          66.         // fork分為兩支,其中一支的節點停留在ProcessState上   
          67.         Token subProcessToken1 = pi.getRootToken().getChild("go to sub");   
          68.         ProcessInstance subPi1 = subProcessToken1.getSubProcessInstance();   
          69.         assertEquals("wait", subPi1.getRootToken().getNode().getName());   
          70.   
          71.         // 另一支返回了state節點,實際上并沒有返回,這個state節點不同于先前的state,它們并不在同一個path中   
          72.         Token stateToken1 = pi.getRootToken().getChild("back");   
          73.         assertEquals("state", stateToken1.getNode().getName());   
          74.            
          75.         // 再次進入fork,啟動第二個子流程   
          76.         stateToken1.signal("create sub");   
          77.         ProcessInstance subPi2 = stateToken1.getChild("go to sub")   
          78.                 .getSubProcessInstance();   
          79.         // 雖然都是子流程,但它們并不相同,在邏輯上是屬于并發的無關系的子流程   
          80.         assertFalse(subPi1.equals(subPi2));   
          81.         // 結束第二個子流程   
          82.         subPi2.signal();   
          83.         assertTrue(subPi2.hasEnded());   
          84.         assertFalse(pi.hasEnded());   
          85.   
          86.         // 結束第一個子流程,但主流程仍未結束   
          87.         subPi1.signal();   
          88.         assertTrue(subPi1.hasEnded());   
          89.         assertFalse(pi.hasEnded());   
          90.            
          91.         // 結束第二個子流程中的state,第一子流程的back分支結束,從而主流程也結束   
          92.         Token stateToken2 = stateToken1.getChild("back");   
          93.         assertEquals("state", stateToken2.getNode().getName());   
          94.         assertFalse(stateToken1.hasEnded());   
          95.         assertFalse(pi.hasEnded());   
          96.         stateToken2.signal("end");   
          97.            
          98.         assertTrue(stateToken1.hasEnded());   
          99.         assertTrue(subPi1.hasEnded());   
          100.         assertTrue(pi.getRootToken().getChild("back").hasEnded());   
          101.         assertTrue(pi.getRootToken().getChild("go to sub").hasEnded());   
          102.         // 主流程結束了   
          103.         assertTrue(pi.hasEnded());   
          104.         // 雖然主流程已經結束了,但是因為子流程沒有join,所以其rootToken仍然停留在fork上   
          105.         assertEquals("fork", pi.getRootToken().getNode().getName());   
          106.         // 第二個子流程到達的end和主流程中的end并不是同一個節點   
          107.         assertTrue(!pi.getRootToken().getNode().equals(stateToken2.getNode()));   
          108.     }   
          109. }   
          posted on 2007-09-11 17:48 jbpm 閱讀(1031) 評論(0)  編輯  收藏 所屬分類: jbpm深入研究

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 怀来县| 高清| 兴安盟| 石渠县| 封丘县| 聂拉木县| 元谋县| 灵川县| 黎平县| 荃湾区| 池州市| 弥勒县| 柞水县| 五家渠市| 颍上县| 密山市| 松原市| 句容市| 罗源县| 潍坊市| 商河县| 庐江县| 图木舒克市| 五峰| 区。| 江阴市| 景洪市| 青冈县| 湖南省| 佛学| 全椒县| 博白县| 华宁县| 太仆寺旗| 仁寿县| 札达县| 广元市| 吐鲁番市| 客服| 兴安盟| 镇沅|