jbpm fork join

Start(启动节点):表示流程的开始从哪里开始,每个流程都有一个start节点。

      Start有一个name属性给start节点取一个名字

   

State:此节点表示一个等待状态,进入此节点,整个流程都会中断,直到系统外的参与者发起继续执行的命令。

     State 只有一个name属性

     例子:

     1.序列状态节点

                

2.可选择的状态节点

Task:(任务节点) 进入这个节点,业务会继续下去。当task下所有的节点下的所以任务都完成,流程才会继续下去。

    1一个任务分配给指定的用户,我们可以使用assignee属性实现

     

      

          这个流程演示了任务分配的两个方面。

 

      第一,assignee 用来指派用户;

      第二, 任务被分配给#{users.owner},这说明程序首先调用users这个名字查找一个对象, 并且调用getOwner()方法来获得用户变量。

当一个流程实例创建时,需要把users 作为一个流程变量分配给它。

      Map<String, Object> variables = newHashMap<String, Object>();

      variables.put("users", newUsers("Marker"));

     executionService.startProcessInstanceByKey("testTask",variables);

      然后Marker 的任务列表可以这样获得:

      List<Task> taskList = taskService.findPersonalTasks("Marker");

2 任务候选人:

    候选人顾名思义就是有多个人可以接收并完成这个任务。

    我们可以通过两个属性定义候选人,candidate-groups和candidate-users。

  

当这个流程实例启动后,一个任务就会被创建,而这个任务在这时是不显示在任何人的任务

   列表中的,因此下面的任务列表会是空的。

  taskService.findPersonalTasks("Marker");

   taskService.findPersonalTasks("King");

   如果想得到这个任务,我们需要将用户添加到组别中,接下来我们为user-dept增加两个成员:

   Marker 和King

   //创建名为user-dept的组

  identityService.createGroup("user-dept");

   //创建用户Marker

  identityService.createUser("Marker", "first name","family name",

   "majk@vip.qq.com");

   //将Marker归入user-dept

  identityService.createMembership("Marker","user-dept");

   //创建用户King

   identityService.createUser("King","first name", "family name", "majk@9.cn");

   //将King归入user-dept

   identityService.createMembership("King","user-dept");

   至此,用户Marker和King 就属于user-dept组,这时再查询任务列表,就会得到这个任务了。

   但是候选人必须在他处理这个任务之前,接收这个任务。

   taskService.takeTask(task.getId(),"Marker");

   当一个候选人接收了这个任务,那么这个任务就会分配(assignee)给他,并且任务会从所

   有候选人的分组任务列表中消失,它会出现在接收人的任务列表中。

   candidate-users 属性则是用来处理以逗号分隔的一系列用户ID。candidate-users属性可以

   和其他分配选项结合使用。

3任务分配处理器

   一个AssignmentHandler 可以通过编程方式来计算一个任务的分配人和候选人。

public interfaceAssignmentHandler extends Serializable {

  /** 设置分配人和候选人*/

  void assign(Assignable assignable,OpenExecution execution) throws Exception;

}

 Assignment-handler 是task节点的子节点。它的子节点都来自用户代码。

下面是任务分配处理器的使用示例:

<processname="testTaskAssignmentHandler"xmlns="http://jbpm.org/4.4/jpdl">

  <start>

    <transition to="review"/>

  </start>

  <task name="task1">

    <assignment-handlerclass="test.AssignTask">

      <field name="assignee">

       <string value="Marker"/>

      </field>

    </assignment-handler>

    <transition to="wait1"/>

  </task>

  <state name="wait1"/>

</process>

该流程启动后进入task1 节点,AssignTask 被调用,将Marker设置为改任务的assignee。

 我们需要注意的是,默认的AssignmentHandler实现类可以使用流程实例中的变量,或使

 用数据库加载其他业务对象。

ForkJion:fork节点把一条执行路径分离成多条同时进行(并发)的执行路径,每条路径产生一个单独的执 行,该节点适用于需要并发流程的场景,比如多部门的审批等。fork后一般会有join节点来合并流

