一个
Jbpm
员工请假流程的实例
作者:吴大愚
Email:dywu_xa@sina.com
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
存放流程中所有的
task
的
AssignmentHandler
分配类
n
共有
4
个类,对应
4
个
task
l
com.myrequest.decision
n
存放流程中所有的
decision
节点的判断类
n
包括
3
个类,对应
3
个
Decision
节点
在
src/test
目录下面,有包:
l
com.myrequest
n
包含此流程的测试类
MyRequestProcessTest.java
在
processes
目录下面,有:
l
流程定义文件夹
MyRequest
,包含:
n
Gpd.xml
n
Processdefinition.xml
n
Processimage.jpg
4.2.
流程代码说明
对流程中使用到的和
Action
,
task
,
decision
相关的类,以及测试类进行说明。
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
分配给那个人,然后由这个人来完成。在人开始任务的时候,可以调用
taskInstance
的
start()
操作,表明任务开始。(
start
()操作是可选的,也可以不调用)
在任务结束后,可以调用
taskInstance
的
end()
操作,表示任务实例结束。如果是整个
task-node
中的最后一个
task
的
end()
操作,那么就会这个
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表中,每一个taskinstance在actorId_字段记录的是次任务实例分配人员的用户名。这也就是上面所说的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
这个方法应该返回一个
transition
的
name
,表示选择走那条边。
这
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
,另外一个是部门主管是否在岗的状态。可以修改这两个参数,进行不同的测试。尤其是第二个参数,会影响流程的走向,可以分别设置为
true
和
false
以观察流程的走向和结果。
在测试类中还有
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)
得到所有分配给
chiefId
的
taskInstance
* */
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)
得到所有分配给
bossId
的
taskInstance
* */
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)
得到所有分配给
userid
的
taskInstance
* */
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>