一個Jbpm員工請假流程的實例

一個Jbpm員工請假流程的實例

 

 

作者:吳大愚

Email:[email protected]

2006-10-26

 

 

適用於jbpm3.1版本

1.   概述

此實例包括的是一個員工請假審批的流程實例,和流程相關的代碼以及相應的測試代碼。此流程在Eclipse3.1.2 ,JBoss-IDE 1.6環境下測試通過。

說明,這篇文章說使用的流程實例是,學習《一個JBPM工作流管理示例》文章中的流程而來。原文中的流程實例不是jbpm3.1版本,不能適用於jbpm3.1。本人將其改寫,並加入自己的設計和實現。原文地址爲http://blogger.org.cn/blog/more.asp?name=lhwork&id=16137。可以對照學習。

2.   流程說明

假設應用背景如下:

在某一公司中,部門員工要休假的話需要部門主管的批准。如果休假天數大於10天的話,在部門主管的同意後,還必須老闆批准。如果是部門主管要休假只要老闆批准即可。在休假被批准之前,申請人可以撤銷休假申請。

每次休假申請結束之後,不管通過未通過或是否取消,都必須記錄下來。主管在批覆申請之後,系統要將批覆結果Email給申請人。對於大於10天的申請,如果部門主管已批准同意而上級主管還未批准,這時申請人撤銷申請後,系統應發Email通知部門主管申請已撤銷。 

3.   流程定義

3.1. 原文件

<?xml version="1.0" encoding="UTF-8"?>

<process-definition

  xmlns="urn:jbpm.org:jpdl-3.1"  name="MyRequest">

   <start-state name="SS_Request">

 

      <transition name="" to="TN_WriteRequest"></transition>

   </start-state>

   <task-node name="TN_WriteRequest">

      <task name="Task_WriteRequest">

         <controller>

            <variable name="dayCount" access="read,write,required"></variable>

         </controller>

         <assignment class="com.myrequest.task.WriteRequestAssignmentHandler"></assignment>

      </task>

      <transition name="Tr_WriteLeave" to="Fork_request">

         <action name="Ac_WriteLeave" class="com.myrequest.action.WriteLeaveActionHandler"></action>

      </transition>

   </task-node>

   <fork name="Fork_request">

      <transition name="Tr_Cancel" to="TN_RequesterCancel"></transition>

      <transition name="Tr_Request" to="Deci_IsChiefHere">

         <action name="Ac_GetChiefState" class="com.myrequest.action.GetChiefStateActionHandler"></action>

      </transition>

   </fork>

   <decision name="Deci_IsChiefHere">

      <handler class="com.myrequest.decision.IsChiefHereDecisionHandler"/>

      <transition name="Tr_Chief" to="TN_ChiefDecide"></transition>

      <transition name="Tr_Boss" to="TN_BossDecide"></transition>

   </decision>

   <task-node name="TN_RequesterCancel">

      <task name="Task_CancelRequest">

         <assignment class="com.myrequest.task.CancelRequestAssignmentHandler"></assignment>

      </task>

      <transition name="Tr_RequestCancel" to="Join_Request">

         <action name="Ac_RequestCancel" class="com.myrequest.action.RequestCancelActionHandler"></action>

      </transition>

   </task-node>

   <task-node name="TN_ChiefDecide">

      <task name="Task_ChiefDecide">

         <assignment class="com.myrequest.task.ChiefDecideAssignmentHandler"></assignment>

      </task>

      <transition name="Tr_ChiefApprove" to="Deci_NeedBossDecide">

         <action name="Ac_ChiefApprove" class="com.myrequest.action.ChiefApproveActionHandler"></action>

      </transition>

      <transition name="Tr_ChiefNotApprove" to="Join_Request">

         <action name="Ac_ChiefNotApprove" class="com.myrequest.action.ChiefNotApproveActionHandler"></action>

      </transition>

   </task-node>

   <join name="Join_Request">

      <transition name="Tr_Join" to="Deci_DoSomething"></transition>

   </join>

   <decision name="Deci_NeedBossDecide">

      <handler class="com.myrequest.decision.NeedBossDecideDecisionHandler"/>     

      <transition name="Tr_Need" to="TN_BossDecide"></transition>

      <transition name="Tr_NotNeed" to="Join_Request">

         <action name="Ac_NotNeed" class="com.myrequest.action.NotNeedActionHandler"></action>

      </transition>

   </decision>

   <task-node name="TN_BossDecide">

      <task name="Task_BossDecide">

         <assignment class="com.myrequest.task.BossDecideAssignmentHandler"></assignment>

      </task>

      <transition name="Tr_BossApprove" to="Join_Request">

         <action name="Ac_BossApprove" class="com.myrequest.action.BossApproveActionHandler"></action>

      </transition>

      <transition name="Tr_BossNotApprove" to="Join_Request">

         <action name="Ac_BossNotApprove" class="com.myrequest.action.BossNotApproveActionHandler"></action>

      </transition>

   </task-node>

   <decision name="Deci_DoSomething">

       <handler class="com.myrequest.decision.DoSomethingDecisionHandler"/>

      <transition name="Tr_Approve" to="ES_Finished">

         <action name="Ac_Approve" class="com.myrequest.action.ApproveActionHandler"></action>

      </transition>

      <transition name="Tr_NotApprove" to="ES_Finished">

         <action name="Ac_NotApprove" class="com.myrequest.action.NotApproveActionHandler"></action>

      </transition>

      <transition name="Tr_Cancel" to="ES_Finished">

         <action name="Ac_Cancel" class="com.myrequest.action.CancelActionHandler"></action>

      </transition>

   </decision>

   <end-state name="ES_Finished">

                     <event type="node-enter">

                            <action name="Ac_Finished" class="com.myrequest.action.FinishedActionHandler"></action>

                     </event>

   </end-state>