程,join节点可以设置在执行该节点之前需要到达该节点的执行的数目。

   

 

   默认情况下join会等待所有的子执行全部结束才会执行,如果设置了multiplicity,那么只要

满足multiplicity 的数量就会执行该join节点,比如在上面流程定义文件中的join 节点中加入

multiplicity= “1”,那么只要有一个执行到达这里,join就会继续往下执行。而不会等待。

     Set<String> set = null;

     //启动流程,获得流程实例

    processInstance =executionService.startProcessInstanceByKey("fork");

    //查看当前的活动节点[state1,state2]

     set =processInstance.findActiveActivityNames();

     //得到活动节点

     String id1 =processInstance.findActiveExecutionIn("state1").getId();

    processInstance =executionService.signalExecutionById(id1);

     //查看当前的活动节点[state2]

     set =processInstance.findActiveActivityNames();

     //得到活动节点

     String id3 =processInstance.findActiveExecutionIn("state2").getId();

    processInstance =executionService.signalExecutionById(id2);

     //查看当前的活动节点[state3]

     set =processInstance.findActiveActivityNames();

     //得到活动节点

     String id3 =processInstance.findActiveExecutionIn("state3").getId();

    processInstance =executionService.signalExecutionById(id3);

     //查看当前的活动节点[无]

     set =processInstance.findActiveActivityNames();

    executionService每次调用signalExecutionById之后都会返回一个新的流程实例,我们在上下

文中要使用这个返回的流程实例,而且每次调用完signalExecutionById都要为这个对象重新赋值,

这样才会得到最新的流程执行结果。

Decision:决策节点,用于觉得在多个执行路径中哪个才可以被执行。

        有transition和handler class元素

       Transition转向时可以是一个条件或者一个表达式

     1条件:

 

         

 2表达式

    

    当我们使用“工作结束”,启动一个新的流程实例。

   Map<String,Object> variables=newHsahMap< String,Object>();

   Variables.put(“content”,”工作结束”);

   executionService.startProcessInstanceByKey("testDecision",variables);

3决策处理器:  使用决策处理器需要实现DecisionHandler接口,将决策权交给决策处理器

  

   下面是自定义的handler类

    package test;

 

import org.jbpm.api.jpdl.DecisionHandler;

import org.jbpm.api.model.OpenExecution;

 

 

public class MyDecisionHandlerimplements DecisionHandler {

 

   @Override

   public String decide(OpenExecution execution) {

      String  content=(String)execution.getVariable("content");

      if (content.equals("工作结束")) {

        return "睡觉";

      }

      else {

        return "学习";

      }

   }

 

}

 

Transition:转换节点,转换节点是流程中最多的节点,它在设计器中用一条有向线段表示,表示从一个即节点到达另一个节点,它的to属性就是标明它的目的节点

End:结束节点,用来表示流程的结束。

    有name属性

   

  上面的流程一开始就结束

Sub-process:子流程节点,创建一个子节点实例并等待直到它完成。当子实例完成,父流程的执行就会继续前进。

    1:子流程变量

      如何向子流程实例传递信息,我们需要运用到变量,与流程变量不同的是,子流程变量有

       parameter-in和parameter-out,其属性var 和subvar分别对应父流程变量和子流程变量。

       在parameter-in 中var 代表将父流程变量传递到subvar子流程变量中;

       在parameter-out 中var 代表父流程变量读取子流程变量subvar。

   定义一个子流程:

    

  

定义一个父任务:

 

      我们启动父流程,并赋予一个文档变量:

 

   Map<String, Object> variables = newHashMap<String, Object>();

   variables.put("document","sometext");

   ProcessInstance processInstance =

      executionService.startProcessInstanceByKey("SubProcessDocument",variables);

   然后父流程达到sub-process 节点,触发子流程启动,并且子流程达到get approval任务节

   点,将subvar 设置的subDocument作为分配人赋值给该任务,因此我们可以使用sometext

   用户来获得其任务列表。

   List<Task> taskList =taskService.findPersonalTasks("sometext");

   Task task = taskList.get(0);

   而后我们将变量subResult设置到子流程的实例中

   Map<String, Object> variables = newHashMap<String, Object>();

   variables.put("subResult","accept");

   taskService.setVariables(task.getId(),variables);

   完成这个子流程的任务,整个子流程结束

   taskService.completeTask(task.getId());

   当子流程结束时,父流程会被signal标记(不是notify 提醒)。首先subResult变量会从子

   流程赋值到父流程的result 变量中,然后上级流程继续并离开review 节点。

