posts - 26,  comments - 7,  trackbacks - 0

          作者: JeffreyHsu


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

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

          從圖中我們可以看到后一個子流程的整棵樹是前一個子流程的兄弟,但是在業(yè)務(wù)級上是并發(fā)的效果,已經(jīng)實(shí)現(xiàn)我們前面的需求。

          現(xiàn)在來說說為什么不能用join而直接用end,因?yàn)闀a(chǎn)生一個問題,state3和sub process 2都到達(dá)了join以后,state2下面的fork就結(jié)束了,就會立刻越過join到達(dá)end,而sub process 1即使執(zhí)行完畢到達(dá)了join卻仍然在傻傻等待著他的兄弟分支也到達(dá)join(而實(shí)際上它已經(jīng)自跑到end去了)一同結(jié)束,這樣sub process 1就會永遠(yuǎn)停在join動彈不得,業(yè)務(wù)無法進(jìn)行。

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

          最后附上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.         // 進(jìn)入分支,此處將進(jìn)入子流程   
          62.         pi.signal("create sub");   
          63.         // 主流程token將停留在fork節(jié)點(diǎn)上   
          64.         assertEquals("fork", pi.getRootToken().getNode().getName());   
          65.   
          66.         // fork分為兩支,其中一支的節(jié)點(diǎn)停留在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節(jié)點(diǎn),實(shí)際上并沒有返回,這個state節(jié)點(diǎn)不同于先前的state,它們并不在同一個path中   
          72.         Token stateToken1 = pi.getRootToken().getChild("back");   
          73.         assertEquals("state", stateToken1.getNode().getName());   
          74.            
          75.         // 再次進(jìn)入fork,啟動第二個子流程   
          76.         stateToken1.signal("create sub");   
          77.         ProcessInstance subPi2 = stateToken1.getChild("go to sub")   
          78.                 .getSubProcessInstance();   
          79.         // 雖然都是子流程,但它們并不相同,在邏輯上是屬于并發(fā)的無關(guān)系的子流程   
          80.         assertFalse(subPi1.equals(subPi2));   
          81.         // 結(jié)束第二個子流程   
          82.         subPi2.signal();   
          83.         assertTrue(subPi2.hasEnded());   
          84.         assertFalse(pi.hasEnded());   
          85.   
          86.         // 結(jié)束第一個子流程,但主流程仍未結(jié)束   
          87.         subPi1.signal();   
          88.         assertTrue(subPi1.hasEnded());   
          89.         assertFalse(pi.hasEnded());   
          90.            
          91.         // 結(jié)束第二個子流程中的state,第一子流程的back分支結(jié)束,從而主流程也結(jié)束   
          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.         // 主流程結(jié)束了   
          103.         assertTrue(pi.hasEnded());   
          104.         // 雖然主流程已經(jīng)結(jié)束了,但是因?yàn)樽恿鞒虥]有join,所以其rootToken仍然停留在fork上   
          105.         assertEquals("fork", pi.getRootToken().getNode().getName());   
          106.         // 第二個子流程到達(dá)的end和主流程中的end并不是同一個節(jié)點(diǎn)   
          107.         assertTrue(!pi.getRootToken().getNode().equals(stateToken2.getNode()));   
          108.     }   
          109. }   
          posted on 2007-09-11 17:48 jbpm 閱讀(1025) 評論(0)  編輯  收藏 所屬分類: jbpm深入研究

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


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 手游| 保山市| 河西区| 大城县| 中江县| 招远市| 横山县| 柳林县| 阳城县| 玉溪市| 手机| 清镇市| 嘉兴市| 石城县| 磐石市| 土默特右旗| 剑阁县| 江山市| 阳高县| 宁乡县| 琼结县| 普兰店市| 马尔康县| 阿拉善左旗| 保定市| 上高县| 西藏| 虎林市| 江达县| 廊坊市| 嘉兴市| 云霄县| 确山县| 河间市| 呼伦贝尔市| 汝南县| 漳州市| 长汀县| 鄂托克旗| 通道| 城市|