</process-definition>

3.2. 流程圖片

3.3. 說明

3.3.1.    命名規則

start-state的定義爲SS_

end-state的定義爲ES_

task-node的定義爲TN_

fork的定義爲Fork_

join的定義爲Join_

task的定義爲Task_

transition的定義爲Tr_

action的定義爲Ac_

3.3.2.    join節點類型

join結點Join_Request,採用的是Discriminator模式,即只要有一個fork發出的分支到達join,流程就可以向下進行。

Join共有三中模式:

l         默認的是所有fork發出的分支都到達,流程才向下進行;

l         第二種就是Discriminator模式,只要有一個fork發出的分支到達join,流程就可以向下進行;

l         第三種是設置當有n個分支到達之後,流程就可以向下進行。

jpdl語言在jbpm3.1版本中還不支持對第二,第三兩種模式的設置。需要在流程實例化之後,來制定join的模式。具體如何實現,參見後面有關代碼部分。

3.3.3.    申請狀態

系統存在一個有關申請的狀態。系統用流程變量RequestState來存儲。共有五個狀態。存儲在com.myrequest.RequestState.java文件中。

在用戶啓動此請假流程,完成第一個填寫請假申請的任務實例後,此狀態置爲REQUEST。在完成取消請求任務之後,狀態改爲CANCEL。等等,讀者可以仔細閱讀流程定義和對應的代碼。

要說明的是所有的狀態修改都在完成任務之後的邊上執行Action中來修改的。這樣雖然增加了很多Action,但是狀態修改明確。但對於這樣的簡單問題,前臺代碼在實際任務完整之後,就可以調用修改此狀態變量。此處將這些修改都放在Action裏面,也有一定演示的含義。

3.3.4.    取消請假任務說明

fork節點後,產生兩個並行分支。其中一個TN_RequestCancel任務節點包含一個Task_CancelRequest的任務。當此分支執行到這裏時,會把這個任務分配給啓動流程的用戶。在流程沒有結束的時候,如果用戶執行這個任務,就表示用戶要取消請假申請。在這個取消申請的任務會修改請假狀態,在此任務結束後,就會首先到達join節點。表示取消了此次申請操作。

4.   代碼說明

4.1. 代碼包結構

本實例是在Eclipse3.1.2裏面實現的。

src/java目錄下面,有包:

l         com.myrequest

n         存放流程的公共信息,包括:

n         interface RequestState,用來存放請求狀態的5種狀態

n         interface RequestVariable 存放流程實例的變量名

l         com.myrequest.action

n         存放流程中所有的ActionHandler

n         共有12個類,每個類對應流程中一個action的代碼。

l         com.myrequest.task

n         存放流程中所有的taskAssignmentHandler分配類

n         共有4個類,對應4task

l         com.myrequest.decision

n         存放流程中所有的decision節點的判斷類

n         包括3個類,對應3Decision節點

src/test目錄下面,有包:

l         com.myrequest

n         包含此流程的測試類 MyRequestProcessTest.java

processes目錄下面,有:

l         流程定義文件夾MyRequest,包含:

n         Gpd.xml

n         Processdefinition.xml

n         Processimage.jpg

4.2. 流程代碼說明

對流程中使用到的和Actiontaskdecision相關的類,以及測試類進行說明。

4.2.1.    Action代碼說明

流程中的Action都使用指定類的形式來完成Action的操作。

例如:

<transition name="Tr_WriteLeave" to="Fork_request">

<action name="Ac_WriteLeave" class="com.myrequest.action.WriteLeaveActionHandler"></action>

</transition>

當流程執行到邊Tr_WriteLeave後,就會自動去執行Action裏面指定的類WriteLeaveActionHandler

WriteLeaveActionHandler實現了接口ActionHandler。此接口就一個函數

public void execute(ExecutionContext executionContext)

當流程執行這個類的時候,就會去調用這個函數。所以我們Action所要完成的工作也都寫在這個函數中。

RequestBeginActionHandler.execute()中,我們只做了將整個流程的請求狀態設置爲REQEUST狀態。

4.2.2.    Task代碼說明

所有Task都是在Task-node中描述的。Task都是人工任務,也就是說需要先將task分配給那個人,然後由這個人來完成。在人開始任務的時候,可以調用taskInstancestart()操作,表明任務開始。(start()操作是可選的,也可以不調用) 在任務結束後,可以調用taskInstanceend()操作,表示任務實例結束。如果是整個task-node中的最後一個taskend()操作,那麼就會這個end操作就會觸發流程繼續向下走。

例如:

<task name="Task_WriteRequest">

<controller>

   <variable name="dayCount" access="read,write,required"></variable>

</controller>

<assignment class="com.myrequest.task.WriteRequestAssignmentHandler"></assignment>

</task>

當流程實例化Task_WriteRequest這個task後,首先會使用WriteRequestAssignmentHandler類來進行任務的分配。WriteRequestAssignmentHandler類實現了AssignmentHandler接口,包含一個
public void assign(Assignable assignable, ExecutionContext executionContext)
接口。其中參數assignable就是此任務實例的引用(TaskInstance實現了Assignable接口)。因此我們只要調用assignable.setActorId(String userid),就可以把這個任務分配給userid所代表的用戶來執行了。

    對於前臺,當用戶登陸後,通過org.jbpm.db.TaskMgmtSession.findTaskInstances(java.lang.String actorId)就可以得到當前用戶所有要執行的任務了,這裏的任務是屬於多個不同的流程實例的。如果查看數據庫就會發現在jbpm_taskInstance表中,每一個taskinstanceactorId_字段記錄的是次任務實例分配人員的用戶名。這也就是上面所說的findTaskInstances方法如何工作的關鍵之處。