Customs自定义节点,调用实现了的自定义的用户代码。

      

以下是自定义的代码  Custom类需要实现ExternalActivityBehaviour接口

 

Java:java任务节点,流程的执行会调用在java活动中配置的类的方法。

      当流程执行到java节点的时候,会执行在该节点上配置的相应的方法。如果有返回值则通过var

属性设置,我们可以通过variables拿到该返回值。

   

Java节点不在界面体现

下面是JavaTest

接下来我们设定好变量,启动新的流程实例:

Map<String,Object> variables = newHashMap<String,Object>();

List<String> list = newArrayList<String>();

//动态为java类设值添加测试数据

list.add("jbpm");

variables.put("list", list);

variables.put("listName","jbpmList");

//通过表达式实例化添加测试数据

variables.put("hand", new Handler());

variables.put("msg", "oneworld!!!");

//启动流程,获得流程实

executionService.startProcessInstanceByKey("javaTask",variables);

Script:脚本节点,此节点会解析一个脚本

Hql:使用hql活动,我们可以在数据库中执行hql查询,并将返回的结果保存到流程变量中。

    有var属性 用来存放查询的结果集

    Unique属性 用来判断是从uniqueResult还是list中取得结果

    子节点 :

    Query 查询语句

    Parameters 查询语句的参数

    

Sql:使用的是sql语句 和hql节点差不多。

Mail:邮件节点,使用mail活动,流程作者可以指定一封email的内容,一次发送给多个收件人。

     有template属性 是个字符串            引用配置文件中的一个mail-template 元素。

                                           如果没找到, 必须使用子元素在内部指定。

    子节点

 attachment节点

 

例子:

End-concel:事件结束节点。可以触发一个事件,可以是流程取消<end-cancel>等价于<end state=”cancel”>;。。

End-error:表示结束发生错误的事件。<end-error>等价于<endstate=”error”>

 

 

 

 

 

 

 

JBPM有五大服务接口 这些服务接口都可以由 流程引擎ProcessEngine获得,该引擎则由Configuration构建的  有以下几种方式

1: ProcessEngine pe =Configuration.getProcessEngine();

  过静态方法直接按照默认的配置文件名称构建流程引擎,该方法会直接加载classpath 下

  名为jbpm.cfg.xml的配置文件,通过该配置文件中的生命去构建引擎

2: ProcessEngine pe = newConfiguration().buildProcessEngine();

   通过实例化Cofiguration后的buildProcessEngine 方法构建引擎,该方法与上述方法过程类似

3: ProcessEngine pe=newConfiguration().setResource("").buildProcessEngine();

自定义JBPM 配置文件名称后,构建流程引擎.

 

五大服务接口:

1流程资源服务接口

RepositoryService;

2执行服务接口

   ExecutionService

3任务服务接口

  TaskService

4 历史服务接口

  HistoryService

5管理服务接口

  ManagementService

 

1流程资源服务接口

//由流程引擎得到

RepositoryServicerepositoryService = processEngine.getRepositoryService();

 

   RepositoryService 包含了管理流程资源的所有方法。

   1) 部署流程

   //通过classpath中的文件名加载

  repositoryService.createDeployment().addResourceFromClasspath(path).deploy();

  

//通过File类加载

  repositoryService.createDeployment().addResourceFromFile(file).deploy();

 

   //通过url地址加载

  repositoryService.createDeployment().addResourceFromUrl(url).deploy();

 

   //通过Zip文件流加载 (流程图实例化可以采用此方式)

   repositoryService.createDeployment().addResourcesFromZipInputStream(zip).deploy();

 

   //通过字符串加载

  repositoryService.createDeployment().addResourceFromString(resourceName,string);

 

       流程部署后,会生成{key}-{version}格式的流程定义ID,如果流程定义文件未指明key 和

   version,程序将使用流程名称作为key,根据当前数据库存储情况生成version (version =key

   的数量+1)。

       生成的key将不是数字和字母的字符,替换为下划线。

