8、JBPM自动活动
2)script脚本活动
jpdl定义:
<!-- script 脚本活动会解析一个script 脚本。 任何一种符合JSR-223 规范 的脚本引擎语言都可以在这里运行。 expr:执行表达式的文本 var:返回值存储的 变量名 --> <script name="invoke script" expr="Send packet to #{order.address}" var="text" g="96,16,104,52"> <transition to="wait" /> </script>
测试代码如下:
Map<String, Object> variables = new HashMap<String, Object>(); variables.put("order", new Order("Berlin")); Execution execution = executionService .startProcessInstanceByKey("ScriptExpression", variables); String executionId = execution.getId(); String text = (String) executionService.getVariable(executionId, "text"); assertTextPresent("Send packet to Berlin", text);
3)hql查询
jpdl定义:
<!-- 使用hql 活动,我们可以在database 中执行HQL query var:存储结果的变量名 unique:值为true 是指从uniqueResult()方法中 获得hibernate query 的结果。 默认值是false。 值为false 的话会使用list()方法得到结果。 --> <hql name="get task names" var="tasknames with i" g="96,16,115,52"> <!-- query:HQL query parameter:query 的参数 --> <query> select task.name from org.jbpm.pvm.internal.task.TaskImpl as task where task.name like :taskName </query> <parameters> <string name="taskName" value="%i%" /> </parameters> <transition to="count tasks" /> </hql> <hql name="count tasks" var="tasks" unique="true" g="243,16,95,52"> <query> select count(*) from org.jbpm.pvm.internal.task.TaskImpl </query> <transition to="wait" /> </hql>
测试事例代码如下:
ProcessInstance processInstance = executionService.startProcessInstanceByKey("Hql"); String processInstanceId = processInstance.getId(); // 设定预期结果 Set<String> expectedTaskNames = new HashSet<String>(); expectedTaskNames.add("dishes"); expectedTaskNames.add("iron"); // 获取第一个hql活动的执行结果,流程变量"tasknames with i" Collection<String> taskNames = (Collection<String>) executionService .getVariable(processInstanceId, "tasknames with i"); taskNames = new HashSet<String>(taskNames); assertEquals(expectedTaskNames, taskNames); // 获取第二个hql活动的执行结果,流程数据库中共有3条记录 Object activities = executionService.getVariable(processInstanceId, "tasks"); assertEquals("3", activities.toString());
4)sql查询
jpdl定义:
<!--sql 活动和hql 活动十分相似, 唯一不同的地方就是 使用session.createSQLQuery(...) --> <sql name="get task names" var="tasknames with i" g="96,16,126,52"> <query> select NAME_ from JBPM4_TASK where NAME_ like :name </query> <parameters> <string name="name" value="%i%" /> </parameters> <transition to="count tasks" /> </sql> <sql name="count tasks" var="tasks" unique="true" g="254,16,92,52"> <query> select count(*) from JBPM4_TASK </query> <transition to="wait" /> </sql>
测试事例代码同Hql事例代码。
5) mail(邮件活动)
jpdl定义:
<!-- from:发件者列表 to: 主要收件人列表 cc:抄送收件人列表 bcc: 密送收件人列表 subject:这个元素的文字内容会成为消息的主题 text:这个元素的文字内容会成为消息的文字内容 html:这个元素的文字内容会成为消息的HTML 内容 attachments:每个附件都会配置在单独的子元素中 --> <mail g="99,25,115,45" language="juel" name="send rectify note"> <to addresses=" winston@minitrue"/> <cc groups="innerparty" users="bb"/> <bcc groups="thinkpol"/> <subject>rectify ${newspaper}</subject> <text>${newspaper} ${date} reporting bb dayorder doubleplusungood refs unpersons rewrite fullwise upsub antefiling</text> <!-- <html><table><tr><td>${newspaper}</td><td>${date}</td> <td>reporting bb dayorder doubleplusungood refs unpersons rewrite fullwise upsub antefiling</td> </tr></table></html> <attachments> <attachment url='http://www.george-orwell.org/1984/3.html' /> <attachment resource='org/example/pic.jpg' /> <attachment file='${user.home}/.face' /> </attachments> --> <transition to="wait"/> </mail>
9、事件
Jpdl定义:
<state name="wait" g="96,16,104,52"> <!-- event:事件名称(start或end) event-listener:一个事件监听器实现对象。 start:活动开始时捕获 end:活动结束时捕获 --> <on event="start"> <event-listener class="org.jbpm.examples.eventlistener.LogListener"> <field name="msg"><string value="start on activity wait"/></field> </event-listener> </on> <on event="end"> <event-listener class="org.jbpm.examples.eventlistener.LogListener"> <field name="msg"><string value="end on activity wait"/></field> </event-listener> </on> <transition to="park"> <event-listener class="org.jbpm.examples.eventlistener.LogListener"> <field name="msg"><string value="take transition"/></field> </event-listener> </transition> </state>
监听器LogListener代码:
public class LogListener implements EventListener { String msg; public void notify(EventListenerExecution execution) { List<String> logs = (List<String>) execution.getVariable("logs"); if (logs==null) { logs = new ArrayList<String>(); execution.setVariable("logs", logs); } logs.add(msg); execution.setVariable("logs", logs); } }
测试事例代码如下:
ProcessInstance processInstance = executionService .startProcessInstanceByKey("EventListener"); Execution execution = processInstance.findActiveExecutionIn("wait"); executionService.signalExecutionById(execution.getId()); List<String> expectedLogs = new ArrayList<String>(); expectedLogs.add("start on process definition"); expectedLogs.add("start on activity wait"); expectedLogs.add("end on activity wait"); expectedLogs.add("take transition"); List<String> logs = (List<String>) executionService .getVariable(processInstance.getId(), "logs"); assertEquals(expectedLogs, logs);
默认情况下,事件监听器只对当前订阅的元素所触发的事件起作用,即propagation=”false”,
但通过指定事件监听器的传播属性propagation=”enabled”或(propagation=”true”),
则该事件监听器可以对其监听元素的所有子元素起作用。
10. 异步执行
1)几乎所有的活动都支持异步属性,流程一旦进入异步执行方式,一个异步消息会被作为当前事务的一部门发送出去,
然后当前事务会立即自动提交。
Jpdl定义:
<!-- continue属性: sync (默认值) 作为当前事务的一部分,继续执行元素。 async 使用一个异步调用(又名安全点)。当前事务被提交,元素在一个新事务中执行。 事务性的异步消息被jBPM 用来 实现这个功能。 --> <java name="generate pdf" continue="async" class="org.jbpm.examples.async.activity.Application" method="generatePdf" g="86,26,87,50"> <transition to="calculate primes"/> </java> <java name="calculate primes" continue="async" class="org.jbpm.examples.async.activity.Application" method="calculatePrimes" g="203,26,98,50"> <transition to="end"/> </java>
Application事例代码如下:
public class Application implements Serializable { private static final long serialVersionUID = 1L; public void generatePdf() { // 此方法执行需要消耗较长时间 } public void calculatePrimes() { // 此方法执行需要消耗较长时间 } }
测试事例代码如下:
ProcessInstance processInstance = executionService .startProcessInstanceByKey("AsyncActivity"); String processInstanceId = processInstance.getId(); // 流程实例处于异步执行状态 assertEquals(Execution.STATE_ASYNC, processInstance.getState()); // 获取流程实例异步消息队列中的第1条消息 Job job = managementService.createJobQuery() .processInstanceId(processInstanceId).uniqueResult(); // 手工执行异步消息 managementService.executeJob(job.getId()); processInstance = executionService.findProcessInstanceById(processInstanceId); // 流程实例处于异步执行状态 assertEquals(Execution.STATE_ASYNC, processInstance.getState()); // 获取第2条消息(job)并执行之 job = managementService.createJobQuery() .processInstanceId(processInstanceId) .uniqueResult(); managementService.executeJob(job.getId()); assertNull(executionService.findProcessInstanceById(processInstanceId));
2)异步分支/聚合
Jpdl定义:
<!-- exclusive 这个值被用来 将两个来自分支的异步调用的job 结果进行持久化。 各自的事务会分别执行ship goods 和send bill, 然后这两个执行都会达到join 节点。 在join 节点中,两个事务会同步到一个相同的执行上(在数据库总更新同一个执行), 这可能导致一个潜在的乐观锁失败。--> <fork g="99,68,80,40" name="fork"> <!-- 并行的流程分支以独占方式异步执行 --> <on event="end" continue="exclusive" /> <transition g="122,41:" to="ship goods"/> <transition g="123,142:" to="send bill"/> </fork> <java class="org.jbpm.examples.async.fork.Application" g="159,17,98,50" method="shipGoods" name="ship goods"> <transition g="297,42:" to="join"/> </java> <java class="org.jbpm.examples.async.fork.Application" g="159,117,98,50" method="sendBill" name="send bill"> <transition g="297,141:" to="join"/> </java> <join g="274,66,80,40" name="join"> <transition to="end"/> </join>
测试事例代码如下:
ProcessInstance processInstance = executionService.startProcessInstanceByKey("AsyncFork"); String processInstanceId = processInstance.getId(); // 获取异步消息列表 List<Job> jobs = managementService.createJobQuery() .processInstanceId(processInstanceId).list(); //有两个分支,有2条异步消息 assertEquals(2, jobs.size()); Job job = jobs.get(0); //手工执行第1条 managementService.executeJob(job.getId()); job = jobs.get(1); //手工执行第2条 managementService.executeJob(job.getId()); Date endTime = historyService .createHistoryProcessInstanceQuery() .processInstanceId(processInstance.getId()) .uniqueResult() .getEndTime(); // 流程已结束 assertNotNull(endTime);
11. 流程变量
1)流程变量与流程实例绑定, 可通过以下方法来操作流程变量:
例:
ProcessInstance startProcessInstanceById (String processDefinitionId,Map<String,Object>variables); ProcessInstance startProcessInstanceById (String processDefinitionId,Map<String,Object>variables,String processInstanceKey);
2)其它引擎服务中也存在类似的方法,例如TaskService也提供方法操作任务绑定的流程变量。
3)通过流程变量控制流程的流向是正确的做法,但是不要被这种“方便”的机制诱惑而往流程实例里面放所有的东西,
特别是与流转控制无关的业务数据。
五、 JBPM数据表
JBPM4_DEPLOYMENT: 流程定义的部署记录
JBPM4_DEPLOYPROP: 已部署的流程定义的具体属性
JBPM4_LOB:流程定义的相关资源,包括JPDL XML、图片、用户代码Java类等。
JBPM4_JOB:异步活动或定时执行的Job记录。
JBPM4_VARIABLE:流程实例的变量。
JBPM4_EXECUTION:流程实例及执行对象。
JBPM4_SWIMLANE:任务泳道。
JBPM4_PARTICIPATION:任务参与者,任务的相关用户,区别于任务的分配人。
JBPM4_TASK:流程实例的任务记录。
JBPM4_HIST_PROCINST:保存历史的流程实例记录。
JBPM4_HIST_ACTINST:保存历史的活动实例记录。
JBPM4_HIST_TASK:保存历史的任务实例记录。
JBPM4_HIST_VAR:保存历史的流程变量数据。
JBPM4_HIST_DETAIL:保存流程实例、活动实例、任务实例运行过程中历史明细数据。
JBPM4_ID_USER:保存用户记录。
JBPM4_ID_MEMBERSHIP:保存用户和用户组之间的关联关系。
JBPM4_ID_GROUP:保存用户组记录。