WriteRequestAssignmentHandler .assign()裏面,我們首先讀入流程變量userId,然後將任務分配給這個userId
    如何調用任務實例的end,來表示任務實例的完成呢?真正的系統中應該是在前臺,當客戶通過web或是客戶端觸發操作,然後執行對應的任務實例的end操作。但是在我們的代碼中只能通過在junit的測試代碼中來模擬。具體參見後面講解測試代碼部分。

4.2.3.    Decision代碼說明

Decision節點可以有多種方式來進行條件判斷。

方法一是在每條出邊上加一個beanshell的表達式,jbpm引擎會按照流程定義文檔中邊的順序一次調用,來判斷那個表達式爲true,當發現第一個爲true的時候,流程就走這條邊了。

方法二就是對Decision節點配置一個handler。通過一個類來實現條件判斷。

 

例如:

   <decision name="Deci_IsChiefHere">

      <handler class="com.myrequest.decision.IsChiefHereDecisionHandler"/>

      <transition name="Tr_Chief" to="TN_ChiefDecide"></transition>

      <transition name="Tr_Boss" to="TN_BossDecide"></transition>

   </decision>

表示當執行到Deci_IsChiefHere節點後,會自動執行IsChiefHereDecisionHandler類。IsChiefHereDecisionHandler實現了DecisionHandler接口。此接口包含一個方法public String decide(ExecutionContext executionContext) throws Exception 這個方法應該返回一個transitionname,表示選擇走那條邊。

IsChiefHereDecisionHandler.decide()操作中,我們首先讀取流程變量isChiefHere,然後判斷走那條邊。

4.3. 流程測試類代碼說明

4.3.1.    測試類整體說明

測試類爲com.myrequest. MyRequestProcessTest

包含三個設施函數,分別爲

l         test14DayAndBossNotApprove()

n         測試員工申請14天假期,部門主管批准,但老闆不批准

l         test4DayAndChiefApprove()

n         測試員工申請14天假期,部門主管批准,(不需要老闆批准)

l         test14DayAndChiefApproveAndUserCancel()

n         測試員工申請14天假期,部門主管批准,在老闆審批前員工自己撤銷申請

 

每個測試前都執行setUp()操作,這個操作用來設置流程中兩個變量,一個是用戶id,另外一個是部門主管是否在崗的狀態。可以修改這兩個參數,進行不同的測試。尤其是第二個參數,會影響流程的走向,可以分別設置爲truefalse以觀察流程的走向和結果。

 

在測試類中還有7個輔助函數。分別爲:

l         deployProcessDefinition()

n         流程部署

l         createProcessInstance()

n         創建流程實例

n         設置join節點的性質爲Discriminator模式(參見流程定義部分)

n         設置流程相關變量

n         啓動流程

l         userWriteRequest(int daycount)

n         模擬申請員工完成Task_WriteRequest任務,參數爲請假的天數

l         chiefDecide(boolean isApprove)

n         模擬部門主管完成Task_ ChiefDecide任務,參數爲部門主管是否批准

l         bossDecide(boolean isApprove)

n         模擬老闆完成Task_ BossDecide任務,參數爲老闆是否批准

l         userCancel()

n         模擬申請員工完成Task_ CancelRequest任務

l         checkTasks()

n         檢查整個流程中所有的任務的相關信息

4.3.2.    checkTasks()說明

checkTasks()的核心是pi.getTaskMgmtInstance().getTaskInstances();返回流程實例的所有任務實例列表。但要說明的是所返回的任務實例列表和當前流程執行的位置有關,在流程開始處,流程執行中間,和流程執行結束處調用得到的任務實例列表不同。列表包含已經完成的任務實例和當前任務實例。

本來在此方法中還有現實每個任務實例起始時間和結束時間的操作。但發現返回全部爲null。這說明在沒有使用數據庫是,有關時間的屬性是不可用的。也就是說,這些時間屬性都是記錄在數據庫jbpm_taskInstance表中的。沒有用數據庫自然就得不到,它不會保留在內存的流程實例中。要說明的是jbpm_taskInstance表的start字段如果有時間,表示任務實例已經開始執行。如果end字段有時間,表示任務實例已經結束,此任務已經完成。

4.3.3.    測試中有關任務實例獲取的說明

因爲沒有使用數據庫,所以不能使用org.jbpm.db.TaskMgmtSession.findTaskInstances(java.lang.String actorId)得到不同用戶的當前任務。所以只能便利當前流程實例任務列表,從中找到相應的任務來操作。

如果有人有更好的辦法,請留言告知,謝謝:)

5.   實例不足和待學習地方

5.1. 不足

沒有使用swimlane,可以添加swimlane來進行任務分配。像websale就是有角色的。主要的原因是對swimlane的使用我還沒有搞清楚。我有關swimlane的學習心得會在下一篇對jbpm自帶實例websale的分析中來描述。

5.2. 學習點

    通過這個實例,我發現org.jbpm.module.exe.ModuleInstance類有很多創建任務實例的方法,例如createTaskInstance(Task task)等等。我一直認爲任務的實例化是在流程執行過程中,又工作流引擎來做的工作。不知道在我們寫的代碼中需要用到創建流程這樣的方法嗎?如果要用的話,在什麼情況下會用到呢?

       

       此外還有很多問題沒有搞懂,比如jbpm的模塊化思想,它的Ioc實現等等。慢慢學習吧。

6.   完整代碼

代碼太多,貼還是不貼呢,這是個問題啊。

 

6.1. MyRequestProcessTest

package com.myrequest;

 

import org.jbpm.graph.node.*;

import java.io.FileInputStream;

import java.util.*;

 

import org.jbpm.graph.def.ProcessDefinition;

import org.jbpm.graph.exe.ProcessInstance;

import org.jbpm.taskmgmt.*;

import org.jbpm.identity.*;

import org.jbpm.context.exe.ContextInstance;

import org.jbpm.taskmgmt.exe.*;

 