2) 删除流程

 

   //删除流程定义,如果该定义还存在活动的流程实例,将抛出异常

  repositoryService.deleteDeployment(deploymentId);

 

   //级联删除所有该流程相关的内容

   repositoryService.deleteDeploymentCascade(deploymentId);

 

   3) 挂起/恢复流程

   //当流程定义挂起后,其相关记录不会被删除,此时发起新流程实例或更新其实例的数据,都会抛出异常

  repositoryService.suspendDeployment(deploymentId);

 

   //恢复流程定义后,可以继续操作流程及其实例

  repositoryService.resumeDeployment(deploymentId);

   4) 查询流程示例

   ProcessDefinitionQuery pdq =repositoryService.createProcessDefinitionQuery();

   List<ProcessDefinition> pdList =pdq.processDefinitionKey("xxx").list();

   for (ProcessDefinition processDefinition :pdList) {

       //TODO

    }

 

   5) 获得流程定义图片

   //该方法可以将流程设计时生成的图片文件以流格式返回,前提条件是图片也发布到了数据库中

   //具体使用方法后面将会介绍到

  repositoryService.getResourceAsStream(deploymentId,"xxx.png");

 

2执行服务接口

由流程引擎得到

  ExecutionServiceexecutionService = processEngine.getExecutionService();

ExecutionService 主要用于维护流程实例,执行等待状态的流程,并且包含了流程实例的查询和

流程变量的操作。

 

   1) 启动新的流程实例

 

      a) 使用Key 启动最新的流程实例

        executionService.startProcessInstanceByKey("VWIN");

         上述方法会以Key 为VWIN 流程定义的最新版本启动一个新的流程实例,是最简单且最常

         用的方法。

 

      b) 指定流程版本

 

         executionService.startProcessInstanceById("VWIN-2");

         上述方法会以流程为VWIN-2的定义启动一个新的流程实例,VWIN 是流程定义的Key,2

         是流程定义的版本。

 

      c) 指定流程实例的ID

 

        executionService.startProcessInstanceByKey("VWIN","CGD0008");

         上述方法与第a种方法类似,唯一区别是手动指定了流程实例的ID,这个ID可以用我们的业务对象ID,例如采购单。

 

      d) 使用变量

 

         Map<String,Object> variables =new HashMap<String,Object>();

         variables.put("customer","John Doe");

         variables.put("type","Accident");

         variables.put("amount", newFloat(763.74));

         executionService.startProcessInstanceByKey("VWIN",variables);

 

         上述方法在启动流程实例时,就会将设置的变量保存,启动后可以使用这些变量。

 

   2) 执行等待的流程

      当使用一个state活动时,流程会在达到state 的时候等待,直到一个Signal 出现。

      其实state 的执行就是流程实例本身,我们可以通过:

     executionService.signalExecutionById(executionId);

      来执行。

 

      获得正确执行的方法是给state分配一个监听器,如:

 

      <state name="wait">

       <on event="start">

         <event-listenerclass="org.jbpm.examples.StartExternalWork" />

       </on>

        ...

       </state>

 

       在事件监听器StartExternalWord  中,我们可以执行额外需要完成的工作,通过

       execution.getId()获得确切的流程。

3任务服务TaskService

  //由流程引擎得到