import junit.framework.TestCase;

 

import com.myrequest.*;

 

 

public class MyRequestProcessTest extends TestCase {

       //static JbpmConfiguration cfg = JbpmConfiguration.getInstance();

       ProcessDefinition pdf ;

       ProcessInstance pi;      

       String userId;

       boolean isChiefHere;

      

       public void setUp(){

              userId = "dust";

              isChiefHere=true;

       }

       public void test14DayAndBossNotApprove() throws Exception {            

              this.deployProcessDefinition() ;

              this.createProcessInstance() ;

              this.userWriteRequest(14) ;

              this.chiefDecide(true) ;

              this.bossDecide(false);

              this.checkTasks();        

       }

       public void test4DayAndChiefApprove() throws Exception {            

              this.deployProcessDefinition() ;

              this.createProcessInstance() ;

              this.userWriteRequest(4) ;

              this.chiefDecide(true) ;

              this.checkTasks();        

       }

       public void test14DayAndChiefApproveAndUserCancel() throws Exception {         

              this.deployProcessDefinition() ;

              this.createProcessInstance() ;

              this.userWriteRequest(14) ;

              this.chiefDecide(true) ;

              this.userCancel();

              this.checkTasks();        

       }

      

       protected void deployProcessDefinition() throws Exception{

             

              System.out.println("==MyRequestProcessTest.deployProcessDefinition()==");

              FileInputStream fis = new FileInputStream("processes/MyRequest/processdefinition.xml");

              pdf = ProcessDefinition.parseXmlInputStream(fis);

              assertNotNull("Definition should not be null", pdf);       

       }

 

       protected void createProcessInstance() throws Exception{

              System.out.println("==MyRequestProcessTest.createProcessInstance()==");

              assertNotNull("Definition should not be null", pdf);

              pi = new ProcessInstance(pdf);

              assertNotNull("processInstance should not be null", pi);

             

              Join join_Request = (Join)pi.getProcessDefinition().getNode("Join_Request");

              assertNotNull("should find join_request node !",join_Request);

              join_Request.setDiscriminator( true);

              //設置申請人

              pi.getContextInstance() .createVariable(RequestVariable.userId,this.userId);

              //設置流程運行是,部門主管是否在崗

              pi.getContextInstance() .createVariable(RequestVariable.isChiefHere,new Boolean(this.isChiefHere));

              //啓動流程

              pi.getRootToken().signal();   

             

       }

       /**

        * @param daycount  請假天數

        * */

       protected void userWriteRequest(int daycount){

              System.out.println("==MyRequestProcessTest.userWriteRequest()==");

              TaskInstance wr = (TaskInstance)pi.getTaskMgmtInstance().getTaskInstances().iterator() .next() ;

              assertEquals(this.userId,wr.getActorId()) ;

              ContextInstance ci = pi.getContextInstance();

              ci.setVariable("dayCount",new Integer(daycount));

              wr.end();

       }

       /**

        * @param isApprove 部門主管是否同意請假

        * */

       protected void chiefDecide(boolean isApprove){

              System.out.println("==MyRequestProcessTest.chiefDecide()==");

              //String chiefId="today123";

              /**

               * 如果後臺使用數據庫的話,就可以使用

               * org.jbpm.db.TaskMgmtSession.findTaskInstances(java.lang.String actorId) 得到所有分配給chiefIdtaskInstance

               * */

              Collection coll = pi.getTaskMgmtInstance().getTaskInstances();

              Iterator it = coll.iterator();

              while(it.hasNext()){

                     TaskInstance ti = (TaskInstance)it.next();

                     if(ti.getName().equals("Task_ChiefDecide")){

                            assertEquals("today123",ti.getActorId());

                            if(isApprove)

                                   ti.end("Tr_ChiefApprove");

                            else

                                   ti.end("Tr_ChiefNotApprove");

                            return;

                     }

              }

             

       }

      

       /**

        * @param isApprove 老闆是否同意請假

        * */

       protected void bossDecide(boolean isApprove){

              System.out.println("==MyRequestProcessTest.bossDecide()==");

              //String bossId="elena";

              /**

               * 如果後臺使用數據庫的話,就可以使用

               * org.jbpm.db.TaskMgmtSession.findTaskInstances(java.lang.String actorId) 得到所有分配給bossIdtaskInstance

               * */      

              Collection coll = pi.getTaskMgmtInstance().getTaskInstances();

              Iterator it = coll.iterator();

              while(it.hasNext()){

                     TaskInstance ti = (TaskInstance)it.next();

                     if(ti.getName().equals("Task_BossDecide")){

                            assertEquals("elena",ti.getActorId());

                            if(isApprove)

                                   ti.end("Tr_BossApprove");

                            else

                                   ti.end("Tr_BossNotApprove");

                            return;

                     }

              }

       }

       protected void userCancel(){

              System.out.println("==MyRequestProcessTest.userCancel()==");

              /**

               * 如果後臺使用數據庫的話,就可以使用

               * org.jbpm.db.TaskMgmtSession.findTaskInstances(java.lang.String actorId) 得到所有分配給useridtaskInstance

               * */      

              Collection coll = pi.getTaskMgmtInstance().getTaskInstances();

              Iterator it = coll.iterator();

              while(it.hasNext()){

                     TaskInstance ti = (TaskInstance)it.next();

                     if(ti.getName().equals("Task_CancelRequest")){

                            assertEquals(this.userId,ti.getActorId());

                            ti.end();

                            return;

                     }

              }

       }

      

       protected void checkTasks(){      

              System.out.println("==MyRequestProcessTest.checkTasks()==");

              Collection coll = pi.getTaskMgmtInstance().getTaskInstances();

              Iterator it = coll.iterator();

              System.out.println("====Process has task:====");

              while(it.hasNext()){

                     TaskInstance ti = (TaskInstance)it.next();

                     System.out.println("=="+ti.getName()+"==");

                     System.out.println("=="+ti.getActorId()+"==");

                     System.out.println("=="+ti.getVariables().toString() +"==");

              }

              System.out.println("====end====");  

       }    

}

6.2. ApproveActionHandler

package com.myrequest.action;

 

import org.jbpm.graph.def.ActionHandler;

import org.jbpm.graph.exe.ExecutionContext;

 

import com.myrequest.*;

 

public class ApproveActionHandler implements ActionHandler {

 

       public void execute(ExecutionContext executionContext) throws Exception {

              // TODO Auto-generated method stub

             

              System.out.println("==ApproveActionHandler.execute()==");

              String user =(String)executionContext.getContextInstance().getVariable(RequestVariable.userId);

              int dayCount = ((Integer)executionContext.getContextInstance().getVariable(RequestVariable.dayCount)).intValue();

              /**

               * 發送郵件給申請人user,告知其請假被批准。

               *

               * */

              System.out.println("==發送郵件給"+user+",告知其"+dayCount+"天的請假申請,已經被批准。==");

       }    

}

6.3. BossApproveActionHandler

package com.myrequest.action;

 

import org.jbpm.graph.def.ActionHandler;

import org.jbpm.graph.exe.ExecutionContext;

import com.myrequest.*;

public class BossApproveActionHandler implements ActionHandler {

 

       public void execute(ExecutionContext executionContext) throws Exception {

              // TODO Auto-generated method stub

              executionContext.getContextInstance().setVariable(RequestVariable.requestState,RequestState.APPROVE );

              System.out.println("==BossApproveActionHandler.execute()==");

       }

 

}

6.4. BossNotApproveActionHandler

package com.myrequest.action;

 

import org.jbpm.graph.def.ActionHandler;

import org.jbpm.graph.exe.ExecutionContext;

import com.myrequest.*;

public class BossNotApproveActionHandler implements ActionHandler {

 

       public void execute(ExecutionContext executionContext) throws Exception {

              // TODO Auto-generated method stub

              executionContext.getContextInstance().setVariable(RequestVariable.requestState,RequestState.DISAPPROVE );

              System.out.println("==BossNotApproveActionHandler.execute()==");

       }

 

}

6.5. CancelActionHandler

package com.myrequest.action;

 

import org.jbpm.graph.def.ActionHandler;

import org.jbpm.graph.exe.ExecutionContext;

 

import com.myrequest.RequestVariable;

import com.myrequest.*;

public class CancelActionHandler implements ActionHandler {

 

       public void execute(ExecutionContext executionContext) throws Exception {

              // TODO Auto-generated method stub

              System.out.println("==CancelActionHandler.execute()==");

              String user =(String)executionContext.getContextInstance().getVariable(RequestVariable.userId);

              //如果取消的時候,部門主管已經批准過,那麼需要給部門主管發送郵件,通知其請假已經取消

              if(executionContext.getContextInstance().hasVariable(RequestVariable.isChiefHere) && ((Boolean)executionContext.getContextInstance().getVariable(RequestVariable.isChiefHere)).booleanValue()){

                     int dayCount = ((Integer)executionContext.getContextInstance().getVariable(RequestVariable.dayCount)).intValue();

              //通過user找到對應的chief

              /**

               * 發送郵件給chief,告知其請假被批准。

               *

               * */

              System.out.println("==發送郵件給部門主管,告知其部門員工"+user+""+dayCount+"天請假申請,已經取消。==");

              }

       }

}

6.6. ChiefApproveActionHandler

package com.myrequest.action;

 

import org.jbpm.graph.def.ActionHandler;

import org.jbpm.graph.exe.ExecutionContext;

 

import com.myrequest.RequestState;

import com.myrequest.RequestVariable;

import com.myrequest.*;

public class ChiefApproveActionHandler implements ActionHandler {

 

       public void execute(ExecutionContext executionContext) throws Exception {

              // TODO Auto-generated method stub

              executionContext.getContextInstance().setVariable(RequestVariable.requestState,RequestState.CHIEFAPPROVE );

              System.out.println("==ChiefApproveActionHandler.execute()==");

 

       }

 

}

6.7. ChiefNotApproveActionHandler

package com.myrequest.action;

 

import org.jbpm.graph.def.ActionHandler;

import org.jbpm.graph.exe.ExecutionContext;

import com.myrequest.*;

public class ChiefNotApproveActionHandler implements ActionHandler {

 

       public void execute(ExecutionContext executionContext) throws Exception {

              // TODO Auto-generated method stub

              executionContext.getContextInstance().setVariable(RequestVariable.requestState,RequestState.DISAPPROVE );

              System.out.println("==ChiefNotApproveActionHandler.execute()==");

 

       }

 

}

6.8. FinishedActionHandler

package com.myrequest.action;

 

import org.jbpm.graph.def.ActionHandler;

import org.jbpm.graph.exe.ExecutionContext;

 

import com.myrequest.*;

 

public class FinishedActionHandler implements ActionHandler {

 

       public void execute(ExecutionContext executionContext) throws Exception {

              System.out.println("==FinishedActionHandler.execute()==");

              String user = (String)executionContext.getContextInstance().getVariable( RequestVariable.userId);

              Integer dayCount = (Integer)executionContext.getContextInstance().getVariable( RequestVariable.dayCount);

              String requestState = (String)executionContext.getContextInstance().getVariable( RequestVariable.requestState);

             

              /**

               * 將上述信息進行記錄,保存每一次員工請假的信息,無論是否批准還是取消請求

               *

               * */

              System.out.print("==在系統中記錄:"+user+",申請請假"+dayCount+"天,");

              if(requestState.compareTo(RequestState.APPROVE)==0)

                     System.out.print("被批准。");

              else if(requestState.compareTo(RequestState.DISAPPROVE)==0)

                     System.out.print("未被批准。");

              else if(requestState.compareTo(RequestState.CANCLE)==0)

                     System.out.print("已取消。");

              else{                    

                     System.out.println("");

                     System.out.println("====系統出現問題,最終申請狀態爲:"+requestState+"====");

                     System.out.println("");

              }

             

              System.out.println("==");

 

       }

 

}