TaskService taskService =processEngine.getTaskService();

 

   1) 任务列表的访问

 

   TaskService 主要是提供了对任务列表的访问及操作,如:

 

    //查找指定用户的任务列表

   List<Task> taskList = taskService.findPersonalTasks("marker");

 

    //查找指定组的任务列表

   List<Task> groupTaskList =taskService.findGroupTasks("hr-group");

 

    for (Task task : taskList) {

       //TODO

       taskService.completeTask(task.getId());

    }

 

   2) 读写相关数据

    一般情况下,我们在执行任务时都会对应一个表单,表单可以读写任务的相关数据。

 

    taskService.getVariable(taskId, variableName);

    taskService.getVariables(taskId, variableNames);

    taskService.getVariableNames(taskId);

    taskService.setVariables(taskId, variables);

 

   3) 完成任务

 

    我们可以通过以下几种方式完成任务:

 

   taskService.completeTask(taskId);

   taskService.completeTask(taskId, variables);

   taskService.completeTask(taskId, outcome);

   taskService.completeTask(taskId, outcome, variables);

    我们可以提供一个 map,在任务完成之前作为流程变量添加到流程实例中,也可以提供一个

 

   outcome (出口),以决定任务完成后的流向。但是我们需要注意任务的不同配置将会带来的问题:

 

      a) 如果一个任务拥有一个没有name 的transition:

 

         <task name="myTask">

           <transition to="end"/>

         </task>

 

         taskService.getOutcomes(taskId);//返回一个包含null值的集合

         taskService.completeTask(taskId);//使用这个transition

         taskService.completeTask(taskId, variables);//使用这个transition

 

                                                                    By Marker(majk@9.cn)

 

----------------------- Page10-----------------------

 

          taskService.completeTask(taskId, outcome);//抛出异常

          taskService.completeTask(taskId, outcome, variables);//抛出异常

 

      b) 如果一个任务拥有一个有name 的transition:

 

          <task name="myTask">

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

          </task>

 

          taskService.getOutcomes(taskId);//返回包含这个transition名称的集合

          taskService.completeTask(taskId);//使用这个transition

          taskService.completeTask(taskId, variables); //抛出异常(因为没有无名的transition)

          taskService.completeTask(taskId, outcome);//根据指定的名称执行转移 (如果没有该名称,

          则抛出异常)

 

          taskService.completeTask(taskId, outcome, variables);//抛出异常 (因为没有无名的

          transition)

 

      c) 如果一个任务拥有多个transition,而其中一个没有name,其他都有name:

 

          <task name="myTask">

           <transition to="next"/>

           <transition name="to other task"to="otherTask"/>

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

          </task>

 

          taskService.getOutcomes(taskId);//返回一个包含null值和其他transition名称的集合

          taskService.completeTask(taskId);//使用没有名称的transition

          taskService.completeTask(taskId, variables);//使用没有名称的transition

          taskService.completeTask(taskId, outcome);//使用指定名称的transition

           taskService.completeTask(taskId,outcome, variables);//使用指定名称的transition

 

      d) 如果一个任务拥有多个transition,并且都有唯一的name:

 

          <task name="myTask">

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

           <transition name="to other task"to="otherTask"/>

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

          </task>

 

          taskService.getOutcomes(taskId);//返回一个包含null值和其他transition名称的集合

          taskService.completeTask(taskId);//抛出异常(因为没有无名的transition)

          taskService.completeTask(taskId, variables); //抛出异常(因为没有无名的transition)

          taskService.completeTask(taskId, outcome);//使用指定名称的transition

          taskService.completeTask(taskId, outcome, variables);//使用指定名称的transition

 

4历史服务HistoryService

//由流程引擎得到

HistoryService historyService =processEngine.getHistoryService();

历史服务顾名思义就是对流程实例的运行时历史进行访问,如果想查询某流程定义的所有历史流 程实例,可以使用如下方法:

 historyService.createHistoryProcessInstanceQuery()

        .processDefinitionId(processDefinitionId)

        .orderAsc(HistoryProcessInstanceQuery.PROPERTY_STARTTIME)

        .list();

5管理服务ManagementService

   管理服务通常用来管理job,下文中我们用Timer进行测试,因为任务需要时间触发,因此在JUnit

测试中,达到时间要求是不可能的,因此我们可以显式获得Job 手动触发,例如:

 

   Job job = managementService.createJobQuery()

                  .processInstanceId(processInstance.getId())

                  .uniqueResult();

 

   managementService.executeJob(job.getId());

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值