6.9. NotApproveActionHandler

package com.myrequest.action;

 

import org.jbpm.graph.def.ActionHandler;

import org.jbpm.graph.exe.ExecutionContext;

 

import com.myrequest.RequestVariable;

 

public class NotApproveActionHandler implements ActionHandler {

 

       public void execute(ExecutionContext executionContext) throws Exception {

              // TODO Auto-generated method stub

              System.out.println("==NotApproveActionHandler.execute()==");

              String user =(String)executionContext.getContextInstance().getVariable(RequestVariable.userId);

              int dayCount = ((Integer)executionContext.getContextInstance().getVariable(RequestVariable.dayCount)).intValue();

             

              /**

               * 發送郵件給申請人user,告知其請假沒有被批准。

               *

               * */

              System.out.println("==發送郵件給"+user+",告知其"+dayCount+"天的請假申請,沒有被批准。==");

       }

 

}

6.10.    NotNeedActionHandler

package com.myrequest.action;

 

import org.jbpm.graph.def.ActionHandler;

import org.jbpm.graph.exe.ExecutionContext;

import com.myrequest.*;

public class NotNeedActionHandler implements ActionHandler {

 

       public void execute(ExecutionContext executionContext) throws Exception {

              // TODO Auto-generated method stub

              executionContext.getContextInstance().setVariable(RequestVariable.requestState,RequestState.APPROVE );

              System.out.println("==NotNeedActionHandler.execute()==");

       }

 

}

6.11.    RequestCancelActionHandler

package com.myrequest.action;

 

import org.jbpm.graph.def.ActionHandler;

import org.jbpm.graph.exe.ExecutionContext;

import com.myrequest.*;

public class RequestCancelActionHandler implements ActionHandler {

 

       public void execute(ExecutionContext executionContext) throws Exception {

              // TODO Auto-generated method stub

              String requestState = (String)executionContext.getContextInstance().getVariable(RequestVariable.requestState);

             

              //只有兩種狀態下允許撤銷

              if(requestState.compareTo(RequestState.REQEUST)==0 || requestState.compareTo(RequestState.CHIEFAPPROVE)==0 ){

                    

                     //如果撤銷請求的時候,請求狀態爲“部門主管批准”狀態

                     if(requestState.compareTo(RequestState.CHIEFAPPROVE)==0){

                            executionContext.getContextInstance().createVariable(RequestVariable.isChiefHere,new Boolean(true));

                     }                  

                     executionContext.getContextInstance().setVariable(RequestVariable.requestState,RequestState.CANCLE );

              }

              else{

                     System.out.println("==can't canel request==");

              }

             

              System.out.println("==RequestCancelActionHandler.execute()==");

       }

 

}

6.12.    WriteLeaveActionHandler

package com.myrequest.action;

 

import org.jbpm.graph.def.ActionHandler;

import org.jbpm.graph.exe.ExecutionContext;

 

import com.myrequest.RequestState;

import com.myrequest.RequestVariable;

import com.myrequest.*;

 

public class WriteLeaveActionHandler implements ActionHandler {

 

       /**

        * 設置請假狀態爲請求

        * */

       public void execute(ExecutionContext executionContext) throws Exception {

              // TODO Auto-generated method stub

              //設置請求狀態爲請求

              executionContext.getContextInstance().createVariable(RequestVariable.requestState,RequestState.REQEUST);

              System.out.println("==RequestBeginActionHandler.execute()==");

       }

 

}

6.13.    DoSomethingDecisionHandler

package com.myrequest.decision;

 

import org.jbpm.graph.exe.ExecutionContext;

import org.jbpm.graph.node.DecisionHandler;

import com.myrequest.*;

public class DoSomethingDecisionHandler implements DecisionHandler {

 

      

       public String decide(ExecutionContext executionContext) throws Exception {

 

             

              String requestState = (String)executionContext.getContextInstance().getVariable(RequestVariable.requestState);

              if(requestState.compareTo(RequestState.APPROVE)==0){

                     return "Tr_Approve";

              }

              else if(requestState.compareTo(RequestState.DISAPPROVE)==0){

                     return "Tr_NotApprove";

              }

              else if(requestState.compareTo(RequestState.CANCLE)==0){

                     return "Tr_Cancel";

              }    

              else{

                    

                     System.out.println("==狀態不對==");

                     throw new Exception("到達的狀態不對,爲:"+requestState);

              }

       }

 

}

6.14.    IsChiefHereDecisionHandler

package com.myrequest.decision;

 

import org.jbpm.graph.exe.ExecutionContext;

import org.jbpm.graph.node.DecisionHandler;

 

import com.myrequest.RequestVariable;

 

public class IsChiefHereDecisionHandler implements DecisionHandler {

 

       public String decide(ExecutionContext executionContext) throws Exception {

              /**

               * 根據主管是否休假來判斷走哪條邊

               * */

              System.out.println("==IsChiefHereDecisionHandler.decide()==");

              //主管在

              if(((Boolean)executionContext.getContextInstance().getVariable(RequestVariable.isChiefHere)).booleanValue())

                    

                     return "Tr_Chief";

              else

                     return "Tr_Boss";

       }

}

6.15.    NeedBossDecideDecisionHandler

package com.myrequest.decision;

 

import org.jbpm.graph.exe.ExecutionContext;

import org.jbpm.graph.node.DecisionHandler;

 

import com.myrequest.*;

 

public class NeedBossDecideDecisionHandler implements DecisionHandler {

 

       public String decide(ExecutionContext executionContext) throws Exception {

              // TODO Auto-generated method stub

              int dayCount =((Integer)executionContext.getContextInstance().getVariable(RequestVariable.dayCount)).intValue();

              int dayLevel= 10;//是否需要boss批准的分界

              if(dayCount>=dayLevel){

                     return "Tr_Need";

              }

              else{

                     return "Tr_NotNeed";

              }

             

       }

 

}

6.16.    BossDecideAssignmentHandler

package com.myrequest.task;

 

import org.jbpm.graph.exe.ExecutionContext;

import org.jbpm.taskmgmt.def.AssignmentHandler;

import org.jbpm.taskmgmt.exe.Assignable;

 

public class BossDecideAssignmentHandler implements AssignmentHandler {

 

       public void assign(Assignable assignable, ExecutionContext executionContext)

                     throws Exception {

              // TODO Auto-generated method stub

              /**

               * 以角色boss到數據庫中查找,找到userid elena

               * */

              String bossId="elena";

              //elena is boss

              assignable.setActorId(bossId);

       }

 

}

6.17.    CancelRequestAssignmentHandler

package com.myrequest.task;

 

import org.jbpm.graph.exe.ExecutionContext;

import org.jbpm.taskmgmt.def.AssignmentHandler;

import org.jbpm.taskmgmt.exe.Assignable;

 

import com.myrequest.*;

 

public class CancelRequestAssignmentHandler implements AssignmentHandler {

 

       public void assign(Assignable assignable, ExecutionContext executionContext)

                     throws Exception {

              // TODO Auto-generated method stub

 

              String userid=(String)executionContext.getContextInstance() .getVariable(RequestVariable.userId);

              /**

               * 撤銷請假請求任務可以由請假發起人執行,demo裏面是dust

               * */

              assignable.setActorId(userid);

             

              System.out.println("==assign user is:"+userid+" ==");

              System.out.println("==CancelRequestAssignmentHandler.assign()==");

       }

 

}

6.18.    ChiefDecideAssignmentHandler

package com.myrequest.task;

 

import org.jbpm.graph.exe.ExecutionContext;

import org.jbpm.taskmgmt.def.AssignmentHandler;

import org.jbpm.taskmgmt.exe.Assignable;

 

import com.myrequest.*;

 

public class ChiefDecideAssignmentHandler implements AssignmentHandler {

 

       public void assign(Assignable assignable, ExecutionContext executionContext)

                     throws Exception {

              // TODO Auto-generated method stub

              String userid=(String)executionContext.getContextInstance().getVariable( RequestVariable.userId);

        /**

         * 通過userid得到user的上級chief是誰,這裏假設是today123

         * */             

              String chiefId ="today123";

             

              assignable.setActorId(chiefId);

             

              System.out.println("==assign user is:"+userid+" ==");

              System.out.println("==ChiefDecideAssignmentHandler.assign()==");

 

       }

 

}

6.19.    WriteRequestAssignmentHandler

package com.myrequest.task;

 

import com.myrequest.*;

import org.jbpm.graph.exe.ExecutionContext;

import org.jbpm.taskmgmt.def.AssignmentHandler;

import org.jbpm.taskmgmt.exe.Assignable;

 

public class WriteRequestAssignmentHandler implements AssignmentHandler {

 

       public void assign(Assignable assignable, ExecutionContext executionContext)

                     throws Exception {

              // TODO Auto-generated method stub

              String userid =(String)executionContext.getContextInstance().getVariable(RequestVariable.userId);

             

              assignable.setActorId(userid);

              System.out.println("==assign user is:"+userid+" ==");

              System.out.println("==WriteRequestAssignmentHandler.assign()==");

 

       }

 

}

6.20.    RequestState

package com.myrequest;

 

public interface RequestState {

 

       final static String REQEUST="request";

       final static String APPROVE="approve";

       final static String DISAPPROVE="disapprove";

       final static String CANCLE="cancel";

       final static String CHIEFAPPROVE="chiefapprove";

      

}

6.21.    RequestVariable

package com.myrequest;

 

public interface RequestVariable {

      

       //請求狀態

       final static String requestState="RequestState";

       //主管是否在崗

       final static String isChiefHere="isChiefHere";

       //要請假的日期天數

       final static String dayCount = "dayCount";

       //啓動流程,也就是要申請請假的工人的id

       final static String userId ="userId";

       //部門主管是否同意

       final static String isChiefApprove="isChiefApprove";

      

 

}

6.22.    Processdefinition.xml

<?xml version="1.0" encoding="UTF-8"?>

<process-definition

  xmlns="urn:jbpm.org:jpdl-3.1"  name="MyRequest">

   <start-state name="SS_Request">

 

      <transition name="" to="TN_WriteRequest"></transition>

   </start-state>

   <task-node name="TN_WriteRequest">

      <task name="Task_WriteRequest">

         <controller>

            <variable name="dayCount" access="read,write,required"></variable>

         </controller>

         <assignment class="com.myrequest.task.WriteRequestAssignmentHandler"></assignment>

      </task>

      <transition name="Tr_WriteLeave" to="Fork_request">

         <action name="Ac_WriteLeave" class="com.myrequest.action.WriteLeaveActionHandler"></action>

      </transition>

   </task-node>

   <fork name="Fork_request">

      <transition name="Tr_Cancel" to="TN_RequesterCancel"></transition>

      <transition name="Tr_Request" to="Deci_IsChiefHere"></transition>

   </fork>

   <decision name="Deci_IsChiefHere">

      <handler class="com.myrequest.decision.IsChiefHereDecisionHandler"/>

      <transition name="Tr_Chief" to="TN_ChiefDecide"></transition>

      <transition name="Tr_Boss" to="TN_BossDecide"></transition>

   </decision>

   <task-node name="TN_RequesterCancel">

      <task name="Task_CancelRequest">

         <assignment class="com.myrequest.task.CancelRequestAssignmentHandler"></assignment>

      </task>

      <transition name="Tr_RequestCancel" to="Join_Request">

         <action name="Ac_RequestCancel" class="com.myrequest.action.RequestCancelActionHandler"></action>

      </transition>

   </task-node>

   <task-node name="TN_ChiefDecide">

      <task name="Task_ChiefDecide">

         <assignment class="com.myrequest.task.ChiefDecideAssignmentHandler"></assignment>

      </task>

      <transition name="Tr_ChiefApprove" to="Deci_NeedBossDecide">

         <action name="Ac_ChiefApprove" class="com.myrequest.action.ChiefApproveActionHandler"></action>

      </transition>

      <transition name="Tr_ChiefNotApprove" to="Join_Request">

         <action name="Ac_ChiefNotApprove" class="com.myrequest.action.ChiefNotApproveActionHandler"></action>

      </transition>

   </task-node>

   <join name="Join_Request">

      <transition name="Tr_Join" to="Deci_DoSomething"></transition>

   </join>

   <decision name="Deci_NeedBossDecide">

      <handler class="com.myrequest.decision.NeedBossDecideDecisionHandler"/>     

      <transition name="Tr_Need" to="TN_BossDecide"></transition>

      <transition name="Tr_NotNeed" to="Join_Request">

         <action name="Ac_NotNeed" class="com.myrequest.action.NotNeedActionHandler"></action>

      </transition>

   </decision>

   <task-node name="TN_BossDecide">

      <task name="Task_BossDecide">

         <assignment class="com.myrequest.task.BossDecideAssignmentHandler"></assignment>

      </task>

      <transition name="Tr_BossApprove" to="Join_Request">

         <action name="Ac_BossApprove" class="com.myrequest.action.BossApproveActionHandler"></action>

      </transition>

      <transition name="Tr_BossNotApprove" to="Join_Request">

         <action name="Ac_BossNotApprove" class="com.myrequest.action.BossNotApproveActionHandler"></action>

      </transition>

   </task-node>

   <decision name="Deci_DoSomething">

       <handler class="com.myrequest.decision.DoSomethingDecisionHandler"/>

      <transition name="Tr_Approve" to="ES_Finished">

         <action name="Ac_Approve" class="com.myrequest.action.ApproveActionHandler"></action>

      </transition>

      <transition name="Tr_NotApprove" to="ES_Finished">

         <action name="Ac_NotApprove" class="com.myrequest.action.NotApproveActionHandler"></action>

      </transition>

      <transition name="Tr_Cancel" to="ES_Finished">

         <action name="Ac_Cancel" class="com.myrequest.action.CancelActionHandler"></action>

      </transition>

   </decision>

   <end-state name="ES_Finished">

                     <event type="node-enter">

                            <action name="Ac_Finished" class="com.myrequest.action.FinishedActionHandler"></action>

                     </event>

   </end-state>

</process-definition>

6.23.    gpd.xml

<?xml version="1.0" encoding="UTF-8"?>

 

<process-diagram name="MyRequest" width="804" height="613">

  <node name="SS_Request" x="147" y="5" width="140" height="40">

    <transition name="">

      <label x="5" y="-10"/>

    </transition>

  </node>

  <node name="TN_WriteRequest" x="145" y="71" width="140" height="40">

    <transition name="Tr_WriteLeave">

      <label x="5" y="-10"/>

    </transition>

  </node>

  <node name="Fork_request" x="168" y="134" width="200" height="25">

    <transition name="Tr_Cancel">

      <label x="5" y="-10"/>

    </transition>

    <transition name="Tr_Request">

      <label x="5" y="-10"/>

    </transition>

  </node>

  <node name="Deci_IsChiefHere" x="311" y="179" width="140" height="40">

    <transition name="Tr_Chief">

      <label x="5" y="-10"/>

    </transition>

    <transition name="Tr_Boss">

      <label x="5" y="-10"/>

    </transition>

  </node>

  <node name="TN_RequesterCancel" x="9" y="181" width="140" height="40">

    <transition name="Tr_RequestCancel">

      <label x="-73" y="-5"/>

    </transition>

  </node>

  <node name="TN_ChiefDecide" x="159" y="253" width="140" height="40">

    <transition name="Tr_ChiefApprove">

      <label x="-42" y="-9"/>

    </transition>

    <transition name="Tr_ChiefNotApprove">

      <label x="-28" y="-5"/>

    </transition>

  </node>

  <node name="Join_Request" x="115" y="388" width="200" height="25">

    <transition name="Tr_Join">

      <label x="5" y="-10"/>

    </transition>

  </node>

  <node name="Deci_NeedBossDecide" x="415" y="243" width="166" height="40">

    <transition name="Tr_Need">

      <label x="-30" y="-11"/>

    </transition>

    <transition name="Tr_NotNeed">

      <label x="5" y="-10"/>

    </transition>

  </node>

  <node name="TN_BossDecide" x="663" y="241" width="140" height="40">

    <transition name="Tr_BossApprove">

      <label x="31" y="-13"/>

    </transition>

    <transition name="Tr_BossNotApprove">

      <label x="-19" y="4"/>

    </transition>

  </node>

  <node name="Deci_DoSomething" x="146" y="460" width="140" height="40">

    <transition name="Tr_Approve">

      <label x="5" y="-10"/>

    </transition>

    <transition name="Tr_NotApprove">

      <label x="2" y="5"/>

    </transition>

    <transition name="Tr_Cancel">

      <label x="4" y="-25"/>

    </transition>

  </node>

  <node name="ES_Finished" x="147" y="572" width="140" height="40"/>

</process-diagram>

 
發佈了30 篇原創文章 · 獲贊 4 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章